|
@@ -1,10 +1,42 @@
|
|
|
|
+//! Anchor ⚓ is a framework for Solana's Sealevel runtime providing several
|
|
|
|
+//! convenient developer tools.
|
|
|
|
+//!
|
|
|
|
+//! - Rust eDSL for writing safe, secure, and high level Solana programs
|
|
|
|
+//! - [IDL](https://en.wikipedia.org/wiki/Interface_description_language) specification
|
|
|
|
+//! - TypeScript package for generating clients from IDL
|
|
|
|
+//! - CLI and workspace management for developing complete applications
|
|
|
|
+//!
|
|
|
|
+//! If you're familiar with developing in Ethereum's
|
|
|
|
+//! [Solidity](https://docs.soliditylang.org/en/v0.7.4/),
|
|
|
|
+//! [Truffle](https://www.trufflesuite.com/),
|
|
|
|
+//! [web3.js](https://github.com/ethereum/web3.js) or Parity's
|
|
|
|
+//! [Ink!](https://github.com/paritytech/ink), then the experience will be
|
|
|
|
+//! familiar. Although the syntax and semantics are targeted at Solana, the high
|
|
|
|
+//! level workflow of writing RPC request handlers, emitting an IDL, and
|
|
|
|
+//! generating clients from IDL is the same.
|
|
|
|
+//!
|
|
|
|
+//! For detailed tutorials and examples on how to use Anchor, see the guided
|
|
|
|
+//! [tutorials](https://project-serum.github.io/anchor) or examples in the GitHub
|
|
|
|
+//! [repository](https://github.com/project-serum/anchor).
|
|
|
|
+//!
|
|
|
|
+//! Presented here are the Rust primitives for building on Solana.
|
|
|
|
+
|
|
use solana_sdk::account_info::AccountInfo;
|
|
use solana_sdk::account_info::AccountInfo;
|
|
use solana_sdk::instruction::AccountMeta;
|
|
use solana_sdk::instruction::AccountMeta;
|
|
use solana_sdk::program_error::ProgramError;
|
|
use solana_sdk::program_error::ProgramError;
|
|
use solana_sdk::pubkey::Pubkey;
|
|
use solana_sdk::pubkey::Pubkey;
|
|
use std::io::Write;
|
|
use std::io::Write;
|
|
-use std::ops::{Deref, DerefMut};
|
|
|
|
|
|
|
|
|
|
+mod account_info;
|
|
|
|
+mod context;
|
|
|
|
+mod cpi_account;
|
|
|
|
+mod program_account;
|
|
|
|
+mod sysvar;
|
|
|
|
+
|
|
|
|
+pub use crate::context::{Context, CpiContext};
|
|
|
|
+pub use crate::cpi_account::CpiAccount;
|
|
|
|
+pub use crate::program_account::ProgramAccount;
|
|
|
|
+pub use crate::sysvar::Sysvar;
|
|
pub use anchor_attribute_access_control::access_control;
|
|
pub use anchor_attribute_access_control::access_control;
|
|
pub use anchor_attribute_account::account;
|
|
pub use anchor_attribute_account::account;
|
|
pub use anchor_attribute_program::program;
|
|
pub use anchor_attribute_program::program;
|
|
@@ -12,7 +44,7 @@ pub use anchor_derive_accounts::Accounts;
|
|
/// Default serialization format for anchor instructions and accounts.
|
|
/// Default serialization format for anchor instructions and accounts.
|
|
pub use borsh::{BorshDeserialize as AnchorDeserialize, BorshSerialize as AnchorSerialize};
|
|
pub use borsh::{BorshDeserialize as AnchorDeserialize, BorshSerialize as AnchorSerialize};
|
|
|
|
|
|
-/// A data structure of Solana accounts that can be deserialized from the input
|
|
|
|
|
|
+/// A data structure of accounts that can be deserialized from the input
|
|
/// of a Solana program. Due to the freewheeling nature of the accounts array,
|
|
/// of a Solana program. Due to the freewheeling nature of the accounts array,
|
|
/// implementations of this trait should perform any and all constraint checks
|
|
/// implementations of this trait should perform any and all constraint checks
|
|
/// (in addition to any done within `AccountDeserialize`) on accounts to ensure
|
|
/// (in addition to any done within `AccountDeserialize`) on accounts to ensure
|
|
@@ -21,7 +53,18 @@ pub use borsh::{BorshDeserialize as AnchorDeserialize, BorshSerialize as AnchorS
|
|
pub trait Accounts<'info>: ToAccountMetas + ToAccountInfos<'info> + Sized {
|
|
pub trait Accounts<'info>: ToAccountMetas + ToAccountInfos<'info> + Sized {
|
|
fn try_accounts(
|
|
fn try_accounts(
|
|
program_id: &Pubkey,
|
|
program_id: &Pubkey,
|
|
- from: &mut &[AccountInfo<'info>],
|
|
|
|
|
|
+ accounts: &mut &[AccountInfo<'info>],
|
|
|
|
+ ) -> Result<Self, ProgramError>;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/// A data structure of accounts providing a one time deserialization upon
|
|
|
|
+/// initialization, i.e., when the data array for a given account is zeroed.
|
|
|
|
+/// For all subsequent deserializations, it's expected that
|
|
|
|
+/// [Accounts](trait.Accounts.html) is used.
|
|
|
|
+pub trait AccountsInit<'info>: ToAccountMetas + ToAccountInfos<'info> + Sized {
|
|
|
|
+ fn try_accounts_init(
|
|
|
|
+ program_id: &Pubkey,
|
|
|
|
+ accounts: &mut &[AccountInfo<'info>],
|
|
) -> Result<Self, ProgramError>;
|
|
) -> Result<Self, ProgramError>;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -67,177 +110,13 @@ pub trait AccountDeserialize: Sized {
|
|
fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self, ProgramError>;
|
|
fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self, ProgramError>;
|
|
}
|
|
}
|
|
|
|
|
|
-/// Container for a serializable `account`. Use this to reference any account
|
|
|
|
-/// owned by the currently executing program.
|
|
|
|
-#[derive(Clone)]
|
|
|
|
-pub struct ProgramAccount<'a, T: AccountSerialize + AccountDeserialize + Clone> {
|
|
|
|
- info: AccountInfo<'a>,
|
|
|
|
- account: T,
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'a, T: AccountSerialize + AccountDeserialize + Clone> ProgramAccount<'a, T> {
|
|
|
|
- pub fn new(info: AccountInfo<'a>, account: T) -> ProgramAccount<'a, T> {
|
|
|
|
- Self { info, account }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// Deserializes the given `info` into a `ProgramAccount`.
|
|
|
|
- pub fn try_from(info: &AccountInfo<'a>) -> Result<ProgramAccount<'a, T>, ProgramError> {
|
|
|
|
- let mut data: &[u8] = &info.try_borrow_data()?;
|
|
|
|
- Ok(ProgramAccount::new(
|
|
|
|
- info.clone(),
|
|
|
|
- T::try_deserialize(&mut data)?,
|
|
|
|
- ))
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// Deserializes the zero-initialized `info` into a `ProgramAccount` without
|
|
|
|
- /// checking the account type. This should only be used upon program account
|
|
|
|
- /// initialization (since the entire account data array is zeroed and thus
|
|
|
|
- /// no account type is set).
|
|
|
|
- pub fn try_from_init(info: &AccountInfo<'a>) -> Result<ProgramAccount<'a, T>, ProgramError> {
|
|
|
|
- let mut data: &[u8] = &info.try_borrow_data()?;
|
|
|
|
-
|
|
|
|
- // The discriminator should be zero, since we're initializing.
|
|
|
|
- let mut disc_bytes = [0u8; 8];
|
|
|
|
- disc_bytes.copy_from_slice(&data[..8]);
|
|
|
|
- let discriminator = u64::from_le_bytes(disc_bytes);
|
|
|
|
- if discriminator != 0 {
|
|
|
|
- return Err(ProgramError::InvalidAccountData);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Ok(ProgramAccount::new(
|
|
|
|
- info.clone(),
|
|
|
|
- T::try_deserialize_unchecked(&mut data)?,
|
|
|
|
- ))
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountInfo<'info>
|
|
|
|
- for ProgramAccount<'info, T>
|
|
|
|
-{
|
|
|
|
- fn to_account_info(&self) -> AccountInfo<'info> {
|
|
|
|
- self.info.clone()
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'a, T: AccountSerialize + AccountDeserialize + Clone> Deref for ProgramAccount<'a, T> {
|
|
|
|
- type Target = T;
|
|
|
|
-
|
|
|
|
- fn deref(&self) -> &Self::Target {
|
|
|
|
- &self.account
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'a, T: AccountSerialize + AccountDeserialize + Clone> DerefMut for ProgramAccount<'a, T> {
|
|
|
|
- fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
- &mut self.account
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// Similar to `ProgramAccount`, but to reference any account *not* owned by
|
|
|
|
-/// the current program.
|
|
|
|
-pub type CpiAccount<'a, T> = ProgramAccount<'a, T>;
|
|
|
|
-
|
|
|
|
-/// Container for a Solana sysvar.
|
|
|
|
-pub struct Sysvar<'info, T: solana_sdk::sysvar::Sysvar> {
|
|
|
|
- info: AccountInfo<'info>,
|
|
|
|
- account: T,
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'info, T: solana_sdk::sysvar::Sysvar> Sysvar<'info, T> {
|
|
|
|
- pub fn from_account_info(
|
|
|
|
- acc_info: &AccountInfo<'info>,
|
|
|
|
- ) -> Result<Sysvar<'info, T>, ProgramError> {
|
|
|
|
- Ok(Sysvar {
|
|
|
|
- info: acc_info.clone(),
|
|
|
|
- account: T::from_account_info(&acc_info)?,
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'a, T: solana_sdk::sysvar::Sysvar> Deref for Sysvar<'a, T> {
|
|
|
|
- type Target = T;
|
|
|
|
-
|
|
|
|
- fn deref(&self) -> &Self::Target {
|
|
|
|
- &self.account
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'a, T: solana_sdk::sysvar::Sysvar> DerefMut for Sysvar<'a, T> {
|
|
|
|
- fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
- &mut self.account
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'info, T: solana_sdk::sysvar::Sysvar> ToAccountInfo<'info> for Sysvar<'info, T> {
|
|
|
|
- fn to_account_info(&self) -> AccountInfo<'info> {
|
|
|
|
- self.info.clone()
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'info> ToAccountInfo<'info> for AccountInfo<'info> {
|
|
|
|
- fn to_account_info(&self) -> AccountInfo<'info> {
|
|
|
|
- self.clone()
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// Provides non-argument inputs to the program.
|
|
|
|
-pub struct Context<'a, 'b, 'c, 'info, T> {
|
|
|
|
- /// Deserialized accounts.
|
|
|
|
- pub accounts: &'a mut T,
|
|
|
|
- /// Currently executing program id.
|
|
|
|
- pub program_id: &'b Pubkey,
|
|
|
|
- /// Remaining accounts given but not deserialized or validated.
|
|
|
|
- pub remaining_accounts: &'c [AccountInfo<'info>],
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'a, 'b, 'c, 'info, T> Context<'a, 'b, 'c, 'info, T> {
|
|
|
|
- pub fn new(
|
|
|
|
- accounts: &'a mut T,
|
|
|
|
- program_id: &'b Pubkey,
|
|
|
|
- remaining_accounts: &'c [AccountInfo<'info>],
|
|
|
|
- ) -> Self {
|
|
|
|
- Self {
|
|
|
|
- accounts,
|
|
|
|
- program_id,
|
|
|
|
- remaining_accounts,
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// Context speciying non-argument inputs for cross-program-invocations.
|
|
|
|
-pub struct CpiContext<'a, 'b, 'c, 'info, T: Accounts<'info>> {
|
|
|
|
- pub accounts: T,
|
|
|
|
- pub program: AccountInfo<'info>,
|
|
|
|
- pub signer_seeds: &'a [&'b [&'c [u8]]],
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'a, 'b, 'c, 'info, T: Accounts<'info>> CpiContext<'a, 'b, 'c, 'info, T> {
|
|
|
|
- pub fn new(program: AccountInfo<'info>, accounts: T) -> Self {
|
|
|
|
- Self {
|
|
|
|
- accounts,
|
|
|
|
- program,
|
|
|
|
- signer_seeds: &[],
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- pub fn new_with_signer(
|
|
|
|
- accounts: T,
|
|
|
|
- program: AccountInfo<'info>,
|
|
|
|
- signer_seeds: &'a [&'b [&'c [u8]]],
|
|
|
|
- ) -> Self {
|
|
|
|
- Self {
|
|
|
|
- accounts,
|
|
|
|
- program,
|
|
|
|
- signer_seeds,
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
|
|
+/// The prelude contains all commonly used components of the crate.
|
|
|
|
+/// All programs should include it via `anchor_lang::prelude::*;`.
|
|
pub mod prelude {
|
|
pub mod prelude {
|
|
pub use super::{
|
|
pub use super::{
|
|
access_control, account, program, AccountDeserialize, AccountSerialize, Accounts,
|
|
access_control, account, program, AccountDeserialize, AccountSerialize, Accounts,
|
|
- AnchorDeserialize, AnchorSerialize, Context, CpiAccount, CpiContext, ProgramAccount,
|
|
|
|
- Sysvar, ToAccountInfo, ToAccountInfos, ToAccountMetas,
|
|
|
|
|
|
+ AccountsInit, AnchorDeserialize, AnchorSerialize, Context, CpiAccount, CpiContext,
|
|
|
|
+ ProgramAccount, Sysvar, ToAccountInfo, ToAccountInfos, ToAccountMetas,
|
|
};
|
|
};
|
|
|
|
|
|
pub use solana_program::msg;
|
|
pub use solana_program::msg;
|