Homepage | Docs | Developers
Core Concepts | Message Execution Options | Endpoint Addresses
Template project for getting started with LayerZero's OApp development for Solana <> EVM.
This is a simple cross-chain string-passing OApp example involving EVM and Solana.
For a more thorough walkthrough of how a Solana OApp works, refer to Solana OApp Reference in our docs. The reference details the accounts that are required, which will help you identify modifications needed to support your specific use case.
- Rust
v1.75.0 - Anchor
v0.29 - Solana CLI
v1.17.31 - Docker
- Node.js
We recommend using pnpm as a package manager (but you can of course use a package manager of your choice).
Docker is required to build using anchor. We highly recommend that you use the most up-to-date Docker version to avoid any issues with anchor builds.
0.29 and solana version 1.17.31 specifically to compile the build artifacts. Using higher Anchor and Solana versions can introduce unexpected issues during compilation. See the following issues in Anchor's repo: 1, 2. After compiling the correct build artifacts, you can change the Solana version to higher versions.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -ysh -c "$(curl -sSfL https://release.anza.xyz/v1.17.31/install)"If this is your first time installing the Solana CLI, run the following to generate a keypair at the default keypair path (~/.config/solana/id.json):
solana-keygen newInstall and use the correct version
cargo install --git https://github.com/coral-xyz/anchor --tag v0.29.0 anchor-cli --lockedLZ_ENABLE_SOLANA_OAPP_EXAMPLE=1 npx create-lz-oapp@latestThe CLI will also automatically run pnpm install for you.
Make sure you select the OApp (Solana) example from the dropdown:
✔ Where do you want to start your project? … ./example
? Which example would you like to use as a starting point? › - Use arrow-keys. Return to submit.
OApp
OFT
OFTAdapter
ONFT721
OFT (Solana)
❯ OApp (Solana)To compile the Solidity OApp contract and build the Solana OApp program, run:
pnpm compilesolana airdrop 5 -u devnetWe recommend that you request 5 devnet SOL, which should be sufficient for this walkthrough. For the example here, we will be using Solana Devnet. If you hit rate limits, you can also use the official Solana faucet.
Copy the example .env file:
cp .env.example .envand fill up the values.
Choose your preferred means of setting up your EVM deployer wallet/account:
MNEMONIC="test test test test test test test test test test test junk"
or...
PRIVATE_KEY="0xabc...def"
By default, the scripts will use the keypair at the default location ~/.config/solana/id.json. If you want to use this keypair, there is no need to set any environment variable. There will, however, be a prompt when running certain commands to confirm that you want to use the default keypair.
If you wish to use a different keypair, then you can set either of the following in the .env:
-
SOLANA_PRIVATE_KEY- this can be either in base58 string format (i.e. when imported from a wallet) or the Uint8 Array in string format (all in one line, e.g.[1,1,...1]). -
SOLANA_KEYPAIR_PATH- the location to the keypair file that you want to use.
Also set the RPC_URL_SOLANA_TESTNET value. Note that while the naming used here is TESTNET, it refers to the Solana Devnet. We use TESTNET to keep it consistent with the existing EVM testnets.
Create the MyOApp programId keypair file by running:
solana-keygen new -o target/deploy/my_oapp-keypair.json
anchor keys syncRun
anchor keys list
to view the generated programId (public keys). The output should look something like this:
my_oapp: <OAPP_PROGRAM_ID>
Copy the OApp's program ID, which you will use in the build step.
Ensure you have Docker running before running the build command.
anchor build -v -e MYOAPP_ID=<OAPP_PROGRAM_ID>Where <OAPP_PROGRAM_ID> is replaced with your OApp Program ID copied from the previous step.
While for building, we must use Solana v1.17.31, for deploying, we will be using v1.18.26 as it provides an improved program deployment experience (i.e. ability to attach priority fees and also exact-sized on-chain program length which prevents needing to provide 2x the rent as in v1.17.31).
First, we switch to Solana v1.18.26 (remember to switch back to v1.17.31 later)
sh -c "$(curl -sSfL https://release.anza.xyz/v1.18.26/install)"solana program deploy --program-id target/deploy/my_oapp-keypair.json target/verifiable/my_oapp.so -u devnet --with-compute-unit-price <COMPUTE_UNIT_PRICE_IN_MICRO_LAMPORTS>ℹ️ --with-compute-unit-price takes in the microlamport value applied per compute unit. This is how we can attach a priority fee to our deployment.
ℹ️ the -u flag specifies the RPC URL that should be used. The options are mainnet-beta, devnet, testnet, localhost, which also have their respective shorthands: -um, -ud, -ut, -ul
1.17.31 and Anchor version 0.29.0
sh -c "$(curl -sSfL https://release.anza.xyz/v1.17.31/install)"Solana programs require accounts to be initialized before state can be written.
Run the following to init the OApp store account:
npx hardhat lz:oapp:solana:create --eid 40168 --program-id <PROGRAM_ID>ℹ️ The address of this account (and not the OApp program ID) is what will be used as the OApp address in the context of cross-chain messaging.
ℹ️ The example init_store method being called by this task can be called by anyone, and can only be called once. Modify it accordingly if for your use case it should be access controlled or callable multiple times based on some param value.
To deploy your Solidity contracts to your desired EVM blockchain(s), run the following command in your project's folder:
npx hardhat lz:deployYou will be presented with a list of networks that have been defined via your hardhat.config.ts. Select the ones you want to deploy to.
More information about available CLI arguments can be found using the --help flag:
npx hardhat lz:deploy --helpWiring will apply the settings configured in the LZ config file. By default, this file is named layerzero.config.ts.
This step is required only for the Solana OApp and is again required due to the need to init accounts explicitly.
The task initializes the OApp's SendConfig and ReceiveConfig Accounts.
You need to do this only when initializing the OApp for the first time. However, if a new pathway involving Solana is added, you need to run this again as the SendConfig and ReceiveConfig accounts are required per peer.
npx hardhat lz:oapp:solana:init-config --oapp-config layerzero.config.tsRun the wire task
Run the following to wire the pathways specified in your layerzero.config.ts
npx hardhat lz:oapp:wire --oapp-config layerzero.config.tsWith a squads multisig, you can simply append the --multisig-key flag to the end of the above command.
With your OApps wired, you can now send a message.
Send from Solana Devnet (40168) to Arbitrum Sepolia (40231) :
npx hardhat lz:oapp:send --from-eid 40168 --dst-eid 40231 --message "Hello from Solana Devnet"Send from Arbitrum Sepolia (40231) to Solana Devnet (40168) :
npx hardhat --network arbitrum-sepolia lz:oapp:send --from-eid 40231 --dst-eid 40168 --message "Hello from Arbitrum Sepolia"ℹ️ For the list of supported chains and their endpoint ID's refer to the Deployed Endpoints page.
Congratulations, you have now successfully set up an EVM <> Solana OApp.
The test command will execute the hardhat and forge tests:
pnpm testJoin our community! | Follow us on X (formerly Twitter)