Deployment
Prerequisites
Before beginning this process, you should have:
Synced Chia full node
Synced Ethereum full node
A Coinbase Cloud account and access to your base RPC URL (details in step 1)
A Nostr relay (empty public key whitelist)
Access to the machine you intend to run the validator software on
Two hardware wallets, one for Ethereum (e.g., Trezor) and one for Chia (Tangem)
The Ozone wallet app installed on your phone
Note: For testnet deployment, you don't need the Chia/Ethereum full nodes to get everything set up (see details in step 1). However, you should still sync nodes to test the setup is working as a whole.
Step 0: Generate Keys
First, install the validator software from here by following the instructions. You'll then need generate your two (Chia/EVM) hot keys and a Nostr private key by running:
Even if you're deploying on testnet, take the scenario seriously and handle keys properly.
When running the commands, you'll see Warning: Failed to load config.json
- ignore the warning for now, as we'll set up the config in later steps.
It is up to you if you want to back up mnemonics - a majority of validators can always rekey the portal. In the next step, you're going to use:
Chia/Ethereum private keys (hex format)
Nostr mnemonic
Before proceeding, please send a message that follows the template below on the deployment channel:
To get your Tangem public key, you'll need to use Ozone. Connect your Tangem card to the app. Once you're on the main screen (which displays your wallet balance), press on 'Settings' in the top right corner. Select 'Sign Messages' and put any message in the message field. Once you sign it, your card's key will be found in the response JSON ("pubkey").
Please see 'Attestations' to see how to generate an attestation for your cold XCH key. Note that the config is not yet set, so you'll need to use the optional --pubkey
switch.
A validator's index can always be used to get their details from lists. For example, in the multisig_keys
list we'll set below, multisig_keys[index]
will contain the multisig (cold) key of the validator for a given index. Note that these are 'code' lists - i.e., numbering starts at 0. Please do NOT make everything confusing by identifying yourself with a negative index.
Once you send the message, you may proceed to the next step and save the private keys in the config file.
Step 1: Set up config.json
In the root of the 'cli' local copy, create a file called 'config.json' and paste the following template:
From the previous step, you should fill:
xch.my_hot_private_key
with your hot XCH keyeth.my_hot_private_key
andbse.my_hot_private_key
with your hot Ethereum keynostr.my_mnemonic
with your Nostr mnemonic
After all validators have submitted their details, validator 0 will send a message containing values for:
xch.portal_keys
andxch.multisig_keys
eth.hot_addresses
=bse.hot_addresses
nostr.relays
The message will also contain a list of public keys to add to your Nostr server whitelist. At this point, you may can set:
xch.chia_root_or_chia_url
If you're running a node locally, replace this key with
xch.chia_root
and set it to the location of the 'mainnet' folder (e.g.,/home/yakuhito/.chia-testnet11/mainnet
)If you are on testnet and your node is still syncing, replace the key with
xch.chia_url
and set it tohttps://testnet.fireacademy.io
. Please make sure to switch it with the option above (xch.chia_root
) once you're synced!
xch.portal_threshold
,xch.multisig_threshold
,eth.portal_threshold
,bse.portal_threshold
: Set to 3 for testnet, 7 for mainnetxch.sign_min_height
: The minimum number of confirmations a message needs to have on Chia for it to be signed. Used to prevent attacks exploiting re-orgs - set this value to 5 for testnet and 32 for mainnet (source).eth.rpc_url
: Point this to your Ethereum RPC URL.If you're on testnet and waiting for your node to sync, you can set the value to an Alchemy/Infura/etc. RPC URL. However, please make sure to make it point to your node later, as you should test your whole infrastructure.
eth.sign_min_height
andbse.sign_min_height
: The minimum number of confirmations a message needs to have on L1 for it to be signed. Please see this post about finality. For mainnet, set this value to 64 (2 epochs). For testnet, set the value to 10 (~2 minutes) for Base and 64 for Ethereum (Sepolia).bse.rpc_url
: You can create a Coinbase Cloud account here. You'll be allowed to create a node for free (i.e., get an API key).For mainnet, the value should look like this:
https://api.developer.coinbase.com/rpc/v1/base/[api-key]
For testnet, please ensure that you select 'Base Sepolia' (i.e., testnet) before copying the URL. It's somewhere on the page, and the default is mainnet even if you 'created' a testnet node. The value should look like this:
https://api.developer.coinbase.com/rpc/v1/base-sepolia/[api-key]
Don't forget to update your Nostr server's pubkey whitelist - Validator 0 will share the list after all validators have submitted their attestations.
Step 2: Deploy contracts
Validator 0 will deploy the portal singleton on XCH and a multisig on each EVM network (Ethereum and Base). Once addresses are shared, fill in the following config values:
xch.portal_launcher_id
- Launcher id of portal singleton (will be sent in a message)xch.min_height
- First block when messages can be sent. Will also be included in the message.eth.deployer_safe_address
andbse.deployer_safe_address
: This is the cold key multisig. Get the addresses from the message and access them using the Safe{Wallet} app. Check that the threshold and addresses are set appropriately (same values as config).
In the Safe app, a deployment transaction will also be created shortly after. After updating the config, you can verify the transactions using:
Slightly different versions of the solidity compiler might generate different addresses. Check the addresses from the output against what you got from Validator 0 - on mainnet, a specific docker image will be used, which you will be able to use yourself to get the same address.
Where [chain-id]
is either 'eth' or 'bse.' For each EVM network, you can go on to fill the following config values:
portal_address
: The address of the portal. In the deploy command output, you can find it underTx 2: deploy TransparentUpgradeableProxy
asPredicted address
.erc20_bridge_address
: The address of theERC20Bridge
contract. It's thePredicted address
underTx 3: deploy ERC20Bridge
.
To allow the Portal contract to be updated, it'll be deployed behind a standard proxy called "TransparentUpgradeableProxy." The address of the 'Portal' contract is the 'logic address' (it implements the current logic of the portal, which means the address can change). However, when specifying the portal address, always refer to the address of the proxy contract, as that is the contract that runs the logic (e.g., sends and receives messages).
Once the transaction has enough confirmations, it will be executed by validator 0. You'll then be able to fill in the last two config values, eth.min_height
and bse.min_height
. Their value should be the block that the contract deployment transaction was confirmed at.
Step 3: Run validator
You're now ready to run the validator software! Start it using:
Last updated