This tutorial covers how to call one program from another, a process known as cross-program-invocation (CPI).
To get started, clone the repo.
git clone https://github.com/project-serum/anchor
And change directories to the example.
cd anchor/examples/tutorial/basic-3
We start with the program that will be called by another program, the puppet.
<<< @/../examples/tutorial/basic-3/programs/puppet/src/lib.rs
If you've followed along the other tutorials, this should be straight forward. We have
a program with two instructions, initialize
, which does nothing other than the
initialization of the account (remember, the program transparently prepends a unique 8
byte discriminator the first time an account is used), and set_data
, which takes a previously
initialized account, and sets its data field.
Now, suppose we wanted to call set_data
from another program.
We define a new puppet-master
crate, which successfully executes the Puppet program's set_data
instruction via CPI.
<<< @/../examples/tutorial/basic-3/programs/puppet-master/src/lib.rs#core
Things to notice
CpiContext
object with the target instruction's accounts and program,
here SetData
and puppet_program
.cpi
module on the crate, here, puppet::cpi::set_data
.Accounts
struct has a new type, CpiAccount
, containing the target program's Puppet
account. Think of CpiAccount
exactly like ProgramAccount
, except used for accounts not
owned by the current program.::: tip
When using another Anchor program for CPI, make sure to specify the cpi
feature in your Cargo.toml
.
If you look at the Cargo.toml
for this example, you'll see
puppet = { path = "../puppet", features = ["cpi"] }
.
:::
Often it's useful for a program to sign instructions. For example, if a program controls a token
account and wants to send tokens to another account, it must sign. In Solana, this is done by specifying
"signer seeds" on CPI. To do this using the example above, simply change
CpiContext::new(cpi_accounts, cpi_program)
to
CpiContext::new_with_signer(cpi_accounts, cpi_program, signer_seeds)
.
For more background on signing with program derived addresses, see the official Solana documentation.
Solana currently has no way to return values from CPI, alas. However, you can approximate this by having the callee write return values to an account and the caller read that account to retrieve the return value. In future work, Anchor should do this transparently.
Now that you can have your programs call other programs, you should be able to access all the work being done by other developers in your own applications!
Up until now, we've treated programs on Solana as stateless. In the next tutorial we will learn how to add a global state to our program.