Opening a Connection
For new chains or rollups, the first step to sending messages or transferring assets is opening a connection.
The connection codifies the security assumptions between Union and your chain and is updated using
consensus proofs. This should be done after having a Cometbls
light client configured.
Relaying
Voyager
is our relayer: an off-chain tool to submit packets and consensus proofs. Voyager can initiate the connection
during initial setup, as well as relaying packets and proofs once the connection is live. First, we need to download the binary:
# Download voyager
wget https://github.com/unionlabs/union/releases/download/$LATEST/voyager-x86_64-linux -O voyager && chmod +x voyager
On top of the relayer, a proving server is necessary to generate the ZKPs:
# Download galoisd
wget https://github.com/unionlabs/union/releases/download/$LATEST/galoisd-x86_64-linux -O galoisd && chmod +x galoisd
# Download the circuit and keys
wget https://github.com/unionlabs/union/releases/download/$LATEST/circuit.zip && unzip circuit.zip
Finally, Voyager uses a Postgres instance to persist state. You can use an appropriate SaaS solution or a local installation.
Starting galoisd
We need to run galoisd
, our prover to be able to generate ZKPs. We recommend running Galois on a separate server with at least 32 GB of RAM and 8 physical cores.
galoisd \
--serve 0.0.0.0:9999 \
--cs-path=./circuit/r1cs.bin \
--pk-path=./circuit/pk.bin \
--vk-path=./circuit/vk.bin \
--max-conn 1
Setting up Voyager
We recommend running Voyager on a machine co-located with your chain’s RPC nodes, to ensure low latency. Below is an example configuration file (minimal-config.json).
{
"chain": {
"union-testnet": {
"chain_type": "union",
"enabled": true,
"keyring": {
"name": "cosmos-testnet",
"keys": [
{
"type": "raw",
"name": "alice",
"key": "0xaa820fa947...b10a7d6f"
}
]
},
"ws_url": "ws://localhost:26657/websocket",
"prover_endpoints": ["http://localhost:9999"],
"grpc_url": "http://localhost:9090",
"gas_config": {
"gas_price": "1.0",
"gas_denom": "muno",
"gas_multiplier": "1.1",
"max_gas": 400000
}
},
"cosmos-testnet": {
"chain_type": "cosmos",
"enabled": true,
"keyring": {
"name": "cosmos-testnet",
"keys": [
{
"type": "raw",
"name": "alice",
"key": "0xaa820fa947...b10a7d6f"
}
]
},
"gas_config": {
"gas_price": "1.0",
"gas_denom": "stake",
"gas_multiplier": "1.1",
"max_gas": 400000
},
"ws_url": "ws://localhost:26957/websocket",
"grpc_url": "http://localhost:9390"
}
},
"voyager": {
"num_workers": 4,
"laddr": "0.0.0.0:7717",
"queue": {
"type": "pg-queue",
"database_url": "postgres://user:[email protected]:5432/default",
"max_connections": 20,
"min_connections": 20,
"idle_timeout": null,
"max_lifetime": null
}
}
}
We now need to change the configuration parameters for our chain accordingly. voyager
needs an account with funds to send transactions.
You need to supply your private key to voyager
. Let’s first export it, then add it to the config.
$NODE_BIN keys export $KEY_NAME --unarmored-hex --unsafe
The following command puts the private key in the config. Be aware that the key should be 0x
prefixed.
cat <<< $(jq '.chain."cosmos-testnet".keyring.keys[0].key = "0x$PRIVATE_KEY"' minimal-config.json) > minimal-config.json
We also need to specify the $WS_URL
(websocket), $GRPC_URL
, and the denom $DENOM
for our network:
cat <<< $(jq '.chain."cosmos-testnet".ws_url = "$WS_URL" | .chain."cosmos-testnet".grpc_url = "$GRPC_URL" | .chain."cosmos-testnet".gas_config.gas_denom = "$DENOM"' minimal-config.json) > minimal-config.json
You should change the max_gas
, gas_multiplier
, and gas_price
according to your chain’s configuration.
The final thing about the configuration is to set up the union
account.
If you do not already have one, you could follow this guide.
Let’s set our union
private key too:
cat <<< $(jq '.chain."union-testnet".keyring.keys[0].key = "0x$UNION_PRIVATE_KEY"' minimal-config.json) > minimal-config.json
Starting Voyager
Voyager manages database migrations internally. Run the following command on startup to set up the database. This command is idempotent and can always be safely run.
voyager -c minimal-config.json run-migrations
Next, we need to start voyager. We recommend daemonizing this or running it under systemd for production usage.
voyager -c minimal-config.json relay
Now in a new window, instruct the voyager to monitor Union and your chain.
voyager -c ./minimal-config.json init-fetch union-testnet --enqueue
voyager -c ./minimal-config.json init-fetch cosmos-testnet --enqueue
Creating the Clients
We first need to create a light client on both chains to track each other’s consensus:
voyager -c ./minimal-config.json \
handshake \
union-testnet\
cosmos-testnet \
--create-clients \
--client-a-config null \
--client-b-config '{"checksum":"0x$COMETBLS_CLIENT_CHECKSUM"}' \
--enqueue
As soon as you run the command, you will see that voyager
will create the clients. You should see similar messages in your logs:
2024-06-25T13:32:40.195484Z INFO processing item{id=7303}:relay:handle{chain_id=osmosis-devnet-1}:using signer{keyring=osmosis-devnet key_name=alice address=osmo1jk9psyhvgkrt2cumz8eytll2244m2nnzhgejsf}: relay_message::chain::cosmos_sdk: cosmos tx tx_hash=0xb2290d735a024554f1b05a4e3cf20e4f21f940ee5b40a2e34392af481938d332 msgs=/ibc.core.client.v1.MsgCreateClient
And also the corresponding event:
2024-06-25T13:32:43.178552Z INFO processing item{id=7377}:relay:handle{chain_id=union-devnet-1}: relay_message::event: event=create_client height=1-541 tx_hash=0x215343a69bfbc6b2c7e367c0c4870a80a68ba7710a9812c8419fe890aff64ec4 client_id=07-tendermint-0 client_type=07-tendermint consensus_height=1-860
Opening the IBC Connection
Now we are going to open the IBC connection. Each chain has a single connection to another chain or rollup.
voyager -c ./minimal-config.json \
handshake \
union-testnet \
cosmos-testnet \
--open-connection \
--client-a $TENDERMINT_CLIENT_ID \
--client-b $COMETBLS_CLIENT_ID \
--connection-ordering unordered \
--enqueue
Again, you will see the transactions happening on voyager
’s logs. You can also try tracking ConnectionOpenInit
, ConnectionOpenTry
, ConnectionOpenAck
, and ConnectionOpenConfirm
transactions from the explorers.
You need to confirm that the connection is opened on both sides:
# Query the connection on Union
uniond query ibc connection end $UNION_CONNECTION_ID --node https://rpc.testnet-8.union.build:443
# Query the connection on your chain
$NODE_BIN query ibc connection end $YOUR_CONNECTION_ID --node $YOUR_RPC
Make sure that the state
is OPEN
on both ends before moving on to channel opening.
Opening the channel
Finally, we can start opening a channel between the ics20 transfer
module on your chain and the ucs01
module on Union
.
Note that the command below only requires the connection ID on Union
to be specified.
voyager -c ./minimal-config.json \
handshake \
union-testnet\
cosmos-testnet \
--open-channel \
--connection-a $UNION_CONNECTION_ID \
--port-a $UCS01_RELAY_PORT \
--port-b transfer \
--channel-version ics20-1 \
--channel-ordering unordered \
--enqueue
This time, the transactions to watch will be ChannelOpenInit
, ChannelOpenTry
, ChannelOpenAck
, and ChannelOpenConfirm
.
Make sure the state
of the channel is OPEN
on both ends:
# Query the connection on Union
uniond query ibc channel end $UCS01_PORT_ID $UNION_CHANNEL_ID --node https://rpc.testnet-8.union.build:443
# Query the connection on your chain
$NODE_BIN query ibc channel end transfer $YOUR_CHANNEL_ID --node $YOUR_RPC
Alternative Setup
voyager
is also capable of doing all of the above in a single command once:
voyager -c ./minimal-config.json \
handshake \
union-testnet\
cosmos-testnet \
--create-clients \
--open-connection \
--client-a-config null \
--client-b-config '{"checksum":"0x$COMETBLS_CLIENT_CHECKSUM"}' \
--connection-ordering unordered \
--open-channel \
--port-a $UCS01_RELAY_PORT \
--port-b transfer \
--channel-version ics20-1 \
--channel-ordering unordered \
--enqueue
Verify the Connection
Now that the previous steps are completed, you can start receiving and sending funds to any chain within the Union:
$COSMOS_BIN tx ibc-transfer transfer transfer channel-0 10000$DENOM \
--from $KEY \
--fees 500$DENOM