Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit 4cd23c9

Browse files
onchain-development anchor-cpi updated (#394)
* onchain anchor-cpi updated * minor refactor Co-authored-by: Mike MacCana <mike.maccana@gmail.com> * minor refactor Co-authored-by: Mike MacCana <mike.maccana@gmail.com> * minor refactor Co-authored-by: Mike MacCana <mike.maccana@gmail.com> * minor refactor --------- Co-authored-by: Mike MacCana <mike.maccana@gmail.com>
1 parent 158891d commit 4cd23c9

File tree

1 file changed

+60
-42
lines changed

1 file changed

+60
-42
lines changed

content/courses/onchain-development/anchor-cpi.md

+60-42
Original file line numberDiff line numberDiff line change
@@ -114,21 +114,20 @@ pub fn new_with_signer(
114114

115115
#### CPI accounts
116116

117-
One of the main things about `CpiContext` that simplifies cross-program
118-
invocations is that the `accounts` argument is a generic type that lets you pass
119-
in any object that adopts the `ToAccountMetas` and `ToAccountInfos<'info>`
120-
traits.
117+
One of the key features of `CpiContext` is that the `accounts` argument is
118+
generic, allowing you to pass in any object that implements the `ToAccountMetas`
119+
and `ToAccountInfos<'info>` traits.
121120

122-
These traits are added by the `#[derive(Accounts)]` attribute macro that you've
123-
used before when creating structs to represent instruction accounts. That means
124-
you can use similar structs with `CpiContext`.
121+
These traits are added by the `#[derive(Accounts)]` attribute macro you've used
122+
before, to specify the accounts required by your instruction handlers. You can
123+
use also use `#[derive(Accounts)]` structs with `CpiContext`.
125124

126125
This helps with code organization and type safety.
127126

128-
#### Invoke an instruction on another Anchor program
127+
#### Invoke an instruction handler on another Anchor program
129128

130-
When the program you're calling is an Anchor program with a published crate,
131-
Anchor can generate instruction builders and CPI helper functions for you.
129+
When calling another Anchor program with a published crate, Anchor can generate
130+
instruction builders and CPI helper functions for you.
132131

133132
Simply declare your program's dependency on the program you're calling in your
134133
program's `Cargo.toml` file as follows:
@@ -141,11 +140,11 @@ callee = { path = "../callee", features = ["cpi"]}
141140
By adding `features = ["cpi"]`, you enable the `cpi` feature and your program
142141
gains access to the `callee::cpi` module.
143142

144-
The `cpi` module exposes `callee`'s instructions as a Rust function that takes
145-
as arguments a `CpiContext` and any additional instruction data. These functions
146-
use the same format as the instruction functions in your Anchor programs, only
147-
with `CpiContext` instead of `Context`. The `cpi` module also exposes the
148-
accounts structs required for calling the instructions.
143+
The `cpi` module turns `callee`'s instructions into Rust functions. These
144+
functions take a `CpiContext` and any extra data needed for the instruction.
145+
They work just like the instruction functions in your Anchor programs, but use
146+
`CpiContext` instead of `Context`. The `cpi` module also provides the account
147+
structs needed for these instruction handler.
149148

150149
For example, if `callee` has the instruction `do_something` that requires the
151150
accounts defined in the `DoSomething` struct, you could invoke `do_something` as
@@ -212,24 +211,24 @@ possible options:
212211
similar pattern if you decide to use an accounts struct and `CpiContext` to
213212
organize and prepare your CPI.
214213
```rust
215-
pub fn mint_to<'a, 'b, 'c, 'info>(
216-
ctx: CpiContext<'a, 'b, 'c, 'info, MintTo<'info>>,
214+
pub fn mint_to<'info>(
215+
ctx: CpiContext<'_foo, '_bar, '_baz, 'info, MintTo<'info>>,
217216
amount: u64,
218217
) -> Result<()> {
219-
let ix = spl_token::instruction::mint_to(
218+
let instruction_handler = spl_token::instruction::mint_to(
220219
&spl_token::ID,
221220
ctx.accounts.mint.key,
222221
ctx.accounts.to.key,
223222
ctx.accounts.authority.key,
224223
&[],
225224
amount,
226225
)?;
227-
solana_program::program::invoke_signed(
228-
&ix,
226+
anchor_lang::solana_program::program::invoke_signed(
227+
&instruction_handler,
229228
&[
230-
ctx.accounts.to.clone(),
231-
ctx.accounts.mint.clone(),
232-
ctx.accounts.authority.clone(),
229+
ctx.accounts.to,
230+
ctx.accounts.mint,
231+
ctx.accounts.authority
233232
],
234233
ctx.signer_seeds,
235234
)
@@ -242,8 +241,8 @@ possible options:
242241
We're deep enough into Anchor at this point that it's important to know how to
243242
create custom errors.
244243

245-
Ultimately, all programs return the same error
246-
type: [`ProgramError`](https://docs.rs/solana-program/latest/solana_program/program_error/enum.ProgramError.html).
244+
Ultimately, all programs return the same error type: 
245+
[`ProgramError`](https://docs.rs/solana-program/latest/solana_program/program_error/enum.ProgramError.html).
247246
However, when writing a program using Anchor you can use `AnchorError` as an
248247
abstraction on top of `ProgramError`. This abstraction provides additional
249248
information when a program fails, including:
@@ -381,14 +380,14 @@ pub struct InitializeMint<'info> {
381380
bump,
382381
payer = user,
383382
mint::decimals = 6,
384-
mint::authority = mint,
383+
mint::authority = user,
385384
)]
386385
pub mint: Account<'info, Mint>,
387386
#[account(mut)]
388387
pub user: Signer<'info>,
389388
pub token_program: Program<'info, Token>,
390389
pub rent: Sysvar<'info, Rent>,
391-
pub system_program: Program<'info, System>
390+
pub system_program: Program<'info, System>,
392391
}
393392
```
394393

@@ -455,7 +454,7 @@ pub struct AddMovieReview<'info> {
455454
seeds=[title.as_bytes(), initializer.key().as_ref()],
456455
bump,
457456
payer = initializer,
458-
space = MovieAccountState::INIT_SPACE + title.len() + description.len()
457+
space = DISCRIMINATOR + MovieAccountState::INIT_SPACE
459458
)]
460459
pub movie_review: Account<'info, MovieAccountState>,
461460
#[account(mut)]
@@ -486,12 +485,6 @@ been initialized, it will be initialized as an associated token account for the
486485
specified mint and authority. Also, the payer for the costs related with the
487486
account initialization will be set under the constraint `payer`.
488487

489-
If you're unfamiliar with the `INIT_SPACE` constant used for the `movie_review`
490-
account space allocation, please refer to the
491-
[`solution-pdas`](https://github.com/solana-foundation/developer-content/blob/4c8eada3053061e66b907c9b49701b064544681d/content/courses/onchain-development/anchor-pdas.md?plain=1#L467)
492-
branch that is being used as our starting point. In there, we discuss the
493-
implementation of the `Space` trait and the `INIT_SPACE` constant.
494-
495488
Next, let’s update the `add_movie_review` instruction to do the following:
496489

497490
- Check that `rating` is valid. If it is not a valid rating, return the
@@ -520,15 +513,29 @@ use anchor_spl::associated_token::AssociatedToken;
520513
Next, update the `add_movie_review` function to:
521514

522515
```rust
523-
pub fn add_movie_review(ctx: Context<AddMovieReview>, title: String, description: String, rating: u8) -> Result<()> {
516+
pub fn add_movie_review(
517+
ctx: Context<AddMovieReview>,
518+
title: String,
519+
description: String,
520+
rating: u8
521+
) -> Result<()> {
524522
// We require that the rating is between 1 and 5
525-
require!(rating >= MIN_RATING && rating <= MAX_RATING, MovieReviewError::InvalidRating);
523+
require!(
524+
rating >= MIN_RATING && rating <= MAX_RATING,
525+
MovieReviewError::InvalidRating
526+
);
526527

527528
// We require that the title is not longer than 20 characters
528-
require!(title.len() <= MAX_TITLE_LENGTH, MovieReviewError::TitleTooLong);
529+
require!(
530+
title.len() <= MAX_TITLE_LENGTH,
531+
MovieReviewError::TitleTooLong
532+
);
529533

530534
// We require that the description is not longer than 50 characters
531-
require!(description.len() <= MAX_DESCRIPTION_LENGTH, MovieReviewError::DescriptionTooLong);
535+
require!(
536+
description.len() <= MAX_DESCRIPTION_LENGTH,
537+
MovieReviewError::DescriptionTooLong
538+
);
532539

533540
msg!("Movie review account created");
534541
msg!("Title: {}", title);
@@ -568,12 +575,23 @@ pub fn add_movie_review(ctx: Context<AddMovieReview>, title: String, description
568575
Here we are only adding the check that `rating` and `description` are valid.
569576

570577
```rust
571-
pub fn update_movie_review(ctx: Context<UpdateMovieReview>, title: String, description: String, rating: u8) -> Result<()> {
578+
pub fn update_movie_review(
579+
ctx: Context<UpdateMovieReview>,
580+
title: String,
581+
description: String,
582+
rating: u8
583+
) -> Result<()> {
572584
// We require that the rating is between 1 and 5
573-
require!(rating >= MIN_RATING && rating <= MAX_RATING, MovieReviewError::InvalidRating);
585+
require!(
586+
rating >= MIN_RATING && rating <= MAX_RATING,
587+
MovieReviewError::InvalidRating
588+
);
574589

575590
// We require that the description is not longer than 50 characters
576-
require!(description.len() <= MAX_DESCRIPTION_LENGTH, MovieReviewError::DescriptionTooLong);
591+
require!(
592+
description.len() <= MAX_DESCRIPTION_LENGTH,
593+
MovieReviewError::DescriptionTooLong
594+
);
577595

578596
msg!("Movie review account space reallocated");
579597
msg!("Title: {}", title);
@@ -682,7 +700,7 @@ After that, neither the test for `updateMovieReview` nor the test for
682700
683701
At this point, run `anchor test` and you should see the following output
684702
685-
```shell
703+
```bash
686704
anchor-movie-review-program
687705
Initializes the reward token (458ms)
688706
Movie review is added (410ms)

0 commit comments

Comments
 (0)