Solidity – How to Get and Test Contract-Created Contracts in Hardhat Tests

hardhatsolidity

I've got a contract which creates another contract, stores it in a map, and returns the contract to the caller with a get function. What I am trying to do is retrieve the created contract stored in the map and test its values, but I'm not quite sure how to about that.

Here is the relevant code for the main contract and the test I'm trying to run on the child contract. The child contract (of type BindingTemplate) has a method called 'bindingName()' which is what I'm trying to call in my test

//parent
import "./BindingTemplate.sol";
import "./EnumsLibrary.sol";
contract BindingManager { 
    string[] private templateList; //array of template names 
    mapping(string => BindingTemplate) private templates; //id->template
  
   function makeTemplate(
        string memory bindingName,
    ) public   {      
        BindingTemplate myTemplate = new BindingTemplate(bindingName); 
        templates[bindingName] = myTemplate;
    }
  
    function getTemplate(string memory bindingName) public view returns(BindingTemplate) {
        string memory id = idMapping[bindingName];
        require(bytes(id)[0] != 0x0, "no such binding");
        return templates[id];
    }
 }
    

This my test code (javascript/chai/hardhat). In the before each which precedes this I create and deploy BindingManager and get the actuall contract using bManager.deployed(). The problem relates to getting the deployed contract created by BManager (which is a BindingTemplate contract).

it('sets values and returns a template', async function() {
    temp =  await bManager.makeTemplate("EditionLimit", "The limit is ${limit}", "Limit: ${limit}", 2 )
    btaddress = await bManager.getTemplate("EditionLimit");
    bTemplate = btaddress.deployed(); // <== fails with "TypeError btaddress.deployed is not a function
    result = await bTemplate.bindingName();   
    expect(result).to.not.be.undefined;
})

My question is, how do I get an instance of the new BindingTemplate contract to run tests on it?

Best Answer

On the JavaScript side you would let instance = await ContractName.at(<address>).

Your problem is you don't know the address. Your factory doesn't give up it's secrets easily because no even is emitted and you don't provide a function to make this information discoverable.

A best practice is to make all aspects of the contract state discoverable. Another best practice is to emit an event with all inputs and pertinent information like that when the state changes. If you did those things, you would have two options:

  1. Inspect the contract
  2. Inspect the event log

Have a look over here for a minimalist approach to making it discoverable. Deploy contract from contract in Solidity

Hope it helps.

Related Topic