question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Linking libraries from generated type has inconsistent behavior

See original GitHub issue

Ethers Beta Version

v6-beta

Describe the Problem

It is not clear when linking libraries (linkLibraryAddresses) is required or how this functionality works. I have two extremely similar contracts, and the generated types are quite different. One is the normal type that I am used to ContractA, but the other ContractB has additional functionality around linking libraries and a required argument in the constructor.

Ideally, I would like ContractB to not require linking libraries at all. At the very least, though, I would like to know why this is a requirement for one of the contracts but not the other. Some documentation around library linking would also be good, as the only other relevant piece of information after an extensive search was just when this feature got added: https://github.com/ethers-io/ethers.js/issues/195

Code Snippet

Normal contract factory type ContractA__factory.ts that uses libraries has a familiar constructor that just requires a signer address:

type ContractAConstructorParams =
  | [signer?: Signer]
  | ConstructorParameters<typeof ContractFactory>;

const isSuperArgs = (
  xs: ContractAConstructorParams
): xs is ConstructorParameters<typeof ContractFactory> => xs.length > 1;

export class ContractA__factory extends ContractFactory {
  constructor(...args: ContractAConstructorParams) {
    if (isSuperArgs(args)) {
      super(...args);
    } else {
      super(_abi, _bytecode, args[0]);
    }
    this.contractName = "ContractA";
  }

Abnormal contract factory type ContractB__factory.ts that uses libraries has a constructor that requires linkLibraryAddresses parameter and additional functionality such as linkBytecode():

type ContractBConstructorParams =
  | [linkLibraryAddresses: ContractBLibraryAddresses, signer?: Signer]
  | ConstructorParameters<typeof ContractFactory>;

const isSuperArgs = (
  xs: ContractBConstructorParams
): xs is ConstructorParameters<typeof ContractFactory> => {
  return (
    typeof xs[0] === "string" ||
    (Array.isArray as (arg: any) => arg is readonly any[])(xs[0]) ||
    "_isInterface" in xs[0]
  );
};

export class ContractB__factory extends ContractFactory {
  constructor(...args: ContractBConstructorParams) {
    if (isSuperArgs(args)) {
      super(...args);
    } else {
      const [linkLibraryAddresses, signer] = args;
      super(
        _abi,
        ContractB__factory.linkBytecode(linkLibraryAddresses),
        signer
      );
    }
    this.contractName = "ContractB";
  }

  static linkBytecode(
    linkLibraryAddresses: ContractBLibraryAddresses
  ): string {
    let linkedBytecode = _bytecode;

    linkedBytecode = linkedBytecode.replace(
      new RegExp("__\\$0d23297b21f644609e8328ff630c929483\\$__", "g"),
      linkLibraryAddresses[
        "contracts/libraries/MyLib.sol:MyLib"
      ]
        .replace(/^0x/, "")
        .toLowerCase()
    );

    return linkedBytecode;
  }

  export interface ContractBLibraryAddresses {
    ["contracts/libraries/MyLib.sol:MyLib"]: string;
  }

Errors

If I try to manually turn ContractB’s type into a type resembling ContractA (removing the link library requirement), I get errors about bytecode mismatch. Likely not important for this issue but can post if useful.

Environment

node.js, Hardhat

Environment (Other)

typechain

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
zemsecommented, May 7, 2022

Ideally, I would like ContractB to not require linking libraries at all. At the very least, though, I would like to know why this is a requirement for one of the contracts but not the other.

If the compiled contract’s artifact mentions that it needs a library to be linked, then typechain would generate ethers types that require you to supply the library address. You can checkout solidity docs here.

TLDR; If your contract imports any library and uses any of it’s external methods in it’s code, then that library is needed to deployed separately and it’s address to be included in the bytecode.

0reactions
0xKudocommented, May 7, 2022

Ideally, I would like ContractB to not require linking libraries at all. At the very least, though, I would like to know why this is a requirement for one of the contracts but not the other.

If the compiled contract’s artifact mentions that it needs a library to be linked, then typechain would generate ethers types that require you to supply the library address. You can checkout solidity docs here.

TLDR; If your contract imports any library and uses any of it’s external methods in it’s code, then that library is needed to deployed separately and it’s address to be included in the bytecode.

Thank you so much, turns out I didn’t have an external function in the library, but I did have a public!

SOLUTION: Move all external/public functions to internal/private.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Linking libraries with incompatible dependecies - c++
If you have "too many" dependencies on both libraries, your other solution may be to build an "interposer" library.
Read more >
[assembly:LinkerSafe] inconsistency. Didn't find class "android ...
So I have few questions here: Is it intended to have this linker-inconsistent behavior for same nuget package but different targets frameworks?
Read more >
536856 – libtool command line options inconsistent to ...
Description of problem: Creating a shared and static library with "libX_la_LDFLAGS = -shared -static" in Makefile.am is not working. Only a static lib...
Read more >
Dynamic linking best practices - begriffs.com
In this article we'll learn how to build shared libraries and install them properly on several platforms. For guidance, we'll examine the ...
Read more >
Symbol Processing - Linker and Libraries Guide
Inconsistencies between symbol types are not suppressed by the link-editor's -t option.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found