- 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 -- -y
sh -c "$(curl -sSfL https://release.solana.com/v1.17.31/install)"
Install and use the correct version
cargo install --git https://github.com/coral-xyz/anchor --tag v0.29.0 anchor-cli --locked
LZ_ENABLE_SOLANA_OFT_EXAMPLE=1 npx create-lz-oapp@latest
pnpm install
pnpm test
solana airdrop 5 -u devnet
We 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.
cp .env.example .env
In the .env
just created, set SOLANA_PRIVATE_KEY
to your private key value in base58 format. Since the locally stored keypair is in an integer array format, we'd need to encode it into base58 first.
You can run the npx hardhat lz:solana:base-58
to output your private key in base58 format. Optionally, pass in a value for the --keypair-file
flag if you want to use the keypair other than the default at ~/.config/solana/id.json
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 programId
keypair files by running:
morpheus:setup:anchor:keys
--force
flag that overwrites the existing keys with the ones you generate.
Run
anchor keys list
to view the generated programId (public keys). The output should look something like this:
oft: <OFT_PROGRAM_ID>
Copy the OFT's programId and go into lib.rs. Note the following snippet:
declare_id!(Pubkey::new_from_array(program_id_from_env!(
"OFT_ID",
"9UovNrJD8pQyBLheeHNayuG1wJSEAoxkmM14vw5gcsTT"
)));
Replace 9UovNrJD8pQyBLheeHNayuG1wJSEAoxkmM14vw5gcsTT
with the programId that you have copied.
Ensure you have Docker running before running the build command.
pnpm hardhat morpheus:anchor:build:verifiable
ℹ️ The majority of the SOL required to deploy your program will be for rent (specifically, for the minimum balance of SOL required for rent-exemption), which is calculated based on the amount of bytes the program or account uses. Programs typically require more rent than PDAs as more bytes are required to store the program's executable code.
In our case, the OFT Program's rent accounts for roughly 99% of the SOL needed during deployment, while the other accounts' rent, OFT Store, Mint, Mint Authority Multisig and Escrow make up for only a fraction of the SOL needed.
You can preview how much SOL would be needed for the program account. Note that the total SOL required would to be slightly higher than just this, to account for the other accounts that need to be created.
pnpm hardhat morpheus:deploy:anchor:rent
You should see an output such as
Rent-exempt minimum: 3.87415872 SOL
ℹ️ LayerZero's default deployment path for Solana OFTs require you to deploy your own OFT program as this means you own the Upgrade Authority and don't rely on LayerZero to manage that authority for you. Read this to understand more no why this is important.
pnpm hardhat morpheus:anchor:deploy:verifiable
ℹ️ 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
priorityFee
.
This section only applies if you are unable to land your deployment transaction due to network congestion.
ℹ️ Priority Fees are Solana's mechanism to allow transactions to be prioritized during periods of network congestion. When the network is busy, transactions without priority fees might never be processed. It is then necessary to include priority fees, or wait until the network is less congested. Priority fees are calculated as follows: priorityFee = compute budget * compute unit price
. We can make use of priority fees by attaching the --with-compute-unit-price
flag to our solana program deploy
command. Note that the flag takes in a value in micro lamports, where 1 micro lamport = 0.000001 lamport.
View instructions
Because building requires Solana CLI version `1.17.31`, but priority fees are only supported in version `1.18`, we will need to switch Solana CLI versions temporarily.sh -c "$(curl -sSfL https://release.solana.com/v1.18.26/install)"
You can run refer QuickNode's Solana Priority Fee Tracker to know what value you'd need to pass into the --with-compute-unit-price
flag.
ℹ️ The average is calculated from getting the prioritization fees across recent blocks, but some blocks may have 0
as the prioritization fee. averageFeeExcludingZeros
ignores blocks with 0
prioritization fees.
Now let's rerun the deploy command, but with the compute unit price flag.
npx hardhat setup:anchor:deploy:verifiable
1.17.31
and Anchor version 0.29.0
sh -c "$(curl -sSfL https://release.solana.com/v1.17.31/install)"
ℹ️ For OFT and OFT Mint-and-Burn Adapter, the SPL token's Mint Authority is set to the Mint Authority Multisig, which always has the OFT Store as a signer. The multisig is fixed to needing 1 of N signatures.
ℹ️ For OFT and OFT Mint-And-Burn Adapter, you have the option to specify additional signers through the --additional-minters
flag. If you choose not to, you must pass in --only-oft-store true
, which means only the OFT Store will be a signer for the _Mint Authority Multisig*.
--only-oft-store
, you will not be able to add in other signers/minters or update the Mint Authority, and the Freeze Authority will be immediately renounced. The token Mint Authority will be fixed Mint Authority Multisig address while the Freeze Authority will be set to None.
pnpm hardhat morpheus:oft:solana:create
--additional-minters
flag to add a CSV of additional minter addresses to the Mint Authority Multisig. If you do not want to, you must specify --only-oft-store true
.
ℹ️ You can also specify --amount <AMOUNT>
to have the OFT minted to your deployer address upon token creation.
Check layerzero.config.ts
address
for the solana contract object. Do not specify addresses for the EVM chain contract objects. Under the hood, we use hardhat-deploy
to retrieve the contract addresses of the deployed EVM chain contracts. You will run into an error if you specify address
for an EVM chain contract object.
pnpm hardhat lz:deploy # follow the prompts
Note: If you are on testnet, consider using MyOFTMock
to allow test token minting. If you do use MyOFTMock
, make sure to update the sepoliaContract.contractName
in layerzero.config.ts to MyOFTMock
.
npx hardhat lz:oapp:init:solana --oapp-config layerzero.config.ts --solana-secret-key <SECRET_KEY> --solana-program-id <PROGRAM_ID>
ℹ️ <SECRET_KEY>
should also be in base58 format.
npx hardhat lz:oapp:wire --oapp-config layerzero.config.ts --solana-secret-key <PRIVATE_KEY> --solana-program-id <PROGRAM_ID>
With a squads multisig, you can simply append the --multisigKey
flag to the end of the above command.
This is only relevant for OFT. If you opted to include the --amount
flag in the create step, that means you already have minted some Solana OFT and you can skip this section.
ℹ️ This is only possible if you specified your deployer address as part of the --additional-minters
flag when creating the Solana OFT. If you had chosen --only-oft-store true
, you will not be able to mint your OFT on Solana.
First, you need to create the Associated Token Account for your address.
spl-token create-account <TOKEN_MINT>
Then, you can mint. Remember this is in local decimals, so with local decimals of 9, you would need to pass in --amount 1000000000
to mint 1 OFT.
spl-token mint <TOKEN_MINT> <AMOUNT> --multisig-signer ~/.config/solana/id.json --owner <MINT_AUTHORITY>
ℹ️ ~/.config/solana/id.json
assumes that you will use the keypair in the default location. To verify if this path applies to you, run solana config get
and not the keypair path value.
ℹ️ You can get the <MINT_AUTHORITY>
address from deployments/solana-testnet/OFT.json.
npx hardhat morpheus:oft:solana:send --amount <AMOUNT> --to <EVM_ADDRESS>
npx hardhat --network sepolia-testnet send --amount <AMOUNT> --to <TO>
ℹ️ If you encounter an error such as No Contract deployed with name
, ensure that the tokenName
in the task defined in tasks/evm/send.ts
matches the deployed contract name.