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).
Initialize a new project
If you’re using Soldeer for the first time in a new Foundry project, you can use the init
command to install a fresh instance of Soldeer, complete with the necessary configurations and the latest version of forge-std
.
forge soldeer init
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" }
Add a Dependency Stored in GIT
If you choose to use Git as a source for your dependencies — though we generally discourage this, since Git isn’t designed to be a dependency manager — you can provide the Git repository link as an additional argument. Soldeer will then automatically handle the installation using a Git subprocess. For example:
forge soldeer install forge-std~1.9.2 https://github.com/foundry-rs/forge-std.git
If you want to use a specific revision, branch, or tag, you can do so by appending the following arguments to the command: --rev/--tag/--branch
e.g.
forge soldeer install forge-std~1.9.2 https://github.com/foundry-rs/forge-std.git --rev 4695fac44b2934aaa6d7150e2eaf0256fdc566a7
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
You can use forge soldeer uninstall DEPENDENCY
.
Example: forge soldeer uninstall @openzeppelin-contracts
. This will action will remove:
- the config entry
- the
dependencies
artifacts - the
soldeer.lock
entry - the
remappings
entry (txt or config remapping)
Additionally you can manually remove a dependency by just removing the artifacts: dependency files, config entry, remappings entry.
Remappings
The remappings are now fully configurable, the config TOML file (foundry.toml) accepts a
[soldeer]
field with the following options
[soldeer]
# whether soldeer manages remappings
remappings_generate = true
# whether soldeer re-generates all remappings when installing, updating or uninstalling deps
remappings_regenerate = false
# whether to suffix the remapping with the version: `name-a.b.c`
remappings_version = true
# a prefix to add to the remappings ("@" would give `@name`)
remappings_prefix = ""
# where to store the remappings ("txt" for `remappings.txt` or "config" for `foundry.toml`)
# ignored when `soldeer.toml` is used as config (uses `remappings.txt`)
remappings_location = "txt"
Installing dependencies of dependencies aka sub-dependencies
Whenever you install a dependency, that dependency might have other dependencies that need to be installed as well. Currently, you can handle this by either specifying the recursive_deps
field as a configuration entry in the config file or by passing the --recursive-deps
argument when running the install or update command. This will ensure that all necessary sub-dependencies are automatically pulled in.
e.g.
[soldeer]
recursive_deps = true
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
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
Login Data
By default, Soldeer saves the login token in the ~/.soldeer/.soldeer_login
file, which is used to push files to the central repository. If you prefer to save the token in a different location, you can set the environment variable SOLDEER_LOGIN_FILE
.
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.