Welcome to the Cubist docs!
Cubist is an SDK and command line tool for building distributed web3 applications. Dive in with our easy example app!
Cubist’s goal is to make testing and development seamless, even if your dapp runs across multiple chains. Using our SDK, you write smart contracts as if they're deployed on the same chain; Cubist automatically generates the tricky (and risky!) bridge code that allows your smart contracts to interact.
What version of Cubist is this release?
Cubist alpha version 0.2.1-alpha.
Cubist is currently in its alpha release. APIs may change in the future, and you should not use Cubist to deploy apps to mainnet (yet)!
What chains and languages does Cubist support?
Cubist supports off-chain code written in:
- JavaScript
- TypeScript
- and Rust
Cubist supports development and deployment for:
- Ethereum
- Polygon
- Avalanche
- and Avalanche subnets
Support for more chains and more off-chain languages coming soon!
What Cubist tools do I need to get started?
There are two pieces you need to use Cubist:
- The Cubist CLI tool. The CLI tool is what you use to build your projects, run chains locally for testing, run the Cubist relayer, etc.
- The Cubist SDK. The SDK is what you use to interact with your
contracts from off the chain; right now, there's a Java/TypeScript SDK and
a Rust SDK. Typically, you won't use the SDK directly. Instead, when you
use the CLI to
cubist build
your project, Cubist will generate ORM code that makes it easy to interface with your contracts. This ORM code is built from (and exposes) SDK functions. You can learn more by checking out our example applications or the Node SDK and Rust SDK docs.
What does cross-chain code look like using Cubist?
With Cubist, cross-chain contracts look exactly like single-chain contracts; Cubist automatically generates the cross-chain code that allows the contracts to interact.
What's an example of cross-chain code using Cubist?
Consider an application that exposes a number stored across two different chains. The sender contract stores a number and then sends it to the receiver contract; the receiver contract stores the number, too.
Here's an example of the sender contract:
import './StorageReceiver.sol';
contract StorageSender { // deployed on one chain
StorageReceiver receiver; // deployed on a different chain
uint256 number;
constructor (uint256 num, StorageReceiver addr) {
number = num;
receiver = addr;
}
function store(uint256 num) public onlyOwner {
number = num;
receiver.store(number); // cross-chain call
}
}
Even though the sender contract and receiver contract are deployed
on different chains, we can write them as if they're deployed on the
same chain. Cubist will analyze the contracts and emit extra code
and contracts that allow receiver.store(number)
to actually send
the number from one chain to another.
What are the limitations of Cubist's cross-chain support?
Right now, Cubist can only generate cross-chain code for public functions with no return values.
If you're interested in support for other types of functions, reach out to us at [email protected] or on discord.
How do I change chains?
You can change the chain on which your contract runs by editing a
configuration file.
Your cubist-config.json
will look something like this:
{
...
"targets": {
"ethereum" : {
"files": ["./contracts/StorageReceiver.sol"]
},
"polygon": {
"files": ["./contracts/StorageSender.sol"]
}
},
...
}
This tells Cubist that StorageReceiver.sol
should be deployed on Ethereum
and StorageSender.sol
should be deployed on Polygon. Changing polygon
to avalanche
would direct Cubist to deploy StorageSender
on Avalanche
instead.
How do I change bridge providers?
Right now, the only relayer available is the Cubist Trusted Relayer. Our next release will support the Axelar bridge provider (and potentially others as well). Changing bridge providers will be the same as changing chains---just a matter of editing the configuration file.
Reach out at [email protected] or on discord if you're interested in new bridge provider support!
How does Cubist generate cross-chain code?
Given your contract source code and intended targets for each file,
Cubist analyzes each contract. For example, in the StorageSender
contract above, Cubist determines that StorageSender
uses
the StorageReceiver
contract in StorageReceiver.sol
.
Cubist knows that StorageReceiver
is deployed on Chain B, while
StorageSender
is deployed on Chain A. Since StorageSender
calls
StorageReceiver
, Cubist generates a "shim" contract that exposes
StorageReceiver
to Chain A. Anytime StorageSender
calls a
StorageReceiver
function, it's actually calling the Chain A shim's
version of the function. The shim function emits events that the Cubist
relayer uses to relay function calls to the "real" StorageReceiver
contract on Chain B. There are more detailed walk-throughs in the
advanced examples.