Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
On Ethereum, every state change is implicitly gated by msg.sender. On Solana, the signer set is explicit — a transaction names every signer, and programs check is_signer on the accounts they care about. This design produces the 'authority pattern': every account has an authority field (the pubkey allowed to act on it), and programs verify that the correct authority signed the current transaction. This is the bedrock of Solana access control. Forget the signer check and you have a catastrophic bug — this is the #1 cause of Solana hacks.
A token mint has a mint_authority. Only a transaction signed by that authority can mint. The SPL Token program verifies this on every call. If you build your own program with a similar pattern, you must emit the same check — Anchor's has_one = authority constraint does this for you, but you can also write it manually. Failing to check is how protocols lose $20M.
has_one = authority and changes authority: Signer to authority: AccountInfo. Deploy it. Show that a non-authority can drain the vault. Then fix it. Record the audit finding in a markdown note.has_one, signer, address, owner, constraint = expr. For each, write a one-line example. Understand what each guards against.Sysvar::Instructions sysvar — programs can introspect the transaction to verify the instruction context. Note when you'd use this (e.g., enforce a preceding instruction like a priority-fee payment).// Anchor program with authority pattern
use anchor_lang::prelude::*;
#[program]
pub mod vault {
use super::*;
pub fn withdraw(ctx: Context<Withdraw>, amount: u64) -> Result<()> {
// has_one = authority is checked by the Anchor macro BEFORE this runs
**ctx.accounts.vault.to_account_info().try_borrow_mut_lamports()? -= amount;
**ctx.accounts.recipient.to_account_info().try_borrow_mut_lamports()? += amount;
Ok(())
}
}
#[account]
pub struct Vault { pub authority: Pubkey, pub balance: u64 }
#[derive(Accounts)]
pub struct Withdraw<'info> {
#[account(mut, has_one = authority)]
pub vault: Account<'info, Vault>,
pub authority: Signer<'info>, // MUST be a signer
#[account(mut)] pub recipient: AccountInfo<'info>,
}
// If Anchor's has_one check is removed OR authority is not a Signer,
// ANYONE can drain the vault by passing the real authority's pubkey
// (without signing) plus their own recipient. This is the bug that drained
// multiple Solana protocols in 2022–2023.
cargo run