0

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?

2 Answers 2

2

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.

3
  • Actually I the getTemplate() function which returns(BindingTemplate) returns the address of the created contract to my test. The part I couldn't figure out was how to get the contract at that address. Finally I came across the ContractName.attach(address) function which appears to do the trick. Is it the same as the .at(address) function you mentioned above?
    – GGizmos
    Sep 11, 2021 at 17:01
  • Sounds right. I couldn't "see" what your getTemplate would return. The precise syntax depends on whether one is using ethers, web3js, etc. Sep 11, 2021 at 20:21
  • Thanks. sent you a note on linked in btw.
    – GGizmos
    Sep 11, 2021 at 20:31
0

Just to add a little more complete code.

describe("Tests", function () {

  beforeEach(async function () {
    const factory = await ethers.getContractFactory("Factory");
    const factoryContract = await factory.deploy();
  });

  it("Interacts with child contract", async function() {
    await factoryContract.createChild();
    const childContractAddress = await factoryContract.getChildContractAddress(); // this should be saved in a variable in the factory contract
    const child = await ethers.getContractFactory("Child");
    const childContract = await child.attach(childContractAddress);
    
    // you can now call functions on the child contract
    const someChildData = await childContract.getData();
    assert.equal(someChildData, expectedValue);     
  });
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.