Be very helpful to know if the scenario below is possible
contract A { import "./B.sol";
... address c = new B(); b = B (c)
}
//somewhere in JS instance_of_B = web3.eth.contract(B.abi).at(c);
Yes its possible.
Web3.js doesnt care how the contract was deployed. It just needs: - the contract ABI - the contract address - and a provider to transport requests to the Ethereum Blockchain
Now, you need to return the address of the new contract created to the outside world, so that web3 can see it. You cant return data from a transaction , however you can use emit an event with the address of the contract and have web3 monitor this event
You have approximately answered your own question. Let's walk through the details and sort out the concerns and syntax.
The requirements for reading a contract are
Contract design can assist with the second requirement.
You wouldn't do:
contract A { import "./B.sol"; ...
But, you might do
import "./B.sol";
contract A { ...
And, you could have a function to deploy a new B
:
function createB() public returns(address contractB) {
B b = new B(); // cast b as B, defined by "contract B" in the imported file
return address(b);
}
Since that is a state-changing function, software clients will only get a transactionHash and not address(b)
- that response is only available to other contracts. It can be very useful and is generally recommended to also emit an event for an important state-change such as this. Events are observable by a Web3 watcher.
import "./B.sol";
contract A {
event LogNewB(address creator, address contractB);
function createB() public returns(address contractB) {
B b = new B();
emit LogNewB(msg.sender, b);
return address(b);
}
What if the observer isn't watching? It can be useful to make this discoverable by inspecting the contract. A can keep track of the B instances it deploys:
address[] public bList;
...
bList.push(b);
Altogether ...
import "./B.sol";
contract A {
address[] public bList;
event LogNewB(address creator, address contractB);
function createB() public returns(address contractB) {
B b = new B();
emit LogNewB(msg.sender, b);
bList.push(address(b));
return address(b);
}
Since bList
is public
, you get a "free" getter that will return the address at a row, roughly equivalent to:
function bList(uint row) public view returns(address) {
return bList[row];
}
Now there are three ways for a Web3 client to construct a list of all the B contracts that were deployed by A. They can listen to event logs, resolve mined transaction hashes and inspect the log arguments, or inspect the bList
. Together with knowledge of ABI for B, the client can:
var instanceB = web3.eth.contract(abi).at(address);
As Julien pointed out, Web3 is indifferent about the method that was used to deploy the contract.
Hope it helps.
p.s. It may be helpful to add a quick function to reveal the length of the bList
, otherwise software clients will not know where the end of the array is. Something like:
function getBCount() public view returns(uint) { return bList.length; }