1

I am learning Solidity and writing a contract that uses a library. I'm using truffle for the project. When I try to test the contract I get the following error

Error: User contains unresolved libraries. You must deploy and link the following libraries before you can deploy a new version of User: IterableMapping

The code for the library is taken from iterable_mapping.sol and stored in IterableMapping.sol

The code of the contract looks like following and stored in User.sol

pragma solidity ^0.4.18;

import "./IterableMapping.sol";

contract User
{
    event ItemInserted(bool replaced);
    event ItemRemoved(bool success);

    // Just a struct holding our data.
    IterableMapping.itmap data;
    // Insert something
    function insert(uint k, uint v) public returns (uint size)
    {
        // Actually calls itmap_impl.insert, auto-supplying the first parameter for us.
        bool replaced = IterableMapping.insert(data, k, v);

        ItemInserted(replaced);

        // We can still access members of the struct - but we should take care not to mess with them.
        return data.size;
    }

    function remove(uint k) public returns (bool success)
    {
        success = IterableMapping.remove(data, k);

        ItemRemoved(success);
    }

    // Computes the sum of all stored data.
    function sum() public view returns (uint s)
    {
        for (var i = IterableMapping.iterate_start(data); IterableMapping.iterate_valid(data, i); i = IterableMapping.iterate_next(data, i))
        {
            var (, value) = IterableMapping.iterate_get(data, i);
            s += value;
        }
    }
}

The test code is

const User = artifacts.require('User');

contract('User', (accounts) => {

    it('should insert an item', () => {
        return User.new({
            from: accounts[0]
        }).then(instance => {
            return instance.insert.call(1, 1234, {from: accounts[0]});
        }).then(result => {
            assert.equal(result, 1);
        });
    });
});

I am aware in general the library code should be deployed before the contract using it and the linker at compilation is told to replace the __IterableMapping________ with the address of the deployed library. But in case of testing its not deploying the contract and I'm not sure when i do the User.new if and how can I pass which address to use for library.

  • If you are using truffle v4(below)=>, Go to Migrations folder and modify 2_deploy_contracts and link your library i.e add the line deployer.link (IterableMapping,User) ; Make sure you have the artifacts also. – Rangesh Nov 26 '17 at 12:38
  • I'm currently using the Truffle v4.0.1 and when I created the project it only has the 1_initial_migrations.js – Zabi Nov 26 '17 at 12:42
  • I've change the 1_initial_migrations.js to contain the following deployer.deploy(IterableMapping).then(() => { deployer.deploy(User).then(() => { deployer.link(IterableMapping, User); }); }); – Zabi Nov 26 '17 at 12:43
  • I am not sure about the latest version,but i guess it should be same, you should still have the same like above,go ahead and make changes. – Rangesh Nov 26 '17 at 12:44
  • Let me add that file and make the change you suggested – Zabi Nov 26 '17 at 12:46
4

The problem got solved by adding the 2_deploy_contracts.js and adding the following in it

const IterableMapping = artifacts.require('IterableMapping.sol');
const User = artifacts.require('User.sol');

module.exports = function (deployer) {
    deployer.deploy(IterableMapping).then(() => {
        deployer.deploy(User);
    });
    deployer.link(IterableMapping, User);
};
1

I used Zabi's answer above (thank you Zabi without it I would not have solved my problem) but I still needed to add a return statement and some minor modifications in order to fully implement his solution in JavaScript, though it still worked as is within the Truffle console. My modification of Zabi's solution is as follows:

    var IterableMapping = artifacts.require("./IterableMapping.sol");
    var User = artifacts.require("./User.sol");

    module.exports = function (deployer) {
    deployer.deploy(IterableMapping).then(() => {
        deployer.link(IterableMapping, User);
        return deployer.deploy(User);
    });
};
  • In case this is an answer please explain what have you changed and how this implementation is better then one which is provided by Zabi. – Roman Frolov Jan 31 '18 at 13:18
  • I have added a return statement and moved the linking because otherwise the program hangs forever waiting for the function to return something – Zander Labuschagne Feb 25 '18 at 0:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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