1

I have two contracts that both inherit from OpenZeppelin's Whitelist. After deploying both contracts, I use an instance of the first contract to add a "trusted" address to the whitelist. Since both contracts inherit from the same Whitelist, I would assume that the second contract also sees that "trusted" is whitelisted. However, I don't see that when running tests. My questions are below the code.

contracts A and B:

pragma solidity ^0.4.23;
import "openzeppelin-solidity/contracts/ownership/Whitelist.sol";

contract A is Whitelist {   
}

contract B is Whitelist {   
}

migration 2_deploy.js:

var A = artifacts.require("./A.sol");
var B = artifacts.require("./B.sol");

module.exports = function(deployer, network, accounts) {
    var owner = accounts[0];
    var trusted = accounts[1];

    deployer.deploy(A, {from: owner})
    .then(function(){
        console.log("A deployed");  
        return; 
    });

    deployer.deploy(B, {from: owner})
    .then(function(){
        console.log("B deployed");      
        return;
    });

    A.deployed()
    .then(function(instance) {
        instance.addAddressToWhitelist(trusted, {from: owner})
        .then(function() {
            return;
        });
    });
};

test.js:

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

contract('A', async (accounts) => {
    let owner = accounts[0];
    let trusted = accounts[1];

    a = await A.deployed();
    b = await B.deployed();

    let isWhitelistedA = await a.whitelist(trusted); 
    let isWhitelistedB = await b.whitelist(trusted); 
    console.log("before adding trusted, contract A: "+isWhitelistedA); 
    console.log("before adding trusted, contract B: "+isWhitelistedB); 

    await a.addAddressToWhitelist(trusted, {from: owner});
    isWhitelistedA = await a.whitelist(trusted); 
    isWhitelistedB = await b.whitelist(trusted); 
    console.log("after adding trusted to A, contract A: "+isWhitelistedA);
    console.log("after adding trusted to A, contract B: "+isWhitelistedB);

    await b.addAddressToWhitelist(trusted, {from: owner});
    isWhitelistedA = await a.whitelist(trusted); 
    isWhitelistedB = await b.whitelist(trusted); 
    console.log("after adding trusted to B, contract A: "+isWhitelistedA);
    console.log("after adding trusted to B, contract B: "+isWhitelistedB);  
})

truffle test output:

before adding trusted, contract A: false
before adding trusted, contract B: false
after adding trusted to A, contract A: true
after adding trusted to A, contract B: false
after adding trusted to B, contract A: true
after adding trusted to B, contract B: true

Questions:

  1. Why trusted is not whitelisted before being added in the Test? Migration should have added it.
  2. When trusted is whitelisted via A's instance, why is it not whitelisted according to B? Inheritance should have taken care of that.

Notes:

  • This might be me not understanding how "deployed" and instances work, so please enlighten me what is happening :).
  • test.js is obviously not a proper Truffle Test (as nothing is really tested), but it is a reduced example of a problem I am facing.

Other info:

  • Truffle v4.1.8 (core: 4.1.8)
  • Solidity v0.4.23 (solc-js)
  • using Ganache with localhost
2

Short Answer: Both contracts are creating new instances of Whitelist. They are not sharing the same instance.

To share the same instance - they both need to reference the same address of a single deployed Whitelist.

By deploying both contracts you are, in fact, wasting (however small or large) gas as both contracts have redundant code.

My suggestion (which may or may not fit your use case) is:

  • only have the contract A inherit Whitelist.
  • create a new interface contract that lists the functions of Whitelist that contract B needs to utilize. Contract B will have a variable type of this interface contract.
  • set the address of contract A to the variable of contract B so B now has a reference to the Whitelist

They may be a better architectural design to your problem - But this will get your sandbox example working.

Code snippets:

WhitelistInterface.sol

Contract B:

import "./WhitelistInterface.sol";

WhitelistInterface whitelistInstance;

B's constructor:

require(_whitelistAddress != address(0));
whitelistInstance = WhitelistInterface(_whitelistAddress);

B's function call for whitelisting

bool isWhitelisted = whitelistInstance.whitelist(addressToTest);
  • Note: contract B will only have read access as it is not an owner of the whitelist. So you will be forced to use contract A for onlyOwner functions unless you modify the code. – MSwezey May 16 '18 at 19:25
  • 1
    Right... I now understand better the following sentence from Solidity Docs: When a contract inherits from multiple contracts, only a single contract is created on the blockchain, and the code from all the base contracts is copied into the created contract. That would mean that the code of Whitelist is indeed duplicated in both A and B, each having their own state. – Mike May 17 '18 at 11:17

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.