9

I'm attempting to deploy a contract using Hardhat (via scaffold-eth), but am getting the following error:

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

The contract in question (Factory.sol) imports three contracts, and one of them is called library (Library_Token.sol). I receive this error even if I deploy it first, though.

What is causing this error, and how can it be fixed?

Update: I see Truffle has a function for linking libraries: https://www.trufflesuite.com/docs/truffle/getting-started/running-migrations#deployer-link-library-destinations-

I assume that Hardhat should have something similar, and that's what needs to happen here. As such, I'm guessing the question should be rephrased as 'how do I link a library to a contract using Hardhat', but I guess I won't know until that's figured out and we see if it works.

0

1 Answer 1

7

First things first, let's dive into the issue a bit more.

A linked library isn't just another contract deployed in the same ecosystem, it needs to be actively linked to the contract that uses it, as the link above (to the Truffle code for doing so) demonstrates.

Updated Answer

I'll keep the original answer for posterity (not sure why, just kind of feels like the right thing to do), Hardhat (formerly known as Buidler) at this point has an implementation for linking libraries on deploy (code snippet taken from their docs here). Note: This uses the ethers Hardhat plugin (see link above):

const contractFactory = await this.env.ethers.getContractFactory("Example", {
  libraries: {
    ExampleLib: "0x...",
  },
});

Old Answer

Buidler does not currently (mid-July 2020) have a native shortcut for doing this. An issue has been opened on GitHub, which also has the following workaround in it, also copied and pasted below.

The workaround is preceded by the devs saying that there should be a more direct and simple way to link contracts soon, so it may be worth verifying if they've implemented something for this before using the code below.

const { ethers, config } = require("@nomiclabs/buidler");
const { readArtifact } = require("@nomiclabs/buidler/plugins");

async function main() {
  const Library = await ethers.getContractFactory("Library");
  const library = await Library.deploy();
  await library.deployed();

  const cArtifact = await readArtifact(config.paths.artifacts, "Contract");
  const linkedBytecode = linkBytecode(cArtifact, { Library: library.address });
  const Contract = await ethers.getContractFactory(
    cArtifact.abi,
    linkedBytecode
  );

  const contract = await Contract.deploy();
  await contract.deployed();

  console.log("Contract address:", contract.address);
}

function linkBytecode(artifact, libraries) {
  let bytecode = artifact.bytecode;

  for (const [fileName, fileReferences] of Object.entries(
    artifact.linkReferences
  )) {
    for (const [libName, fixups] of Object.entries(fileReferences)) {
      const addr = libraries[libName];
      if (addr === undefined) {
        continue;
      }

      for (const fixup of fixups) {
        bytecode =
          bytecode.substr(0, 2 + fixup.start * 2) +
          addr.substr(2) +
          bytecode.substr(2 + (fixup.start + fixup.length) * 2);
      }
    }
  }

  return bytecode;
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

If my understanding of the code is correct, you would most likely use this inside /scripts/deploy.js, which should contain the script for deploying the contracts in your project.

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.