Multichain Relayer and Gas Station example
In this article you'll learn how to run end-to-end tests on the entire Multichain Relayer system. You'll find two tests available: an integrated test and a manual test. The integration test is the best way to check that all multichain gas relayer systems are working well together. Manual testing is a good way to debug issues if any individual part of the system isn't working.
Requirements
Before you start testing, set up your local environment and install the Relayer server, the Event indexer and NEAR CLI.
For this tutorial, you need to have installed:
- Python >=3.10
- Rust
- Multichain Relayer Server
- Gas Station Event indexer
- NEAR CLI RS: Make sure to configure it with the correct network and account.
Integration test
This test is the best way to verify that all multichain gas relayer systems are working well together.
In separate terminals, you need to run the following tools:
- Multichain Relayer server, with a valid
config.toml
configuration file - Gas Station indexer, with correct values in
config.toml
- Python integration test script
Multichain Relayer server
The main function of this server is interfacing with foreign chain RPCs sending both pre-signed funding transactions to cover gas and the actual pre-signed transaction once the funding is done.
To run the Multichain Relayer Server:
- Configure the Multichain Relayer by editing the
config.toml
file - Start the multichain relayer server:
cargo run
Find the Multichain Relayer server source code in this GitHub repository.
Gas Station Event indexer
The event indexer is a Python script that picks up events emitted from the gas station contract used for generating signed foreign chain transactions and calls the multichain relayer /send_funding_and_user_signed_txns
endpoint locally.
To run the Gas Station indexer:
-
Ensure you have the Multichain Relayer Server running on
localhost:3030
-
Create the virtual environment and install requirements:
make install
-
Update the
config.toml
configuration file with appropriate values (usecanhazgas.near
for mainnet)network = "testnet"
# gas station contract account id
contract_id = "canhazgas.testnet" -
Populate the environment file containing AWS credentials for reading from Near Lake
cp .env.sample .env
-
Run the indexer script:
make run
Find the Gas Station Event indexer source code in this GitHub repository.
Run integration test
To run the integration test, switch to the multichain-relayer-server
repository folder and execute the Python script:
python3 integration_tests/integration_test.py
You can use the optional --verbose
flag to print subprocess output:
python3 integration_tests/integration_test.py --verbose
Manual testing
This section offers instructions on how to manually perform end-to-end tests on the entire multichain relayer system including the gas station contract, indexer, and relayer server.
This test is a good way to debug issues if any individual part of the system isn't working.
Test setup
The following instructions are only need to be called once to initialize the account on the Gas Station. Make sure to replace the <account_id>
(string) with the account you want to initialize and <token_id>
(integer) with the token id of the NFT you minted in step 2:
- Registration / Storage Deposit:
near contract call-function as-transaction v2.nft.kagi.testnet \
storage_deposit json-args {} prepaid-gas '100.0 Tgas' attached-deposit '1 NEAR' \
sign-as <account_id>.testnet network-config testnet sign-with-keychain send - Mint NFT - make sure to save the token id from the logs of this call
near contract call-function as-transaction v2.nft.kagi.testnet \
mint json-args {} prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' \
sign-as <account_id>.testnet network-config testnet sign-with-keychain send - Approve the Gas Station for this Token (use or use
canhazgas.near
for mainnet):near contract call-function as-transaction v2.nft.kagi.testnet \
ckt_approve_call json-args '{"token_id":"<token_id>","account_id":"canhazgas.testnet","msg":""}' \
prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' \
sign-as <account_id>.testnet network-config testnet sign-with-keychain send
Manual test steps
- Get paymaster info for the chain you want to send to from the gas station contract, then optionally manually set nonces (use
canhazgas.near
for mainnet):which returns something like:near contract call-function as-transaction canhazgas.testnet \
get_paymasters json-args '{"chain_id": "<chain_id>"}' \
prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' \
sign-as <account_id>.testnet network-config testnet sign-with-keychain send--- Result -------------------------
[
{
"foreign_address": "0x98c6C99176911AD4E7fc7413eDF09956B2D7F0F8",
"minimum_available_balance": "99886599999948172000",
"nonce": 28,
"token_id": "1"
}
]
------------------------------------- You may need to manually set the nonce for the paymaster to be able to send the transaction (use
canhazgas.near
for mainnet):
near contract call-function as-transaction canhazgas.testnet \
get_paymasters json-args '{"chain_id": "<chain_id>"}' \
prepaid-gas '100.000 Tgas' \
attached-deposit '0 NEAR' \
sign-as <account_id>.testnet \
network-config testnet \
sign-with-keychain send - You may need to manually set the nonce for the paymaster to be able to send the transaction (use
- Update the transaction details of the EVM transaction you want to send in
generate_eip1559_rlp_hex()
test intests/tests.rs
then run the script and save the RLP hex string output.- If that doesn't work, try running
generate_rlp_evm_txn.py
- If that doesn't work, try running
Python and Rust output different hex RLP encoded transactions.
- If you're using Rust, use
generate_eip1559_rlp_hex()
. - If you're using Python, use
generate_rlp_encoded_transaction(is_eip_1559=true)
- Python
- Rust
Loading...
Loading...
-
Ensure the Multichain Relayer server is configured correctly (
config.toml
) and running:cargo run
-
Ensure the Gas Station indexer is running locally with the correct values in the
config.toml
file -
Construct the signed transaction using the near-cli-rs. The receiver account ID should be the gas station contract. You will need 2 actions if you want the gas station to cover your gas cost on the foreign chain:
- 1 action to send the NEAR equivalent
- 1 function call to the gas station.
You should transfer the amount of
NEAR
that's needed to cover gas both on NEAR and on the foreign chain. You also need to paste in the RLP generated hex for the EVM transaction you want on the other chain generated in step 1. When it asks you to send or display, choose send. For example (usecanhazgas.near
for mainnet):near contract call-function as-transaction canhazgas.testnet \
create_transaction json-args '{"transaction_rlp_hex":"eb80851bf08eb000825208947b965bdb7f0464843572eb2b8c17bdf27b720b14872386f26fc1000080808080","use_paymaster":true,"token_id":"<token_id>"}' \
prepaid-gas '100.000 TeraGas' attached-deposit '<deposit_in_near> NEAR' \
sign-as <account_id>.testnet \
network-config testnet sign-with-keychain sendwhich returns something like:
--- Result -------------------------
{
"id": "29",
"pending_signature_count": 2
}
------------------------------------ -
Get the
"id"
from the receipts from the result in the previous step, and use that to callsign_next
twice (usecanhazgas.near
for mainnet):near contract call-function as-transaction canhazgas.testnet \
sign_next json-args '{"id":"<id>"}' \
prepaid-gas '300.0 Tgas' \
attached-deposit '0 NEAR' \
sign-as <account_id>.testnet \
network-config testnet \
sign-with-keychain sendNote: this step will be updated soon, as support for yield/resume calls is implemented on MPC contract.
-
Watch the output of the gas station event indexer to see the transactions being emitted by the gas station contract.
-
Watch the output of the multichain relayer server to see the transactions being sent to the foreign chain.
Optional for testing purposes
Instead of creating a signed transaction and calling the gas station contract to sign it, you can get the recently signed transactions by calling the contract while replacing the blockheight
with a more recent block height (use canhazgas.near
for mainnet):
near contract call-function as-read-only canhazgas.testnet list_signed_transaction_sequences_after json-args '{"block_height":"157111000"}' network-config testnet now
This will return something like the output below. Take an individual entry in the list of JSONs and send that as the payload of a POST
request to the /send_funding_and_user_signed_txns
endpoint:
[
{
"created_by_account_id": "b807806adcb73f6aecb5ed98bb8bd7bbe7bbf8ed342596ab700ef6b050abc4c3",
"foreign_chain_id": "97",
"signed_transactions": [
"0x02f873610385174876e80085174876e80082520894c89663ac6d169bc3e2e0a99d9fe96f2e82bcc307870eebe0b40e800080c080a0712d44ba4cd7567764231e21f054c5e7d008055222820e9d5ba148ede48755f7a06e8b812d37047593fc51fce7254ea7aef89927cada729bc903cd36fa9659dce4",
"0x02f873618085174876e80085174876e80082520894ef55a8bdf4498ea0af88bc54efb29608bb25e130872aa1efb94e000080c080a017d7024fe9e32ad8da1181729fac7e6a45311c47bf59f2b5a8b5e9fe002c0617a04ad725b362cf12c6e066c5b0b7ecbbf08f5e4d0a240337e6ddc8076f0528e3e5"
]
},
...
{
"created_by_account_id": "b807806adcb73f6aecb5ed98bb8bd7bbe7bbf8ed342596ab700ef6b050abc4c3",
"foreign_chain_id": "97",
"signed_transactions": [
"0x02f873610185174876e80085174876e80082520894c89663ac6d169bc3e2e0a99d9fe96f2e82bcc307870eebe0b40e800080c001a0ff19fe769246de8483b986e5aeaa3360bfb74f238e2a91ea353dac9aad9e24a0a020485dcd2c64172b9bc058b7813646dafbf2f27d51aae388b074e514fdb6de05",
"0x02f873618085174876e80085174876e80082520894ef55a8bdf4498ea0af88bc54efb29608bb25e130872e2f6e5e14800080c001a0dac67c383e8de3211f3c5d360cc2e9a21d160711fc3f80113ac525169317e2eca07140a1d0d1528b6eaf9fac4bb1bd44c1c4f63bb956292b0211a0dad1748e2eea"
]
}
]