There is no easy way to split contracts into deploys, currently this is the way I found:
- create interface of contract and interface of factory;
- move logic to a Factory;
- interface creation and return address of contract being created;
- add factory interface variable;
- add at constructor the assignment of that address;
- replace
myContract = new MyContract();
to the logic exemplified inneedNewExternalContract()
import "MyFactoryI.sol";
contract UsesFactory{
//(...)
MyFactoryI myFactoryI;
Database db;
function UsesFactory(address factory){
myFactoryI = MyFactoryI(factory);
db = new Database();
}
function needNewMyContract(int arg1, int arg2, int arg3, int arg4) internal returns (MyContractI) {
db.newTempAddress("newMyContract()"); //
iFactoryVar.delegatecall("newMyContract(int,int,int,int)",db,arg1,arg2,arg3,arg4);
address contractCreated = db.getTempAddress("newMyContract()"); //
MyContractI myContract = MyContractI(contractCreated);
return myContract;
}
//(...)
}
The example above is of the current implementation, how I've implemented in my App to make a class use a factory. If you want the real code used in a functional contract:
- The big contract being factoried.
- The factory.
- The interface being used in external contracts.
- Factory interface used in contract that uses Factory.
- And the delegated call is here.
This current method is a overload of code for a simple task in most of popular programming languages and is very likely to have bad implementations that are not detected by compiler, but will throw when called.
This is another implementation that uses libraries as helper to access particular contracts
Based on the already implemented transparent delegatecall in library functions:
- move contract code inside library scope;
- replace new instances to
MyLibrary.MyContract myContract = new MyLibrary.MyContract(arg1,arg2,arg3,arg4)
;
The current behavior would internally delegate call of a factory function built in library and would give the address of new contract:
function newMyContract(int arg1,int arg2,int arg3,int arg4) internal returns (address){
return new MyContract(arg1,arg2,arg3,arg4);
}
- Compiler will include those contracts to library code or deploys and calculate their nonces;
- Compiler will craft delegate calls to contracts using the library contract;
- Sources that uses that libraries, solc will check if function exists in the library contract interface.
- Contracts are placed normally after library scope.
- Create a factory function, such as:
function newMyContract(int arg1,int arg2,int arg3,int arg4) internal returns (address){
return new MyContract(arg1,arg2,arg3,arg4);
}
- On deploy, library deploys the contracts at its constructor
- solc precalculates the resulting nonces from the contracts and set them as addresses in constants
- delegatecalls goes to addresses in this constants
- other contract calls
myContract = Library.newMyContract(arg1,arg2,arg3,arg4);
- solidity don't include the contact code generated by library, instead uses delegatecall, that ends up in contract deployed by library.