Build the app
Now that we've installed Cubist, we can build our app! First, we describe
how to build the app; then, we describe what Cubist does when we
run build
.
The following instructions assume that you have installed Cubist.
Build instructions
In the cubist-config.json
we specify the target
chains
on which each contract should run:
{
...
"targets": {
"ethereum" : {
"files": ["./contracts/StorageReceiver.sol"]
},
"polygon": {
"files": ["./contracts/StorageSender.sol"]
}
},
...
}
To change chains, simply alter the configuration file to specify a different chain.
Cubist only allows you to assign chains at a per file granularity---not per contract. If you have two contracts in the same file and want to deploy them on different chains, you'll have to put each contract in its own file.
Now that we've specified where our contracts should run, we build the project using Cubist:
cubist build
What's going on behind the scenes
After we run build
, Cubist generates files in two places. It:
- Creates a
build
directory that contains the compiled contracts (and more). - Adds files to the Rust
src
directory. These files allow us to interact with our smart contracts from within our Rust application.
We walk through the build
dir and the src
dir next.
The build
directory
When you run cubist build
, Cubist generates new files in the build
directory, organized with one directory per target chain:
build
├── ethereum
│ ├── artifacts // Compiled contracts that will run on ethereum
│ │ ├── ...
│ └── contracts // Source files of original and shim contracts on ethereum
| └── ...
└── polygon
├── artifacts // Compiled contracts that will run on polygon
│ ├── StorageReceiver.sol
│ │ └── StorageReceiver.json // ABI (and more) for the shim StorageReceiver contract
│ └── StorageSender.sol
│ └── StorageSender.json // ABI (and more) for the "normal" StorageSender contract
└── contracts
├── StorageReceiver.bridge.json // Configuration for the Cubist relayer
├── StorageReceiver.sol // Shim contract source
└── StorageSender.sol // Original StorageSender source
Within each target directory---here, the polygon
and ethereum
directories---Cubist
saves:
- the ABIs produced when compiling the contracts with
solc
(within theartifacts
directory) - the original and shim source files (in the
contracts
directory).
In this example, the interesting files are in the
polygon
directory. That's because the StorageSender
contract, deployed on
Polygon, makes a cross-chain call by executing receiver.store(..)
on a
StorageReceiver
contract deployed on Ethereum.
As a result, Cubist must generate a StorageReceiver
shim on Polygon for the
the StorageSender
contract to interact with; that shim will emit events anytime
StorageSender
calls a StorageReceiver
function, and the off-chain Cubist relayer
will relay those events to the real StorageReceiver
contract on Ethereum. Here's
an example of the generated shim code, which lives in
build/polygon/contracts/StorageReceiver.sol
:
contract StorageReceiver {
event __cubist_event_StorageReceiver_store(uint256 num);
...
function store(uint256 num) public onlyCaller {
emit __cubist_event_StorageReceiver_store(num);
}
}
The build also generates the information that lets the off-chain relayer do its
job; this information is in the StorageReceiver.bridge.json
file.
You should not modify any of the files in the build
directory.
These files are automatically generated, so your changes may get
overwritten.
The src
directory
Cubist also generates the code that allows our Rust dapp to interact
with the StorageReceiver and StorageSender contracts.
After running build
, our source directory looks like this:
src
├── main.rs // Our dapp code
├── cubist_gen.rs // Cubist-generated bindings for interacting with both contracts
└── cubist_gen
├── storage_receiver.rs // Cubist-generated bindings for StorageReceiver
└── storage_sender.rs // Cubist-generated bindings for StorageSender
The code in src/main.rs
is pre-existing (because this is an example!), but
you'll likely write your app code after running cubist build
. Your app code
will use the bindings that Cubist generates in cubist_gen
and
cubist_gen.rs
;
we'll walk through the functions in that file and directory in
step four, when we run the example application.