4

Currently the cargo build produces one WASM file like contract/target/wasm32-unknown-unknown/release/hello.wasm. How can I produce multiple wasm binaries if my contract source tree contains multiple contracts, one per named Rust module?

My Cargo.toml

[package]
name = "hello"
version = "0.1.0"
authors = ["Why so difficult <argh@example.com>"]
edition = "2018"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
near-sdk = "2.0.0"

[profile.release]
codegen-units = 1
# Tell `rustc` to optimize for small code size.
opt-level = "z"
lto = true
debug = false
panic = "abort"

[workspace]
members = []

Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435

2 Answers2

4

Yes. At the time of this writing we currently don't have anything similar to Truffle for deploying multiple contracts. We've been organizing multiple contracts into their own directories and then using a parent-level build-all.sh script that essentially runs a directory's build.sh.

An example would be the Chainlink repository here: https://github.com/smartcontractkit/near-protocol-contracts

So for instance, one of the three contracts (oracle in this case) has its own directory with a build.sh script:

#!/bin/bash

cargo build --target wasm32-unknown-unknown --release
mkdir -p ./res
cp target/wasm32-unknown-unknown/release/oracle.wasm ./res

Note: when building smart contracts on NEAR you may see cargo build… commands that have more flags than are shown here. In this particular example, those flags have been moved to the .cargo/config file:

[build]
rustflags = ["-C", "link-args=-s"]

This helps for cross-platform compatibility, particularly with Windows.


Then at the parent level of the project there's a simple bash script that runs the child scripts like so:

#!/bin/bash

cd near-link-token && ./scripts/build && cd ..
cd oracle && ./scripts/build && cd ..
cd client && ./scripts/build && cd ..

We do look forward to having a more robust deployment mechanism in the future.

mikeDOTexe
  • 487
  • 5
  • 14
  • Thank you! This example is super helpful. What are the techical requirements to produce a WASM binary for NEAR? I might want to try to stab the tool chain and see if I could avoid the excessive directories and extra toml files. – Mikko Ohtamaa Sep 29 '20 at 12:02
  • 1
    I found this super helpful https://stackoverflow.com/questions/54843118/why-can-a-cargo-package-only-have-one-library-target – Mikko Ohtamaa Sep 29 '20 at 12:30
  • Looks like if binary instead of library would be used as a target it would be easy to build multiple contracts https://stackoverflow.com/a/36604610/315168 – Mikko Ohtamaa Sep 29 '20 at 12:33
  • Moving the correct tick to the other answer, as it is gaining traction. – Mikko Ohtamaa Oct 03 '20 at 16:37
3

Although each contract still needs to go to its own crate, there is a cargo feature called workspaces that remove at least some of the repetitive boilerplate out of your contracts and you will have only one Cargo.lock file.

Split contract folder to multiple folders - let's call them 'token' and 'pool'.

On the the top contract folder have one workspaced Cargo.toml:

[profile.release]
codegen-units = 1
# Tell `rustc` to optimize for small code size.
opt-level = "z"
lto = true
debug = false
panic = "abort"

# Important security flag for the compiler,
# otherwise not present in optimised builds
# https://stackoverflow.com/q/64129432/315168
overflow-checks = true


[workspace]
members = [
    "token",
    "pool"
]

Then on each folder you have its own Cargo.toml that can have dependencies to other crates in the same workspace:

[package]
name = "nep9000_pool"
version = "0.0.0"

# https://stackoverflow.com/a/53985748/315168
edition = "2018"

[dependencies]
near-sdk = "2.0.0"
nep9000_token = { path = "../token" }


[lib]
crate-type = ["cdylib", "rlib"]

One cargo build in the root will build them all.

Full example.

Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435