Build ink contracts without worrying up about setting up your environment with correct dependencies.
This repository contains minimal (at least per its authors knowledge) docker container capable of compiling and building ink! 4.0 contracts.
This works for cases where contract doesn't depend on other contracts by path. For that, see advanced usage
Suggested developer usage is to add the following function to your ~/.bashrc:
function ink-build() {
docker run \
-v ${PWD}:/code \
--platform linux/amd64 \
--rm -it cardinal-cryptography/ink-dev:latest \
cargo contract build --release --quiet
}
NOTE: For ARM use --platform linux/arm64/v8
instead.
Don't forget to source ~/.bashrc
before first usage.
Then use in your project:
$ cd my-project
$ ink-build()
Or, more flexible:
function ink-dev() {
docker run --rm -it \
-v ${PWD}:/code \
-v ~/.cargo/git:/usr/local/cargo/git \
-v ~/.cargo/registry:/usr/local/cargo/registry \
--platform linux/amd64 \
-u $UID:$(id -g) \
cardinal-cryptography/ink-dev:latest "$@"
}
which will now allow for passing in different commands and/or arguments:
$ ink-dev cargo contract check
$ ink-dev cargo contract build --manifest-path some/other/project/Cargo.toml
Another potential use case is to access ink-wrapper within the environment and generate ink!
types based on the contract metadata file. This can be done as follows:
function ink-wrapper {
docker run --rm \
-u $UID:$(id -g) \
-v "${PWD}":/code \
-v ~/.cargo/git:/usr/local/cargo/git \
-v ~/.cargo/registry:/usr/local/cargo/registry \
--entrypoint /bin/sh \
cardinal-cryptography/ink-dev:latest \
-c "ink-wrapper -m metadata.json | rustfmt --edition 2021 > src/ink_contract.rs"
}
This will use metadata.json
to generate ink_contract.rs
which will contain useful types such a representation of the contract and the methods defined on it.
Remember, since mounting volume for the Docker container will mount only that directory recursively any files in the parent directories will not be available/visible inside the container. Below, we present solutions to some more common scenarios in which you might want to use the container.
If your project have similar structure to the following:
my-app/
├─ ink-project-a/
│ ├─ Cargo.toml
│ ├─ lib.rs
├─ ink-project-b/
│ ├─ Cargo.toml
│ ├─ lib.rs
├─ rust-toolchain
where you want to overwrite Rust for all projects inside my-app
, you will have to mount my-app
as docker volume. Only then the rust-toolchain
overrides will be "visible" for both Ink projects.
Example command (assuming PWD=/my-app
):
docker run --rm -v ${PWD}:/code cardinal-cryptography/ink-dev:latest cargo contract build --release --manifest-path ink-project-a/Cargo.toml
By providing --manifest-path
we can specify exactly which project we want to build.
If your contract depends on other contracts using its path, example:
# imaginary Cargo.toml of your contract
[dependencies]
my_other_contract = { path = "../other-contract" features = ["ink-as-dependency"] }
Then using it as described in previous section will fails with [ERROR]: cargo metadata
, that's b/c the my_other_contract
dependency isn't loaded into docker container.
For these cases, we need to mount additional directories manually:
docker run --rm -it \
-v ${PWD}:/code \
-v ~/.cargo/git:/usr/local/cargo/git \
-v ~/.cargo/registry:/usr/local/cargo/registry \
-v ${PWD}/../other-contract:/other-contract
--platform linux/amd64 \
-u $UID:$(id -g) \
cardinal-cryptography/ink-dev:latest \
cargo contract build --release --quiet
Notice the additional -v ${PWD}/../other-contract:/other-contract
which will mount your dependency so that it's visible in the docker container.
The image is built on minimal Debian linux distribution to ensure minimal resulting image size. Only minimal Rust dependencies are installed.
In the root directory run make build-image
.
optimized-build.toml
file contains special build profile used for building cargo-contract
package which results in smaller binary than when using defaults.
To test that the resulting image can build contracts written in ink, run make test-contract-x86_64
(if you're running on ARM, execute test-contract-arm64
) and verify that test-contract/target
contains correct results.