# CORE 5 ## Section 1 ### 5.1.1 Local Anchor Setup (explore) Oh boy, I hope you're excited, we're jumping into Anchor finally. Your life is about to get a lot simpler -- not easier, just simpler relative to native Solana development. In order to build, test, and deploy Solana programs from your machine, you'll need to install quite a few things. Let's get your local setup all sorted out. The Anchor install page, linked below, will lead you through their set up. You will need Rust and Yarn installed first, so please do that if you don't have those on your machine. **Setup on Windows (with Linux)** Install WSL (Windows Subsystem for Linux): https://docs.microsoft.com/en-us/windows/wsl/install Install Ubuntu https://apps.microsoft.com/store/detail/ubuntu-2004/9N6SVWS3RX71?hl=en-us&gl=us **Setup on both macOS and Windows** Install Rust https://www.rust-lang.org/tools/install Install Solana CLI https://docs.solana.com/cli/install-solana-cli-tools Install Yarn https://yarnpkg.com/getting-started/install Install Anchor https://www.anchor-lang.com/docs/installation Assuming you're all set, let's look at some of the Anchor CLI commands. `anchor init <project-name>` will do the initial set up, once all done, open it up in your favorite code editor. Let's have a look at the basic file structure. There's an empty `app` directory, this is where you can put your application front-end. The `migrations` directory starts off with a `deploy.ts` script, this will help with migrations, but we're likely not going to deal with this much over the next set of lessons. The `programs` directory is where the source code of your program will be housed. In there under `/src/lib.rs` you'll find some Rust code, which should look quite different from what we've been working on so far. You won't find an entrypoint, Anchor defines it for us. You'll notice attributes used on virtually everything, that's because there's a lot of boilerplate code in native Solana that Anchor is abstracting away from us, through the use of macros! The `test` directory is for JavaScript tests. The `Anchor.toml` file is where you can make modifications to your configuration. We will cover more of this later, a couple of note are the cluster provider and wallet that's being used, they can all be changed right here. Back to the CLI commands. `anchor build` -- this will take a bit of time the first time you run it, it should show you a similar output as when running `cargo build-bpf`, with a deploy command in the terminal. Fortunately, instead of pasting that long command, you can also just run `anchor deploy`. That won't quite work yet, for two reasons. First, in the `lib.rs` file from before, there's a `declare_id!` macro, which has a default value in it, you'll notice it's the same value every time you start a new anchor program. So, get your acual program's ID by running `anchor keys list`, then paste that value in -- this program ID was generated after running the build command. It also needs to be pasted into the `Anchor.toml` file. The build also generated an idl (/target/idl/[project-name>.json]), which is a JSON declaration of what our program actually does, which is not a whole lot right now. It also generates a typescript idl (/target/types/[project-name].ts) with types we can use in Typescript. The second problem we need to address, the default is for the program to deploy to the localhost. We can either spin up a local validator, or hop into `Anchor.toml` and change the cluster to devnet. Check to see if you have enough SOL, or just airdrop a couple to yourself, then run `anchor deploy`. You should hopefully have a "Deploy success" message with a program ID in the terminal. Change back to the localnet now so we can run a test, which automatically sets up a local validator for the duration of the test. That's about it for the setup, in the next lesson, we'll hop into the code. ### 5.1.2 Intro to Anchor (explore) Let's jump into Anchor! The Anchor framework organizes a program into distinct sections that separate the instruction logic from account validation and security checks, and as mentioned previously, it abstracts away some of the tedious tasks and boilerplate, making our whole process a lot faster. It also does basic security checks, but is far from comprehensive, so you'll have to do your own security checks as well. Here's a very lean file, let's go through each of the sections. ``` rust // use this import to gain access to common anchor features use anchor_lang::prelude::*; // Program on-chain address declare_id!("2EKFZUwMrNdo8YLRHn3CyZa98zp6WH7Zpg16qYGU7htD"); // Instruction logic #[program] mod program_module_name { use super::*; pub fn instruction_one(ctx: Context<InstructionAccounts>, instruction_data: u64) -> Result(<>) { ctx.accounts.account_name.data = instruction_data; Ok(()) } } // Validate incoming accounts for instructions #[derive(Accounts)] pub struct InstructionAccounts<'info> { #[accounts(init, payer = user, space = 8 + 8 )] pub account_name: Account<'info, AccountStruct>, #[accounts(mut)] pub user: Signer<'info>, pub system_program: Program<'info, System> } // Define custom program account type #[account] pub struct AccountStruct { data: u64 } ``` You'll notice each section starts with a macro or attribute, they all help expand the code you're writing. `declare_id!` is used to specify the on-chain address of the program. Remember, you can get this with `anchor keys list` after you build your program for the first time. The `#[program]` attribute defines the module that contains all the program instructions. You'll notice it starts with `mod`. Inside of it is where you implement the logic for your instructions. You'll create a public function for every instruction that your program supports. The account validation and security checks are separate from your program logic. Every instruction will take two arguments, a context and instruction data. Instead of passing in the program id, accounts and instructions, which are now abstracted, you'll simply have these two parameters. Context is what gets us to the account, whose data we want to set to our newly passed in argument. Briefly, let's cover what `Context` is. ``` rust pub struct Context<'a, 'b, 'c, 'info, T> { /// Currently executing program ID pub program_id: &'a Pubkey, /// Deserialized accounts pub accounts: &'b mut T, /// Remaining accounts given, but not deserialized or validated /// Be very careful when using this directly. pub remaining_accounts: &'c [AccountInfo<'info>], /// Bumps seeds found during constraint validation. /// This is provided as a convenience so that handlers /// don't have to recalculate bump seeds or /// pass them in as arguments. pub bumps: BTreeMap<String, u8> } ``` We haven't talked much about "lifetimes" in Rust, the `'a, 'b, 'c, 'info`. The lifetime of Context is tied to every one of its properties that is denoted with a lifetime. It is basically saying, do not deallocate or dereference Context before all the other properties go away. It ensures there is no dangling references. We don't need to worry about truly understanding these right now, it really won't impact much of what we'll be doing. The thing that matters is the `T`, it is a generic, and it is a placeholder for a type. It indicates that Context will have a type inside of it, and that type can be one of many things, which will be decided at runtime. In this instances, it's a generic for the type of accounts. We will later define an accounts struct, that defines what are the accounts that come into this instruction, so that at the beginning of the instruction logic, we don't have to iterate over all of the accounts. It is another great abstraction of Anchor. As you can see, Context also has the program ID, a set of remaining accounts (hopefully you won't have to use this anytime soon), and finally the bump seeds it found during validating accounts, a convenience so handles don't have to recalculate the bump seeds. Back to the original code, let's have a gander at the `#[derive(Accounts)]` section, which is related to the Context type, so at runtime, the accounts type is 'T', but it is of type `InstructionAccounts`, meaning we now have access to the three accounts in `InstructionAccounts`. The derive will extract from the account list, the three fields (account name, user, system program), and it checks that the accounts passed into the instruction actually match this, or it will fail the instruction. If any accounts fail the security checks or validation, the instruction fails long before it attemps to run the logic. As for the account validation, Anchor provides a list of account types that can used in your account validation struct. You'll notice that `account_name` is of type `Account`, which is basucally a wrapper around `AccountInfo` (see below), which we have used before in the native development. It's a wrapper that verifies the owner of this account is your program. ``` rust pub struct AccountInfo<'a> { pub key: &'a Pubkey, pub is_signer: bool, pub is_writable: bool, pub lamports: Rc<RefCell<&'a mut u64>>, pub data: Rc<RefCell<&'a mut [u8]>>, pub owner: &'a Pubkey, pub executable: bool, pub rent_epoch: u64, } ``` In addition to checking its owner, it deserializes the account it finds into the AccountStruct type. Next, the Signer checks to make sure user is the account that has to the sign the instruction, or it will fail. Finally, Program checks that the account info is a program, and that it's the right program, and whether it is executable. We can also check the accounts against any additional constraints, which are above each field with the `#[account]` attribute, with a comma separated list in the paranthesis. For the first one, `#[accounts(init, payer = user, space = 8 + 8 )]`, init creates the account via a CPI to the system program, so all the boilerplate we used in the past, for creating an account, this...just...does it!!! Next it says, the payer of this account must be user, and it declares how much space we need. The first '8' is a discriminator that Anchor provides, and the second '8' is for the bytes required for the AccountStruct type. Finally, for the user account, there's a 'mut' attribute, it designates the account as mutable. Since the user will be paying for this, since it's balance will change, it needs to be mutable. Finally of note, the `#[account]` type implements quite a few traits. ``` #[account] generates trait implementations for the following traits: AccountSerialize AccountDeserialize AnchorSerialize AnchorDeserialize Clone Discriminator Owner ``` One last note, the discriminator (the 8 bytes of space mentioned above), is something we impleneted manually, but Anchor does it automatically by deriving from the first 8 bytes of the SHA-256 of the account struct name. That's about it, that's the structure of how Anchor programs are built. That was a bit dense, but it was necessary to set us up as we move forward and use Anchor. Let's go practice using it. ### 5.1.3 Intro to Anchor (build) Let's build our first Anchor program, a simple counter, entirely from scratch, run `anchor init anchor-counter` or call it whatever you like, and hop into your code editor. Open up the `lib.rs` file in (/programs/(program-name)/src/lib.rs). Our intent, a simple program, that has one account, that stores a count of how many times a certain instruction has been called. This means we'll need two instructions, one to initialize that account and its data structure, and a second instruction to increment the count. You'll notice there's a default instruction called `initialize`, and an account struct called `Initialize`. First, add the generic of `<'info>'` to the Initialize struct. Then, think about what accounts we need for our initilize instruction. Thinking back to our native Solana development, we would need the account we're creating, the user who's singing this, and the system program which is used to generate the account. Let's add an account of type Counter, a struct we'll build out shortly, another account called user of type Signer, and lastly the system program which is of type Program, from System. ``` rust #[derive(Accounts)] pub struct Initialize<'info> { pub counter: Account<'info, Counter>, pub user: Signer<'info>, pub system_program: Program<'info, System>, } ``` Let's create our Counter struct, so the red squiggly leaves us alone, we can leave out the details for now. ``` rust #[account] pub struct Counter { } ``` So, this struct under `#[derive(Accounts)]`, think of it as the account iterator that we put at the beginning of every instruction in native development. It is in a struct to make it easier to work with, so we're not trying to recall the order every time we work with it. Anchor will do some checks on our accounts, as an example, for Signer it checks to make sure the account is a signer, or fail otherwise, but we need to some of our own checks. The `counter` won't exist before we call the instruction, so we can add an attribute called `init`, which will create the account for us. The `init` trait requires two other fields, one called payer, so we add `payer = user`, another called space. Our space value is `8 + 8`, the first eight is for the discriminator, the second for the size of the actual account. Our Counter struct will have a 64-bit unsigned `u64` integer, so that's what the second eight is for. All this should look like this. ``` rust #[account(init, payer = user, space = 8 + 8)] pub counter: Account<'info, Counter>, ``` This will lead to a red squigly under the counter, saying the payer for the init constraint must be mutable, so we add that attribute to user. ``` rust #[derive(Accounts)] pub struct Initialize<'info> { #[account(init, payer = user, space = 8 + 8)] pub counter: Account<'info, Counter>, #[account(mut)] pub user: Signer<'info>, pub system_program: Program<'info, System>, } ``` Let's finish the Counter struct with a field called count. ``` rust #[account] pub struct Counter { pub count: u64, } ``` Let's hop back up to our initialize function and set our counter, and set a value of '0' for it. ``` rust pub fn initialize(ctx: Context<Initialize>) -> Result<()> { let counter = &mut ctx.accounts.counter; counter.count = 0; msg!("Counter account created. Current count: {}", counter.count); Ok(()) } ``` That's it for initialize, let's go ahead and build it with `anchor build` in the terminal. Reminder that this first build will take a minute, and generate a program ID for us which we have to paste into the `lib.rs` and `Anchor.toml` files. To get the ID, use `anchor keys list`. With that done, let's go write up a test. Open up (/tests/[project-name].ts), there'll be some default code for a test called "is initialized", we're going to add some of our own stuff. We'll initialize it with a specific counter account address. Outside of the test, generate a keypair. ``` typescript const counter = anchor.web3.Keypair.generate() ``` Then hop down to the tx line. ``` typescript const tx = await program.methods.initialize().rpc() ``` This whole line is calling initialize, but we can customize it to test what we want. It's basically a builder that knows what methods are available thanks to the /target/idl JSON file. We first add `.accounts({})` and specify the accounts that it needs. This ensures that the counter is created with the public key we just generated. `.accounts({ counter: counter.publicKey })` As this is not a PDA, the program cannot sign for it, so we need to add a new signer as well, which is the counter itself. ` .signers([counter]) ` It should look like this. ``` typescript const tx = await program.methods .initialize() .accounts({ counter: counter.publicKey }) .signers([counter]) .rpc() ``` Now we can get that account by fetching it with the public key. ``` typescript const account = await program.account["counter"].fetch(counter.publicKey) ``` Finally, we can do an assertion to check the count. ``` typescript expect(account.count.toNumber() === 0) ``` The whole of it will look like this. ``` typescript it("Is initialized!", async () => { // Add your test here. const tx = await program.methods .initialize() .accounts({ counter: counter.publicKey }) .signers([counter]) .rpc() const account = await program.account["counter"].fetch(counter.publicKey) expect(account.count.toNumber() === 0) }) ``` Let's run `anchor test`!! Hopefully it passes. 🤞 Alright, let's go build our increment instruction, and test it. Hope back over to the lib.rs file. Let's add a function under our initialize function. Creat a function called `increment` which will have a new type, that we'll create shortly. ``` rust pub fn increment(ctx: Context<>) -> Result<()> { Ok(()) } ``` It'll immedicately ask for a type, let's create that next with an account struct and it's required accounts to run this new instruction. Let's call this struct `Update`, and set the type of the above function to that. ``` rust #[derive(Accounts)] pub struct Update<'info> { } ``` Think about what accounts we need here. We don't need system program as we're not creating a new account, but we need coutner and user. We also no longer need the init attribute since the account has been created, but we do need the counter to be mutable as we're incrementing it. The final struct should look like this. ``` rust #[derive(Accounts)] pub struct Update<'info> { #[account(mut)] pub counter: Account<'info, Counter>, pub user: Signer<'info>, } ``` Then hop back up and add the instruction logic to our function. First create counter, but this time it needs to be mutable. Add in a message with the previous count. Then increment the counter, feel free to peek below on how to use checked math to ensure we don't have integer overflow. Finally, message the updated counter count. ``` rust pub fn increment(ctx: Context<Update>) -> Result<()> { let counter = &mut ctx.accounts.counter; msg!("Previous counter: {}", counter.count); counter.count = counter.count.checked_add(1).unwrap(); msg!("Counter incremented. Current count: {}", counter.count); Ok(()) } ``` That's it, pretty simple. Next, run `anchor build` so our new idl is generated, which will allow our `program.methods.` call to see which instructions are available. Let's go write another test to make sure it's working. Let's call it "Incremented the count", use the same tx logic but instead of calling initialize, call increment. For the accounts, we will need counter. Simiarly, create the account and then assert what should be the new value of the counter, which is hopefully '1'. ``` typescript it("Incremented the count", async () => { const tx = await program.methods .increment() .accounts({ counter: counter.publicKey }) .rpc() const account = await program.account["counter"].fetch(counter.publicKey) expect(account.count.toNumber() === 1) }) ``` Run anchor test, and it should pass. You'll notice, we didn't pass in user here, that's because when we set the provider, it automatically adds user as one of the accounts, and as one of the signers. We can change the default code to this, where we first capture the provider, then set it. So instead of letting Anchor just add user, we make it explicit. ``` typescript const provider = anchor.AnchorProvider.env() anchor.setProvider(provider) ``` Then the test code changes to this where we add the user to the accounts. ``` typescript it("Incremented the count", async () => { const tx = await program.methods .increment() .accounts({ counter: counter.publicKey, user: provider.wallet.publicKey }) .rpc() const account = await program.account["counter"].fetch(counter.publicKey) expect(account.count.toNumber() === 1) }) ``` Run the test again, it should work as well. That's it, you did it, your first anchor program. A bit of a mental shift, once it sets in, it's so much easier than writing native Solana code. ### 5.1.4 Getting Started with Anchor (ship) Alright, time to put your skills to work and build something independently. **Overview** Because we're starting with very simple programs, yours will look almost identical to what we just created. It's useful to try and get to the point where you can write it from scratch without referencing prior code, so try not to copy and paste here. **Action Steps** Write a new program that initializes a counter account and set the count field using the an instruction data argument passed into the instructionImplement initialize, increment and decrement instructionsFollowing what we did in the demo, write testes for each instructionUse anchor deploy to deploy your program. If you’re up for it, write a script like we’ve done previously to send transactions to your newly deployed program, then use Solana Explorer to look at the program logs. As always, get creative with these challenges and take them beyond the basic instructions if you want - and have fun! **Hints** Try to do this independently if you can! But if you get stuck, feel free to reference the solution-decrement branch of [this repository](https://github.com/Unboxed-Software/anchor-counter-program/tree/solution-decrement).