6

The smart contract app I am writing follows what I consider good practice - it is decoupled so that a controller contract calls a logic contract which calls a storage contract. So Contract A calls Contract B calls Contract C.

However, I'm wondering if, because of security, such decoupling is a good idea for smart contracts. That's because I need the onlyOwner modifier to tie down who calls my functions (as describe here: https://github.com/ethereum/wiki/wiki/Solidity-Features). To my mind, it would be great if I could do something like this:

import "Owned.sol";

contract A is Owned {

   B private b;

   function A(address B) {
       b = B(b);
   }

   function myInterface() public onlyOwner {
       a.doStuff({from: msg.sender});
   }
}

contract B is Owned {

   C private c;

   function B(address c) {
       c = C(c);
   }

   function doStuff() public onlyOwner {
       c.store(42,{from: msg.sender});
   }
}

contract C is Owned {

   int private theAnswer;

   function store(int value) public onlyOwner {
       theAnswer = value
   }
}

However, I believe I can't send msg.sender that way. Hence, would I be better bundling Contract A, Contract B and Contract C into a single monolithic contract where msg.sender is valid?

  • 1
    Why don't you just make A the owner of B, and B the owner of C? – Tjaden Hess Oct 25 '16 at 19:32
  • @TjadenHess. I was about to write: "yeah, but how?" But actually, I can pass the address of A to B and B to C in the constructor and assign the owner that way. Doh! Er, yeah - you're right. Sometimes these things just need airing to be solved ;) Thanks! – glowkeeper Oct 25 '16 at 19:48
  • 1
    Actually, what I would do is create B in the constructor of A instead of passing in the address, then use msg.sender within the constructor of B to set the owner. Then do the same, creating C from within the constructor of B – Tjaden Hess Oct 25 '16 at 19:50
  • 1
    @TjadenHess - nice - is that because then B properly owns its instance of C (for example), rather than owning an already deployed C (which might have its ownership changed meanwhile)? – glowkeeper Oct 25 '16 at 19:58
  • 1
    Exactly. In some cases that may not be what you want, but it's generally easier to reason about the contract when it's not interacting with some arbitrary contract – Tjaden Hess Oct 25 '16 at 19:59
3

In the comments to your original post, you have estabilished that deployment of a large monolithic contract may fail due to the block gas limit being reached. A dapp that can't be deployed can't be better. :)


As to solutions: maybe extend Owned to Authable with:

  • mapping (address => bool) public authorised
  • modifier onlyAuthed {...}
  • function authAdd (address _addr) public onlyOwner {...}
  • function authRem (address _addr) public onlyOwner {...}

... and then use Authed+onlyAuthed instead of Owned+onlyOwner in derived dapps?..

You could then deploy the pieces independently. Once there is a "full chain" that can be linked (such as A->B->C[several], you can call C.authAdd(<address-of-B>) from your owner account.

This is a bit tedious, but relatively easy to automate. In addition to that, you don't have to worry about the order of deployment, or whether some dapps fail to deploy.

The scheme can be modified to suit particular needs.


As an alternative, you could use Zeppelin's Ownable and its transfer() function.

This would work fine if:

  • the "ownership chain" is linear, i.e. no case where a dapp could be called by several others; and
  • retaining original ownership (by the deploying account) is not needed (e.g. for nuking purposes).

EDIT:

Then again, you could move b = B(b) out of the constructor to a separate function (like function createChildren(...) public onlyOwner onlyOnce {...}), and add some way to propagate the request to already-created children (like function nagForGrandChildren(...) public onlyOwner {...}). But the issue remains: if nFGC() hits the block gas limit, the function call will have to be repeated - triggered from the original external owner account of A.

One way or another, you'll need to foresee that some part of your chain will fail to deploy. The choice here is between "something down the line" or "anything in between".

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.