The Program Module
The program module is where you define your business logic. You do so by writing functions which can be called by clients or other programs. You've already seen one example of such a function, the set_data
function from the previous section.
#[program]
mod hello_anchor {
use super::*;
pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
if ctx.accounts.token_account.amount > 0 {
ctx.accounts.my_account.data = data;
}
Ok(())
}
}
Context
Each endpoint function takes a Context
type as its first argument. Through this context argument it can access the accounts (ctx.accounts
), the program id (ctx.program_id
) of the executing program, and the remaining accounts (ctx.remaining_accounts
). remaining_accounts
is a vector that contains all accounts that were passed into the instruction but are not declared in the Accounts
struct. This is useful when you want your function to handle a variable amount of accounts, e.g. when initializing a game with a variable number of players.
Instruction Data
If your function requires instruction data, you can add it by adding arguments to the function after the context argument. Anchor will then automatically deserialize the instruction data into the arguments. You can have as many as you like. You can even pass in your own types as long as you use#[derive(AnchorDeserialize)]
on them or implement AnchorDeserialize
for them yourself. Here's an example with a custom type used as an instruction data arg:
#[program]
mod hello_anchor {
use super::*;
pub fn set_data(ctx: Context<SetData>, data: Data) -> Result<()> {
ctx.accounts.my_account.data = data.data;
ctx.accounts.my_account.age = data.age;
Ok(())
}
}
#[account]
#[derive(Default)]
pub struct MyAccount {
pub data: u64,
pub age: u8
}
#[derive(AnchorSerialize, AnchorDeserialize, Eq, PartialEq, Clone, Copy, Debug)]
pub struct Data {
pub data: u64,
pub age: u8
}
Conveniently, #[account]
implements Anchor(De)Serialize
for MyAccount
, so the example above can be simplified.
#[program]
mod hello_anchor {
use super::*;
pub fn set_data(ctx: Context<SetData>, data: MyAccount) -> Result<()> {
ctx.accounts.my_account.set_inner(data);
Ok(())
}
}
#[account]
#[derive(Default)]
pub struct MyAccount {
pub data: u64,
pub age: u8
}