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