Soldeer as a Package Manager
As explained here, Foundry has been using git submodules to handle dependencies up until now.
The need for a native package manager started to emerge as projects became more complex.
A new approach has been in the making, soldeer.xyz, which is a Solidity native dependency manager built in Rust and open sourced (check the repository https://github.com/mario-eth/soldeer).
Adding a Dependency
Add a Dependency Stored in the Central Repository
To add a dependency, you can visit soldeer.xyz and search for the dependency you want to add (e.g., openzeppelin 5.0.2).
Then just run the forge command:
forge soldeer install @openzeppelin-contracts~5.0.2
This will download the dependency from the central repository and install it into a dependencies
directory.
Soldeer can manage two types of dependency configuration: using soldeer.toml
or embedded in the foundry.toml
. In order to work with Foundry, you have to define the [dependencies]
config in the foundry.toml
. This will tell the soldeer CLI
to define the installed dependencies there.
E.g.
# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config
[profile.default]
auto_detect_solc = false
bytecode_hash = "none"
fuzz = { runs = 1_000 }
libs = ["dependencies"] # <= This is important to be added
gas_reports = ["*"]
[dependencies] # <= Dependencies will be added under this config
"@openzeppelin-contracts" = { version = "5.0.2" }
"@uniswap-universal-router" = { version = "1.6.0" }
"@prb-math" = { version = "4.0.2" }
forge-std = { version = "1.8.1" }
Add a Dependency Stored at a Specific Link
If the central repository does not have a certain dependency, you can install it by providing a zip archive link.
E.g.
forge soldeer install @custom-dependency~1.0.0 https://my-website.com/custom-dependency-1-0-0.zip
The above command will try to download the dependency from the provided link and install it as a normal dependency. For this, you will see in the config an additional field called path
.
E.g.
[dependencies]
"@custom-dependency" = { version = "1.0.0", path = "https://my-website.com/custom-dependency-1-0-0.zip" }
Remapping Dependencies
The remapping of a dependency is performed automatically, Soldeer is adding the dependency into the remappings.txt
.
E.g.
@openzeppelin-contracts-5.0.2=dependencies/@openzeppelin-contracts-5.0.2
@uniswap-universal-router-1.6.0=dependencies/@uniswap-universal-router-1.6.0
@prb-math-4.0.2=dependencies/@prb-math-4.0.2
@forge-std-1.8.1=dependencies/forge-std-1.8.1
These remappings mean:
- To import from
forge-std
, we would write:import "forge-std-1.8.1/Contract.sol";
- To import from
@openzeppelin-contracts
, we would write:import "@openzeppelin-contracts-5.0.2/Contract.sol";
Updating Dependencies
Because Soldeer specifies the dependencies in a config file (foundry or soldeer toml), sharing a dependency configuration within the team is much easier.
For example, having this Foundry config file in a git repository, one can pull the repository and then run forge soldeer update
. This command will automatically install all the dependencies specified under the [dependencies]
tag.
# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config
[profile.default]
auto_detect_solc = false
bytecode_hash = "none"
fuzz = { runs = 1_000 }
libs = ["dependencies"] # <= This is important to be added
gas_reports = ["*"]
[dependencies] # <= Dependencies will be added under this config
"@openzeppelin-contracts" = { version = "5.0.2" }
"@uniswap-universal-router" = { version = "1.6.0" }
"@prb-math" = { version = "4.0.2" }
forge-std = { version = "1.8.1" }
Removing Dependencies
To remove a dependency, you have to manually delete it from the dependencies
directory and from the [dependencies]
tag.
Pushing a New Version to the Central Repository
Soldeer acts like npmjs/crates.io, encouraging all developers to publish their projects to the central repository.
To do that, you have to go to soldeer.xyz, create an account, verify it, then
Just add a new project
After the project is created, you can go into your project source and:
- Create a
.soldeerignore
file that acts as a.gitignore
to exclude files that aren’t needed. The.gitignore
file is also respected. - Run
forge soldeer login
to log into your account. - Run
forge soldeer push my-project~1.0.0
in your terminal in the directory that you want to push to the central repository associated with the projectmy-project
at version1.0.0
.
If you want to push a specific directory and not the current directory your terminal is in, you can use forge soldeer push my-project~1.0.0 /path/to/directory
.
Warning ⚠️
You are at risk to push sensitive files to the central repository that then can be seen by everyone. Make sure to exclude sensitive files in the .soldeerignore
file.
Furthermore, we’ve implemented a warning that it will be triggered if you try to push a project that contains any .dot
files/directories.
If you want to skip this warning, you can just use
forge soldeer push my-project~1.0.0 --skip-warnings true
Dry-run
In case you want to simulate what would happen if you push a version, you can use the --dry-run
flag. This will create a zip file that you can inspect before pushing it to the central repository.
forge soldeer push my-project~1.0.0 --dry-run true
Warning ⚠️
- Once a project is created, it cannot be deleted.
- Once a version is pushed, it cannot be deleted.
- You cannot push the same version twice.
- The project name in the command that you run in the terminal must match the project name that you created on the Soldeer website.
- We encourage everyone to use version pinning when importing them into the contracts, this will help with securing your code by knowing exactly what version of a dependency you are using. Furthermore, it will help security researchers in their work.
- Make sure you delete this zip file before pushing the version if you run dry-run. e.g. instead of using
import '@openzeppelin-contracts/token/ERC20.sol'
you should doimport '@openzeppelin-contracts-5.0.2/token/ERC20.sol'
What happens if a certain package is not present in the central repository?
- If a certain package is not present in the central repository, you can open an issue in the Soldeer Repository and the team will look into adding it.
- If you have a package that you want to use and it is not present in the central repository, you can push it to the central repository by following the steps above.