1

I am trying to create a factory and I can not find a way to link libraries to the child contract. I am trying to create a contract factory that create child contracts. the problem is that the child contract use a library and I just don't know how to link the deployed library to the contract created in runtime.

I am using truffle: Truffle v5.4.13 (core: 5.4.13) Solidity - 0.8.7 (solc-js) Node v10.15.3 Web3.js v1.5.3 The error is

Error: Cannot create instance of MetaCoin; no code at address 0x0a9b3Cab26fC5bd045E572555f1cB073A50Ad8a0

This is the code:

SafeMath.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

/**
* @title SafeMath
* @dev Unsigned math operations with safety checks that revert on error
*/
library SafeMath {
    /**
    * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
    */
    function sub(uint256 a, uint256 b) public pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;
        return c;
    }

    /**
    * @dev Adds two unsigned integers, reverts on overflow.
    */
    function add(uint256 a, uint256 b) public pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);
        return c;
    }
}

MetaCoinFactory.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

import "@openzeppelin/contracts/proxy/Clones.sol";

import "./MetaCoin.sol";

contract MetaCoinFactory {

    event UsersContractCreated(address);    
    address immutable tokenImplementation;

    constructor(){
    tokenImplementation = address(new MetaCoin());
    }

    function createToken() public returns (address) {
    address clone = Clones.clone(tokenImplementation);
    MetaCoin(clone).initialize(msg.sender);
        emit UsersContractCreated(clone);
    return clone;
    }
}

MetaCoin.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

import {SafeMath} from "./SafeMath.sol";

contract MetaCoin {
    mapping (address => uint) public balances;
    bool private initialized;

    function initialize(address owner) public {
        require(!initialized, "Contract instance has already been initialized");
        balances[owner] = 100;
    }

    function sendCoin(address receiver, uint amount) public {
        balances[msg.sender] = SafeMath.sub(balances[msg.sender], amount);
        balances[receiver] = SafeMath.add(balances[receiver], amount);
    }

    function getBalance() public view returns (uint){
        return balances[msg.sender];
    }   
}

migration/2_deploy_contracts.js

const SafeMath = artifacts.require("SafeMath");
const MetaCoin = artifacts.require("MetaCoin");
const MetaCoinFactory = artifacts.require("MetaCoinFactory");

module.exports = async function(deployer) {
  await deployer.deploy(SafeMath);
  await deployer.link(SafeMath, [MetaCoinFactory, MetaCoin]);
  await deployer.deploy(MetaCoinFactory);
};

test/metacoinFactory.js

const { expect } = require('chai');

// Import utilities from Test Helpers
const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
const MetaCoinFactory = artifacts.require("MetaCoinFactory");
const MetaCoin = artifacts.require("MetaCoin");
const SafeMath = artifacts.require("SafeMath");

const mode = process.env.MODE;

contract("MetaCoinFactory", accounts => {

  it("should create contract and emit event", async () => {
    const metaCoinFactoryInstance = await MetaCoinFactory.deployed();
    const user = accounts[1];

    let result = await metaCoinFactoryInstance.createToken({ from: user });
    expectEvent(result, 'UsersContractCreated');
  });

  it("should get the address of the child contract", async () => {
    const metaCoinFactoryInstance = await MetaCoinFactory.deployed();
    const user = accounts[1];
    let address = await metaCoinFactoryInstance.createToken.call({ from: user });
    console.log(address);
    expect(address).contains("0x");
  });

  it("should get balance child the contract", async () => {
    const metaCoinFactoryInstance = await MetaCoinFactory.deployed();
    const user = accounts[1];
    let address = await metaCoinFactoryInstance.createToken.call({ from: user });
    const metaCoinInstance = await MetaCoin.at(address);
      // in here I get the error
    let balance = metaCoinInstance.getBalance({ from: user });
    expect(parseInt(balance)).to.be.equal(100);
  });
});

Error

Error: Cannot create instance of MetaCoin; no code at address 0x0a9b3Cab26fC5bd045E572555f1cB073A50Ad8a0

That was the allocated address of the child contract that was returned.

Thanks in advance

1 Answer 1

1

This is the correct way to link the library to the child contract. The problem I was having was related to the line

 let address = await metaCoinFactoryInstance.createToken.call({ from: user})

Since it is a transaction, I should use send(). The last truffle version doesn't have the send() function.. It should call the function instead that will return the transaction object. Sorry for the rookie error.

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.