Deploying with Libraries on Remix-IDE
Libraries are very similar to contracts but they do not store state. Using one is a gas saving strategy that comes in handy when you have a contract that will be deployed many times — but some of the code only needs to be deployed once. By splitting those functions off from a contract into a library, you are deploying less code in the contract— so the gas costs are less.
Once a library is deployed, anyone can use it as long as they have the library’s source code. So, if you can use some functions from someone else’s audited library (like a safemath library)— you’ll be writing safer contracts and writing them more efficiently.
How to connect the contract to the library?
With Remix IDE and all the other dev tools, the library’s address does not go in the contract’s source code. The address is injected (or linked) in the contract’s byte-code at deployment.
Specifically with Remix, there is a metadata.json file which is generated when the contract is compiled. This metadata file contains (among other things) a placeholder where the user will put the libraries addresses.
Let’s go into this more…
An example of deploying with a library
Here is a solidity file that contains a contract and a library. The contract sampleContract contains a function that calls a function in the library aLib:
In this example, the library and the contract get compiled at the same time. If they would have been in separate files — the library would need to be imported (using the import keyword) into the file with the solidity contract.
Here is the link to the Solidity docs about Libraries: https://solidity.readthedocs.io/en/latest/contracts.html?highlight=library#libraries
The Deployment Issue
The library and the calling contract get deployed separately and so they will have separate addresses.
In order to use a library, the calling contract must have the library’s address.
But as stated above, the library’s address is not directly specified in the solidity code. The calling contract’s compiled bytecode contains a placeholder where library’s addresses will go.
At deployment of the calling contract, Remix looks in the contract’s metadata for the library’s address and updates the placeholder with the address.
So before deploying a contract that calls a library, you need to generate the contract’s metadata (AKA its build artifact) and then you need to input the library’s address into the metadata file.
A contract’s metadata is generated at compile time.
Generating Metadata
By default, Remix doesn’t generate a file with the contract’s metadata. To generate this file, we need to go to the settings module.
Go there by clicking on the settings icon in the icon panel.
- Check the first option Generate contract metadata.
- Go to the Solidity Compiler and compile the file
- Go to the files explorer to see the artifacts folder and open it up
Open up the sampleContract.json file. The deploy object in that file should look like this:
After we get the address of the library, we’ll replace the <address> tag of the network we are deploying to with the actual address of the library.
But as you can see, the default behavior of Remix is to automatically deploy the library and link it automatically in the calling contract.
autoDeployLib: true
The default behavior works well for testing out some code. But when the library has already been deployed, you’ll need to make these edits. And that is the situation we are simulating in this article.
But note, when using a library that has already been deployed, you still need to import it in the contract’s source code before you compile it.
Deploy the library & grab its address
In the deploy and run module, deploy the library by selecting in the contract select box. Then, retrieve its address, by clicking on the copy icon at the right of deployed instance.
Edit the calling contract’s metadata file
Go to the calling contract’s metadata file and replace the <address> tag with the library’s address in whatever network you are deploying to.
In this example case, we are deploying to the Javascript VM - in the metadata file above — it is called VM.
We also need to update the autoDeployLib setting so that Remix doesn’t automatically deploy the library when it deploys the contract. So set autoDeployLib to false.
Deploy the library calling contract
Switch to the Deploy & Run transaction module.
Select the JavaScript VM Environment and select the sampleContract in the list of compiled contracts.
Click on Deploy.
And you have deployed a contract linked to a library!
Under the Hood
Let’s see where the library’s address gets placed in the contract’s bytecode.
- Switch to the Solidity Compiler module
- Select the sampleContract contract in the list of compiled contracts.
- Click on ByteCode, it should copy the following to the clipboard:
Essentially, this what the compiler is returning.
For our purposes we are interested in the linkReferences element and the object element.
- linkReferences: ( the 1st element) describes what are the libraries used by the contract.
- object (the next element) is the compiled contract (bytecode). This is what gets deployed and saved onto the blockchain. In this example, the value __$83229fb62534ab89035722de277194ff6d$__ inside the bytecode is just a placeholder for the library address. In your case, the placeholder will be between __$ and $__. It is a bit buried — so search for the __$ (underscore underscore dollar sign).
The metadata JSON from Remix IDE tells Remix to replace the placeholder with the given address.
To review, the library’s address gets injected at deployment — so the replacement of the placeholder with the actual address happens at this stage. If we had just used the library as a normal contract and imported it at compile time, we would be deploying its code with the contract’s code — so there would be no gas savings. By digging into the metadata.json file and updating its settings, we can use a library to decrease the size of the contract and bask in the joy of saving some gas.