It's not madness. On-chain deployment patterns are one way to establish trust between separate contracts. But, you are running into a classic problem.
When a contract A deploys another contract B, the bytecode for contract B gets rolled up into the bytecode for contract A. This is so contract A knows what to do.
Reducing the size of the deployed contract is one of the reasons one might want to split logic into separate modules, but the roll-up defeats the purpose. In a chain like you describe, the total bytecode of all the contracts will end up in contract A and it might be too expensive to deploy, i.e. > 25K bytes.
A solution to this problem is to use a factory pattern. Contract B deployed by BFactory, C by CFactory and so on. Deploy the factories separately and pass their addresses to the contract that will own the deployed contracts. Use an interface
to describe the deployment functions so the whole bytecode doesn't wind up the contract that needs the factory output.
Here's a sketchy idea to get you thinking about how it might work in your case.
interface IFactoryB {
function deployB() external;
}
interface IB {
function doSomething() external;
}
// Inheritance helps catch developer errors at compile time
// You want to catch any difference between implementation and interface description
contract B is IB {
function doSomething() public {
// ... heavy code
}
}
contract BFactory is IFactoryB {
function deployB() public returns(IB) {
B b = new B(); // this is what tells the compiler to compile and include B
b.transferOwnership(msg.sender); // same result as if A deploys an Ownable contract
return IB(address(b));
}
contract A { // does not need B's bytecode, only IB which is much smaller
constructor(address factoryB) {
IB b = IFactoryB(factoryB).deployB(); // this tells the compiler to include IB and IFactoryB
// can now interact with b's functions
// there is no reason at all to include B's bytecode in A because
// calls to B are always external to A
}
}
In summary, use interfaces to control bytecode size and use your judgment to organize the code into separate concerns.
Hope it helps