Custom rpcX Package Guide
Since the Rust compiler can target WebAssembly directly, developing a custom rpcX package is almost the same as building a normal Rust library.
1. Ensure that all dependencies are installed
Install Rust and rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Add WebAssembly as a rust target:
rustup target add wasm32-wasip1
Install Cargo Component:
cargo install cargo-component --locked
Install Solana CLI:
sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"
Install the atlas-rpcx
CLI:
The following command will install the latest version of the Atlas rpcX CLI tool. Currently only Linux and MacOS are supported.
sh -c "$(curl -sSfL release.atlas.xyz/rpcx-cli/install)"
Fund an Atlas keypair
If you don't have a funded Atlas keypair, you can generate a fresh keypair with the following command:
solana-keygen new --outfile <KEYPAIR_PATH>
You can then use the testnet faucet to request some Atlas testnet ETH.
2. Clone the rpcX-hello-world
repo
git clone https://github.com/Ellipsis-Labs/rpcx-hello-world.git
This repo contains a simple example Atlas program that creates an account and writes a message to the account data. It also contains an rpcX package that can be used to parse the account data into human-readable format as well as a script to interact with the deployed program.
3. Initialize the program
First, we'll need a program and some data to parse with our rpcX package.
Build the example program
Inside the cloned project directory, run:
cd program
cargo build-sbf
The output program .so
binary will be located in the target/deploy
folder of your working cargo project directory.
Deploy the example program
solana program deploy --use-rpc <PATH_TO_PROGRAM_BINARY> --url "https://testnet.atlas.xyz"
Execute a transaction using the example program:
cd ../script
cargo run -- --program-id <PROGRAM_ID>
You may also provide the arguments --payer <PAYER_KEYPAIR_PATH>
and --rpc-url <RPC_URL>
to use a non-default payer or RPC URL.
Expected output
Transaction confirmed: <TX_SIGNATURE>
Now check the Atlas Explorer.
After finding the transaction by searching for the <TX_SIGNATURE>
, take a look at the account that was created.
Notice that the account data is encoded bytes and not in a human-readable format.
Make note of the account pubkey as we will use it to test the rpcX package.
4. Build an rpcX package
Now that we have a deployed program and some on-chain data, let's use an rpcX package to parse it.
Build the package:
cargo component build --release --manifest-path rpcx-package/Cargo.toml
Confirm that there is a .wasm
file in the rpcx-package/target/wasm32-wasip1/release
folder.
5. Locally test the rpcX package
Before deploying the package, we can use the atlas-rpcx
CLI to test locally.
The simulate
subcommand can be used to locally test an rpcX package using data from various environments.
simulate
covers all possible rpcX methods (including subscriptions) but if you're following this guide without using the example repo,
make sure that your package implements the required interfaces for the RPC methods you're interested in.
For this guide we will only implement and test the basic Program Parser interface.
Let's look at the account that was created:
atlas-rpcx simulate parsed-account <PATH_TO_RPCX_PACKAGE> <ACCOUNT_PUBKEY> --url https://testnet.atlas.xyz
Here, <ACCOUNT_PUBKEY>
should be the created account pubkey that we pulled from the explorer at the end of step 3.
Notice how we can read the account data that was encoded on the explorer!
Expected output
atlas-rpcx simulate parsed-account ./rpcx-package/target/wasm32-wasip1/release/rpcx_package.wasm CrsT8ezH5EPDBWYfBzanScgXkMf1tc6MK1VFkCTX5zNU --url https://testnet.atlas.xyz
{
"name": "MessageAccount",
"discriminator": null,
"value": {
"message": "Hello World"
}
}
We can also look at the parsed transaction:
atlas-rpcx simulate parsed-transaction <SIGNATURE> -l <PROGRAM_ID> <PATH_TO_RPCX_PACKAGE> --url <RPC_URL>
Expected output
atlas-rpcx simulate parsed-transaction 65enbZtco7q3m2nvNW17q9qPeZgpfGFfh6gJko6JQmBA35nKaoZdTohLwVVsr4hvNmLMgvfgFzNdgXxzorrAmNff -l 9DgBTXe8Wm2ecE44YJPvUYh3PHdcXFzWVnsF6Nf9zgr7 ./rpcx-package/target/wasm32-wasip1/release/rpcx_package.wasm --url https://testnet.atlas.xyz
{
"slot": 13097146,
"blockTime": 1739293699431,
"signature": "65enbZtco7q3m2nvNW17q9qPeZgpfGFfh6gJko6JQmBA35nKaoZdTohLwVVsr4hvNmLMgvfgFzNdgXxzorrAmNff",
"error": null,
"logMessages": [
"Program Ebd9HzPtkWj4WU1FN7bbQcH6HsW2rndcxYLRuBx2uYr invoke [1]",
"Program 11111111111111111111111111111111 invoke [2]",
"Allocated an account with 967440 lamports, but only 278 were needed",
"Program 11111111111111111111111111111111 success",
"Program Ebd9HzPtkWj4WU1FN7bbQcH6HsW2rndcxYLRuBx2uYr consumed 1671 of 199944 compute units",
"Program Ebd9HzPtkWj4WU1FN7bbQcH6HsW2rndcxYLRuBx2uYr success"
],
"returnData": null,
"fee": 100,
"feePayer": "59CqKsFPE8dQfgNkCyd3FTsQ6U84Bv55jJmgr1RKua8G",
"computeUnitsConsumed": 1727,
"preBalances": [
166801068,
0,
0,
328
],
"postBalances": [
165833528,
967440,
0,
328
],
"stateRoot": "FsrqCy5KqvqdDb5N4m9doz8USS4JaKSDJixa6dWBTkYk",
"signatures": [
"65enbZtco7q3m2nvNW17q9qPeZgpfGFfh6gJko6JQmBA35nKaoZdTohLwVVsr4hvNmLMgvfgFzNdgXxzorrAmNff",
"67as2TV7jvpRmEbVXnt9mAERqe6h6c2iwUdb4ZjryufPgqYK26nmtfujGb2j4YcAryDS4Z3bKAcezH4oaoNKDgG5"
],
"accounts": [
{
"pubkey": "59CqKsFPE8dQfgNkCyd3FTsQ6U84Bv55jJmgr1RKua8G",
"isSigner": true,
"isWritable": true
},
{
"pubkey": "5zAWKV2EHuzJeWGPXXgJ5nTebLsQhdpwjntMkEMt5fpv",
"isSigner": true,
"isWritable": true
},
{
"pubkey": "11111111111111111111111111111111",
"isSigner": false,
"isWritable": false
},
{
"pubkey": "Ebd9HzPtkWj4WU1FN7bbQcH6HsW2rndcxYLRuBx2uYr",
"isSigner": false,
"isWritable": false
}
],
"instructions": [
{
"programId": "Ebd9HzPtkWj4WU1FN7bbQcH6HsW2rndcxYLRuBx2uYr",
"ixRawData": "",
"parseErr": "Failed to find Wasm component or IDL for program_id Ebd9HzPtkWj4WU1FN7bbQcH6HsW2rndcxYLRuBx2uYr",
"accounts": [
{
"pubkey": "59CqKsFPE8dQfgNkCyd3FTsQ6U84Bv55jJmgr1RKua8G",
"isSigner": true,
"isWritable": true
},
{
"pubkey": "5zAWKV2EHuzJeWGPXXgJ5nTebLsQhdpwjntMkEMt5fpv",
"isSigner": true,
"isWritable": true
},
{
"pubkey": "11111111111111111111111111111111",
"isSigner": false,
"isWritable": false
}
],
"stackHeight": "0",
"tokenAccountChanges": [],
"programLogs": [],
"events": []
},
{
"programId": "11111111111111111111111111111111",
"ixRawData": "AAAAABDDDgAAAAAACwAAAAAAAAADe7L0i8HKqYbEUEhNNle45S2wo+wRGtPg80UzvudBXw==",
"programName": "System",
"ixName": "CreateAccount",
"ixData": {
"lamports": "967440",
"owner": "Ebd9HzPtkWj4WU1FN7bbQcH6HsW2rndcxYLRuBx2uYr",
"space": "11"
},
"ixDiscriminator": 0,
"accounts": [
{
"name": "Payer",
"pubkey": "59CqKsFPE8dQfgNkCyd3FTsQ6U84Bv55jJmgr1RKua8G",
"isSigner": true,
"isWritable": true
},
{
"name": "NewAccount",
"pubkey": "5zAWKV2EHuzJeWGPXXgJ5nTebLsQhdpwjntMkEMt5fpv",
"isSigner": true,
"isWritable": true
}
],
"stackHeight": "0.0",
"tokenAccountChanges": [],
"programLogs": [],
"events": []
}
],
"preTokenBalances": [],
"postTokenBalances": [],
"parseTransactionErrors": null
}
6. Deploy the rpcX package:
Details about deployment
- Deploying an rpcX package requires "registering" the package on-chain.
The
registry
subcommand of theatlas-rpcx
CLI handles any actions that interact with the package registry, including deploying or searching for packages. - Because packages are stored on-chain, deployments cost gwei/lamports. rpcX package deployments are typically much cheaper than program deploys. Make sure you have enough funds and deploy wisely!
- Packages are uniquely identified by a string with length ≤ 32. If a package implements the Program Parser interface and a program id is used as the identifier during deployment, the Atlas Explorer will use the deployed package to parse data from the program. Only the deployer of a program is allowed to register the rpcX package using the program id.
Run the following command to deploy an rpcX package:
atlas-rpcx registry deploy <PROGRAM_ID> <PATH_TO_RPCX_PACKAGE> --url <RPC_URL>
7. Read parsed data from on-chain
Now that the data has been deployed, check the Atlas explorer to see the parsed data/transactions!
The query
subcommand of the atlas-rpcx
CLI can also be used to query http rpcX endpoints.
atlas-rpcx query parsed-account <PROGRAM_ID> <ACCOUNT_PUBKEY> --url <RPC_URL>
8. Additional Details
This guide just scratches the surface of what you can do with rpcX. There are a variety of data access patterns that rpcX supports that were not covered here. For an example of a more advanced package, see the rpcX price feed demo.
The atlas-rpcx
CLI also supports pubsub subscriptions.
Run atlas-rpcx pubsub --help
for more information about pubsub, or atlas-rpcx --help
for more information the CLI.