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 0.5.2).

image

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" }

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 } 
gas_reports = ["*"] # <= This is important to be added

[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

image

Just add a new project

image

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 project my-project at version 1.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 do import '@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.