As far as I know, brownie automatically links the library to contract. Is there a way to do this manually?

I have bunch of contracts in different projects where some use library and some don't. So I wan't to link manually to those needs library in the contract.

2 Answers 2


According to the Brownie docs, if a contract requires a library, Brownie will automatically link to the most recently deployed one. In other words, Brownie will not automatically link to the most recently deployed one if a contract doesn't require a library.

See: https://eth-brownie.readthedocs.io/en/stable/core-contracts.html

  • I already know this.
    – Emrah
    Commented Sep 29, 2022 at 16:55

This is my approach. I'm open to others if there is a way to simplify it.

from pathlib import Path
from solcx import compile_files, link_code
from brownie import web3, accounts, Contract

library_addresses = {"Lib1": <Lib1 address>, "Lib2", <Lib2 address>}
remappings = [
   '@openzeppelin=Openzeppelin/[email protected]',

contract_file = Path("contracts/MyContract.sol")
contract_compiled_sol = compile_files(
    output_values=["abi", "bin"],
    solc_version=<solc version (e.g. "0.8.14")>,

abi = contract_compiled_sol["contracts/MyContract.sol:MyContract"]["abi"]
bin = contract_compiled_sol["contracts/MyContract.sol:MyContract"]["bin"]
nonce = web3.eth.getTransactionCount(accounts[0].address)

# Here is the MAGIC!!!
bin = link_code(
        f"contracts/libraries/{lib}.sol:{lib}": library_addresses[lib]
        for lib in library_addresses.keys()

MyContract = web3.eth.contract(abi=abi, bytecode=bin) 

tx_data = {
    "from": accounts[0].address,
    "nonce": nonce,
    "gasPrice": int(web3.eth.gas_price * 1.2), # or whatever you want...
    "gas": 3000000, # or whatever makes sense for your contract...

tx = MyContract.constructor(

print(web3.eth.estimateGas(tx)) # Can rebuild transaction with gas estimate

signed_tx = web3.eth.account.signTransaction(

tx_hash = web3.eth.sendRawTransaction(signed_tx.rawTransaction)

receipt = web3.eth.waitForTransactionReceipt(tx_hash, timeout=360)

print(f"\tTransaction: {tx_hash.hex()}")

    f"\tMyContract successfully deployed to {receipt.contractAddress}"

# Now you can interact with your new contract :)
myContract = Contract.from_abi(

Please let me know if there was anything I missed. Also please note, I added in the Openzeppelin remapping because it's a common library remapping added to configurations. So more of an additional help for anyone.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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