Struct vs. Standalone Contract for handling Configuration

Hi! I’ve been faced a few time with a design decision which I really not sure what’s the best way to go and wanted to check with the experience OZ Community.

In some DeFi contracts Im writing I require to store a large number of configuration parameters which will impact on how the procotol itself works. I found it clean to have a separate Configuration contract with all these variables and then reference it from the main contract. Something like this:

contract MyContract {
        Configuration public conf;
}

contract Configuration {
    uint256 public myParam1;
    uint256 public myParam2;

}

But clearly there are other options, the simplest one is to have an internal Struct in the contract with all the parameters and handle it all there directly. Something like this:

contract MyContract {
   
   struct Configuration {   
      uint256 myParam1;
      uint256 myParam2;
  }

  Configuration public conf;
}

1) What do you think its a better approach?
2) Which are some pros/cons that you would use to make a decision around this design?

Please if there are better design patterns or alternatives to this problem let me know as well!

Thanks!

Regards
Julian

Without more information I would say the struct should be preferred, as it’s the simpler approach.

However, you should also consider the access pattern. If these parameters are gonig to be read by multiple contracts, the public struct will generate a getter that will return all of the parameters at once, and if only a few of them are needed this may be inefficient. So it may be better to define the many variables inline, or define multiple structs grouping together parameters that are accessed together.

I think it’s also relevant for choosing between the two options to consider how these parameters are meant to be modified and if you would want to place the access control logic in MyContract itself, or if it makes sense to have a separate Configuration contract with all of the access control and parameter changing logic.

Thanks for the clarification! Makes a lot of sense. In this case it is actually shared by different contracts the config, and also makes sense to have its own access control.

Would the separate contract be much more expensive in terms of transactional cost? Of course deployment will be more expensive but im more concerned about day to day reads/calls to the configuration.

One downside I see of the separate contract is that if I want MyContract to expose certain parameters of the current Configuration, I would still need to create getters that would do something like return this.conf().myParam1() so I will still end up having a lot of code just to expose the internal attributes.

I think it will cost an additional 2500 gas to access the separate Configuration contract (for the first time in each transaction).

You should consult https://github.com/wolflo/evm-opcodes!