Skip to main content

Config File Reference

All cubist applications have a JSON config file cubist-config.json, which specifies:

  • "type": the kind of project the off-chain application code is written in (valid values: "TypeScript", "JavaScript", and "Rust"),
  • "build_dir": where Cubist will write build output (can be overridden via CUBIST_BUILD_DIR env var),
  • "deploy_dir": where Cubist will generate deployment scripts and information (can be overridden via CUBIST_DEPLOY_DIR env var),
  • "contracts": assignment of contracts to chains (currently per contract source file, not per contract)
  • "network_profiles": named profiles containing network/chain configurations
  • "current_network_profile": currently selected network profile (can be overridden via CUBIST_NETWORK_PROFILE env var).

Example JSON file:

{
"type": "TypeScript",
"build_dir": "./build",
"deploy_dir": "./deploy",
"contracts": {
"root_dir": "./contracts",
"targets": {
"avalanche": { "files": [ "./contracts/ava.sol" ] },
"polygon": { "files": [ "./contracts/poly.sol" ] },
"ethereum": { "files": [ "./contracts/eth1.sol", "./contracts/eth2.sol" ] }
}
},
"network_profiles": {
"default": {
"avalanche": { "url": "http://localhost:9560", "autostart": true },
"ethereum": { "url": "http://localhost:7545", "autostart": true },
"polygon": { "url": "http://localhost:9545", "autostart": true }
},
"dev": {
"avalanche": { "url": "http://otherhost:9560" },
"ethereum": { "url": "http://otherhost:7545" },
"polygon": {
"url": "wss://polygon-mumbai.g.alchemy.com/v2/${{env.ALCHEMY_MUMBAI_API_KEY}}",
"proxy": {
"port": 9545,
"chain_id": 80001,
"creds": [{
"mnemonic": { "seed": { "env": "MUMBAI_ACCOUNT_MNEMONIC" } }
}]
}
}
}
},
"current_network_profile": "dev"
}

In the following, we explain the different pieces of the configuration using this example.

Contract Configuration

First off, the user must specify a root directory under which all contract files live. At the moment, Cubist requires a single such root directory.

Next, each contract file must be assigned to a target chain. Contract file paths must be specified relative to the project root directory, and not the contracts root directory (hence the repetition of "./contracts/" in the example above); this is intentional, mimicking package imports in TypeScript.

Optionally, "import_dirs" may be provided as well (when omitted, defaults to ["node_modules"]). As the name suggests, import directories are only used when resolving non-relative imports from contract source files. In other words, contracts from import directories are not automatically compiled and included in the final Cubist dapp.

Network Configuration

Each network profile (under the "network_profiles" element) must provide configuration for every target chain in use.

A portion of that configuration is common to all chains and it includes:

  • "url": URL of the chain endpoint
  • "autostart": whether to start a local instance of the chain at url (applies only if url is a localhost address)
  • "proxy": whether and how to start a Cubist Proxy in front or url (applies only if autostart is false)
caution

On some platforms, using localhost directly in the configuration file leads to errors. If you're having problems, changing the URL to http://127.0.0.1:... should fix the issue.

(Using localhost can cause issues because some operating systems will resolve localhost to the IPv6 address ::1 instead of the IPv4 address 127.0.0.1. This causes errors because the Cubist background processes listen only on the IPv4 address.)

Autostart Local Networks

If autostart is true (default) and url is a localhost address, Cubist (the cubist start command, to be precise) will automatically start a local instance of the specified chain. For example,

{
"ethereum": { "url": "http://localhost:8545", "autostart": true },
"polygon": { "url": "http://localhost:9545", "autostart": true }
}

will instruct Cubist to launch anvil (an Ethereum implementation) and make its JSON RPC endpoint available at http://localhost:8545, as well as bor (a Polygon implementation) and make its JSON RPC endpoint available at http://localhost:9545.

Cubist exposes different customization options for different target chains; here are some examples:

Example: Create funded accounts on Ethereum

The following configuration snippet will bootstrap anvil with 2 funded accounts generated from a specific mnemonic. The mnemonic is read from the ETHEREUM_MNEMONIC environment variable (.env files are supported).

{
"url": "http://localhost:8545",
"autostart": true,
"bootstrap_mnemonic": {
"seed": { "env": "ETHEREUM_MNEMONIC" },
"account_count": 2
}
}

Example: Create funded accounts on Polygon

The following configuration snippet will bootstrap bor with 2 funded accounts, one generated from a given mnemonic (read from the POLYGON_MNEMONIC env var) and one from a given private key (read from the .polygon.secret file).

{
"url": "http://localhost:8545",
"autostart": true,
"local_accounts": [
{ "mnemonic": { "seed": { "env": "POLYGON_MNEMONIC" } } },
{ "private_key": { "hex": { "file": ".polygon.secret" } } }
]
}

Connect to a Public Network

Before discussing how to configure Cubist to connect to public networks, we must first briefly introduce Cubist Proxy.

Cubist Proxy

Cubist Proxy is a component that sits between the client dapp and an actual chain endpoint node and automatically signs every transaction submitted via eth_sendTransaction. All other JSON RPC requests (with a few exceptions) are forwarded to the real endpoint as is.

This is very useful when connecting to a public network, because all credentials can be securely managed by Cubist Proxy. Consequently, the client-side app doesn't have to worry about managing secrets, signing, computing nonces, etc. Proxy configuration includes:

  • "port": localhost port on which the proxy will be listening for requests
  • "chain_id": id of the target chain (so that Cubist Proxy can automatically set it if not set by the client app)
  • "creds": credentials to use.

For every eth_sendTransaction request it receives, Cubist Proxy:

  1. extracts the sender field from it,
  2. looks up the credentials for that sender,
  3. populates any missing transaction parameters (e.g., chain id, nonce, etc.),
  4. signs the transaction on behalf of sender, and finally
  5. forwards the signed transaction to the endpoint via eth_sendRawTransaction.

Example: Connecting to a Public Testnet

When using local chains only, no explicit account/authentication configuration needs to be provided by the user. That's because Cubist will use a default account to start each local chain, and Cubist Proxy will use that same account to automatically sign transactions targeting that chain.

In contrast, when connecting to a public network, the user must already have an account set up with that network provider. If that network only accepts signed transactions (and most likely it does), Cubist must be configured to sign transactions using that existing account. Because the Cubist SDK does not deal with signing at all (by design!), the solution is to configure and run a Cubist Proxy in front of the remote endpoint.

The url field is used to specify a public network endpoint, e.g., wss://polygon-mumbai.g.alchemy.com/v2/${{env.ALCHEMY_MUMBAI_API_KEY}}api-key. Additionally, Cubist Proxy must be configured with at least one credential, which it will use to sign all transactions. The following example specifies a bip39 mnemonic:

{
"url": "wss://polygon-mumbai.g.alchemy.com/v2/${{env.ALCHEMY_MUMBAI_API_KEY}}",
"proxy": {
"port": 9545,
"chain_id": 80001,
"creds": [{
"mnemonic": { "seed": { "env": "MUMBAI_ACCOUNT_MNEMONIC" } }
}]
}
}

  1. Note the use of ${{env.ALCHEMY_MUMBAI_API_KEY}}: instead of hardcoding the secret API key into the plain-text config file, we use the special ${{env.VAR_NAME}} syntax to instruct Cubist to read it from the environment.