3

I'm trying to make a simple test in Truffle using Ganache where I call a function from a smart contract instance. This component will create a Vault and return me its address.

My truffle test does the following:

const VaultFactory = artifacts.require("./VaultFactory");
const Vault = artifacts.require("./Vault");

contract('VaultFactory', async () => {
    it("Should create a new Vault", async () => {
        let VaultFactoryInstance = await VaultFactory.deploy();
        let VaultAddress = await VaultFactoryInstance.CreateVaultContract.call();
        let VaultInstance = await Vault.at(VaultAddress);
    });
});

The VaultFactory.sol code that creates the Vault does the following (the Vault's constructor is empty):

function CreateVaultContract ()
    public
    returns(address)
{
    Vault newVault = new Vault();
    emit VaultCreation(msg.sender, newVault, VaultState.Created);
    return address(newVault);
}

The VaultAdress that I get is not empty, however, when I try to get the VaultInstance, it gives me the following error:

Uncaught Error: Cannot create instance of Vault; no code at address 0xed41bb9a56dad9b9d0901400f0a8de72d3cf1854

I tried doing a web3.eth.getCode(VaultAddress); to see if I had any code, but it returns me 0x0.

So, my VaultFactory contract seems to be deployed and looks like it created a Vault. But for some reason, I can't manage to get its instance. Any idea why?

2
  • 1
    Try to replace await VaultFactory.deploy() with await VaultFactory.new(). Commented Jun 15, 2018 at 15:33
  • 1
    Also, the CreateVaultContract function is not constant (i.e., it changes the state), so you cannot call it and get the return-value directly (you need to send it as a transaction, and get the return-value from the event that this function emits). Commented Jun 15, 2018 at 15:35

3 Answers 3

3

let VaultAddress = await VaultFactoryInstance.CreateVaultContract.call();

should be:

let VaultAddress = await VaultFactoryInstance.CreateVaultContract();

3

I finally managed to get a working solution (even though I'm not sure it's the best one).

const VaultFactory = artifacts.require("./VaultFactory");
const Vault = artifacts.require("./Vault");

contract('VaultFactory', async () => {
    it("Should create a new Vault", async () => {
        let VaultFactoryInstance = await VaultFactory.deploy();
        let VaultReceipt = await VaultFactoryInstance.CreateVaultContract();

        //This returns the address of the newly created Vault
        let VaultAddress = VaultReceipt.logs[0].address;

        let VaultInstance = await Vault.at(VaultAddress);
    });
});

This way, I can get my Vault address and can get the instance of it. I then tried to call a function and it works perfectly!

1

I had two problems

Using .call() does not persist data

Factory factory = await Factory.deployed()
factory.createChild.call()

This doesn't work, because call will return the code that would run on-chain, but it won't actually save anything on-chain. It's like you never called the function at all.

Dynamic arrays don't need initialization

constructor() {
   children = new Child[](1)
}

Don't do this. If you do, it will init 1 element as null.
If you then call factory.children.call(0) that element will be 0x00000...
Obviously, there won't be any code at null.

Working

Solidity

contract Factory {
  event CreatedChild(address child);
  Child[] public children;

  function createChild() {
    Child child = new Child();
    children.push(child);
    emit CreatedChild(address(child);
  }
}

contract Child {}

Truffle

 it("should deploy child", async () => {
  const factory = await Factory.deployed();
  const tx = await factory.createChild();

  const childAddress = tx.logs[0].address;
  const firstChild = await factory.children.call(0);

  // console.log("tx return", childAddress);
  // console.log("array call", firstChild);

  assert.ok(childAddress !== 0);
  assert.equal(childAddress, firstChild);
});

Your Answer

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

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