Ensure you have the following before deploying your application to Mainnet:
- The program ELF file - typically the result of an
anchor buildorcargo-build-sbfthat ends in.so - The program keypair - A JSON file containing an array of integers
In this section, we will describe where to find these assets and how to prepare them.
Preparing your ELF file
The ELF file contains the compiled bytecode, memory layout information, and metadata required for the Solana virtual machine (SVM) to understand how to load and run your program. The ELF file is created when your source code is compiled.
To create your ELF file, you can run the following command for Anchor:
anchor build
or the following for other frameworks:
cargo build-sbf
You can then find your ELF file in a directory like
target/deploy/<PROGRAM_NAME>.so.
Your program is ready when the ELF file is compiled to sBPFv3. To check your program, you can run the following command on Linux:
readelf -h target/deploy/<PROGRAM_NAME>.so | grep Flags:
And the following commands on macOS:
# brew install llvm$(brew --prefix llvm)/bin/llvm-readelf -h target/deploy/<PROGRAM_NAME>.so | grep Flags:
If you see output like the following, your program is ready:
Flags: 0x3
If not, follow the migration guide linked here.
Preparing your program address
Your program address is the program ID you will use to invoke your program instructions. You can either 1) use the program keypair generated during the build, 2) grind a new keypair whose address starts with a custom prefix, or 3) derive an account address from a base address and seed. The first two options produce a keypair that can sign for the program account. An account created with a seed does not have its own private key; the base account controls it.
Use the generated keypair
By default, anchor build and cargo build-sbf place the program keypair at:
target/deploy/<PROGRAM_NAME>-keypair.json
Back up this file before cleaning the build directory. Anyone with access to the keypair can sign as the program account, so do not commit it to source control.
Grind a keypair with a custom prefix
Use vanity to search for an
Ed25519 keypair whose public key starts with a specific base58 prefix. Install
the CPU version from crates.io:
cargo install vanity
The project also provides CUDA, Metal, and OpenCL builds for GPU-accelerated
searches. See the vanity installation instructions for the requirements of
each backend.
vanity grind-keypair --pattern Acme...
When it finds a match, vanity prints the public key, the private seed in hex,
and a Solana-compatible keypair JSON array. Save the JSON file in a safe
location, then confirm that it contains the expected public key:
solana-keygen pubkey path/to/keypair.json
Treat the command output and the saved JSON file as private key material.
Create an account with a seed
For a faster search, vanity grind searches seed strings for
CreateAccountWithSeed instead of generating Ed25519 keypairs. Provide the
public key of the base account that will authorize creation, the account owner,
and the prefix to search for. For an upgradeable program account, use the
upgradeable BPF loader as the owner:
vanity grind \--base <BASE_ACCOUNT_PUBKEY> \--owner BPFLoaderUpgradeab1e11111111111111111111111 \--pattern Acme...
The result includes the derived address and a seed string. Verify them before creating the account:
vanity verify \--base <BASE_ACCOUNT_PUBKEY> \--owner BPFLoaderUpgradeab1e11111111111111111111111 \--seed <SEED>
Use the same base address, seed, and owner to derive the address with
Pubkey::create_with_seed, then submit a System Program
create_account_with_seed instruction. The base account and funding account
must sign the transaction. Because the derived account has no standalone
keypair, this option requires an account-creation and deployment flow that uses
the base account rather than a program keypair file.
Update the program address in your source
After choosing a keypair or seeded account, use its public address as the program ID everywhere the project declares it. If the source still contains the old address, clients can send instructions to the wrong program and runtime ID checks can fail.
In an Anchor workspace, update both the program entry in the root Anchor.toml
and the declare_id! invocation in programs/<PROGRAM_NAME>/src/lib.rs. The
key under [programs.<CLUSTER>] is the program's workspace name. Update every
cluster table where you intend to use the new address; the example below updates
Mainnet.
In Anchor.toml:
[programs.mainnet]-my_program = "<OLD_PROGRAM_ID>"+my_program = "<NEW_PROGRAM_ID>"
In programs/<your_program>/lib.rs:
-declare_id!("<OLD_PROGRAM_ID>");+declare_id!("<NEW_PROGRAM_ID>");
Pinocchio does not use Anchor.toml. Update the declare_id! invocation in the
program crate's src/lib.rs. Current Pinocchio projects import the macro from
pinocchio::address.
Quasar also declares the address in the onchain program crate's src/lib.rs and
does not use Anchor.toml. The declare_id! macro is available through
quasar_lang::prelude::*.
Rebuild the program and regenerate any IDL or client artifacts after changing the address. Also search deployment scripts, tests, and application configuration for the old program ID and replace any hardcoded references.
Is this page helpful?