From cf9f4e8edfd152a8be9317d56d2a8df2edd6379f Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Fri, 10 Sep 2021 17:13:47 -0700 Subject: [PATCH 01/15] lang, spl: Program types --- lang/src/error.rs | 2 + lang/src/lib.rs | 13 +- lang/src/program.rs | 94 ++++++++++++++ lang/src/system_program.rs | 24 ++++ lang/syn/src/codegen/accounts/constraints.rs | 6 +- lang/syn/src/lib.rs | 14 +++ lang/syn/src/parser/accounts/mod.rs | 7 ++ spl/src/dex/cpi.rs | 29 +++++ spl/src/system.rs | 1 + spl/src/token.rs | 19 +++ tests/cfo/programs/cfo/src/lib.rs | 124 ++++++++----------- 11 files changed, 254 insertions(+), 79 deletions(-) create mode 100644 lang/src/program.rs create mode 100644 lang/src/system_program.rs create mode 100644 spl/src/system.rs diff --git a/lang/src/error.rs b/lang/src/error.rs index 7f7fea74f1..46fda08f95 100644 --- a/lang/src/error.rs +++ b/lang/src/error.rs @@ -66,6 +66,8 @@ pub enum ErrorCode { AccountNotMutable, #[msg("The given account is not owned by the executing program")] AccountNotProgramOwned, + #[msg("Program ID was not as expected")] + InvalidProgramId, // State. #[msg("The given state account does not have the correct address")] diff --git a/lang/src/lib.rs b/lang/src/lib.rs index feba101956..5ce0080b46 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -44,8 +44,10 @@ mod error; #[doc(hidden)] pub mod idl; mod loader; +mod program; mod program_account; pub mod state; +mod system_program; mod sysvar; mod vec; @@ -61,12 +63,14 @@ pub use crate::cpi_account::CpiAccount; #[allow(deprecated)] pub use crate::cpi_state::CpiState; pub use crate::loader::Loader; +pub use crate::program::Program; #[doc(hidden)] #[allow(deprecated)] pub use crate::program_account::ProgramAccount; #[doc(hidden)] #[allow(deprecated)] pub use crate::state::ProgramState; +pub use crate::system_program::System; pub use crate::sysvar::Sysvar; pub use anchor_attribute_access_control::access_control; pub use anchor_attribute_account::{account, declare_id, zero_copy}; @@ -217,6 +221,11 @@ pub trait Owner { fn owner() -> Pubkey; } +/// Defines the id of a program. +pub trait Id { + fn id() -> Pubkey; +} + /// Defines the Pubkey of an account. pub trait Key { fn key(&self) -> Pubkey; @@ -234,8 +243,8 @@ pub mod prelude { pub use super::{ access_control, account, declare_id, emit, error, event, interface, program, require, state, zero_copy, Account, AccountDeserialize, AccountSerialize, Accounts, AccountsExit, - AnchorDeserialize, AnchorSerialize, Context, CpiContext, Key, Loader, Owner, - ProgramAccount, Sysvar, ToAccountInfo, ToAccountInfos, ToAccountMetas, + AnchorDeserialize, AnchorSerialize, Context, CpiContext, Key, Loader, Owner, Program, + ProgramAccount, System, Sysvar, ToAccountInfo, ToAccountInfos, ToAccountMetas, }; #[allow(deprecated)] diff --git a/lang/src/program.rs b/lang/src/program.rs new file mode 100644 index 0000000000..9f15a7ebd6 --- /dev/null +++ b/lang/src/program.rs @@ -0,0 +1,94 @@ +use crate::error::ErrorCode; +use crate::*; +use solana_program::account_info::AccountInfo; +use solana_program::instruction::AccountMeta; +use solana_program::program_error::ProgramError; +use solana_program::pubkey::Pubkey; +use std::ops::Deref; + +/// Account container that checks ownership on deserialization. +#[derive(Clone)] +pub struct Program<'info, T: Id + AccountDeserialize + Clone> { + account: T, + info: AccountInfo<'info>, +} + +impl<'a, T: Id + AccountDeserialize + Clone> Program<'a, T> { + fn new(info: AccountInfo<'a>, account: T) -> Program<'a, T> { + Self { info, account } + } + + /// Deserializes the given `info` into a `Program`. + #[inline(never)] + pub fn try_from(info: &AccountInfo<'a>) -> Result, ProgramError> { + if info.key != &T::id() { + return Err(ErrorCode::InvalidProgramId.into()); + } + // Programs have no data so use an empty slice. + let mut empty = &[][..]; + Ok(Program::new(info.clone(), T::try_deserialize(&mut empty)?)) + } +} + +impl<'info, T: Id + Clone> Accounts<'info> for Program<'info, T> +where + T: Id + AccountDeserialize, +{ + #[inline(never)] + fn try_accounts( + _program_id: &Pubkey, + accounts: &mut &[AccountInfo<'info>], + _ix_data: &[u8], + ) -> Result { + if accounts.is_empty() { + return Err(ErrorCode::AccountNotEnoughKeys.into()); + } + let account = &accounts[0]; + *accounts = &accounts[1..]; + Program::try_from(account) + } +} + +impl<'info, T: Id + AccountDeserialize + Clone> ToAccountMetas for Program<'info, T> { + fn to_account_metas(&self, is_signer: Option) -> Vec { + let is_signer = is_signer.unwrap_or(self.info.is_signer); + let meta = match self.info.is_writable { + false => AccountMeta::new_readonly(*self.info.key, is_signer), + true => AccountMeta::new(*self.info.key, is_signer), + }; + vec![meta] + } +} + +impl<'info, T: Id + AccountDeserialize + Clone> ToAccountInfos<'info> for Program<'info, T> { + fn to_account_infos(&self) -> Vec> { + vec![self.info.clone()] + } +} + +impl<'info, T: Id + AccountDeserialize + Clone> ToAccountInfo<'info> for Program<'info, T> { + fn to_account_info(&self) -> AccountInfo<'info> { + self.info.clone() + } +} + +impl<'info, T: Id + AccountDeserialize + Clone> AsRef> for Program<'info, T> { + fn as_ref(&self) -> &AccountInfo<'info> { + &self.info + } +} + +impl<'info, T: Id + AccountDeserialize + Clone> Deref for Program<'info, T> { + type Target = AccountInfo<'info>; + + fn deref(&self) -> &Self::Target { + &self.info + } +} + +impl<'info, T: AccountDeserialize + Id + Clone> AccountsExit<'info> for Program<'info, T> { + fn exit(&self, _program_id: &Pubkey) -> ProgramResult { + // No-op. + Ok(()) + } +} diff --git a/lang/src/system_program.rs b/lang/src/system_program.rs new file mode 100644 index 0000000000..30eed3b76b --- /dev/null +++ b/lang/src/system_program.rs @@ -0,0 +1,24 @@ +use crate::*; +use solana_program::program_error::ProgramError; +use solana_program::pubkey::Pubkey; + +pub use solana_program::system_program::ID; + +#[derive(Clone)] +pub struct System; + +impl anchor_lang::AccountDeserialize for System { + fn try_deserialize(buf: &mut &[u8]) -> Result { + System::try_deserialize_unchecked(buf) + } + + fn try_deserialize_unchecked(_buf: &mut &[u8]) -> Result { + Ok(System) + } +} + +impl anchor_lang::Id for System { + fn id() -> Pubkey { + ID + } +} diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index 070f7fed4e..9758d71dfa 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -515,7 +515,7 @@ pub fn generate_create_account( &[ payer.to_account_info(), #field.to_account_info(), - system_program.to_account_info().clone(), + system_program.to_account_info(), ], &[#seeds_with_nonce], )?; @@ -535,7 +535,7 @@ pub fn generate_create_account( &[ payer.to_account_info(), #field.to_account_info(), - system_program.to_account_info().clone(), + system_program.to_account_info(), ], )?; } @@ -547,7 +547,7 @@ pub fn generate_create_account( ), &[ #field.to_account_info(), - system_program.clone(), + system_program.to_account_info(), ], &[#seeds_with_nonce], )?; diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index c6894bb460..0d4b7a8946 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -271,6 +271,7 @@ impl Field { Ty::Sysvar(_) => quote! { anchor_lang::Sysvar }, Ty::CpiState(_) => quote! { anchor_lang::CpiState }, Ty::ProgramState(_) => quote! { anchor_lang::ProgramState }, + Ty::Program(_) => quote! { anchor_lang::Program }, Ty::AccountInfo => quote! {}, } } @@ -329,6 +330,12 @@ impl Field { SysvarTy::Instructions => quote! {Instructions}, SysvarTy::Rewards => quote! {Rewards}, }, + Ty::Program(ty) => { + let program = &ty.account_type_path; + quote! { + #program + } + } } } } @@ -353,6 +360,7 @@ pub enum Ty { CpiAccount(CpiAccountTy), Sysvar(SysvarTy), Account(AccountTy), + Program(ProgramTy), } #[derive(Debug, PartialEq)] @@ -405,6 +413,12 @@ pub struct AccountTy { pub boxed: bool, } +#[derive(Debug, PartialEq)] +pub struct ProgramTy { + // The struct type of the account. + pub account_type_path: TypePath, +} + #[derive(Debug)] pub struct Error { pub name: String, diff --git a/lang/syn/src/parser/accounts/mod.rs b/lang/syn/src/parser/accounts/mod.rs index 4e120b690a..174b1ae2fd 100644 --- a/lang/syn/src/parser/accounts/mod.rs +++ b/lang/syn/src/parser/accounts/mod.rs @@ -74,6 +74,7 @@ fn is_field_primitive(f: &syn::Field) -> ParseResult { | "CpiState" | "Loader" | "Account" + | "Program" ); Ok(r) } @@ -92,6 +93,7 @@ fn parse_ty(f: &syn::Field) -> ParseResult { "AccountInfo" => Ty::AccountInfo, "Loader" => Ty::Loader(parse_program_account_zero_copy(&path)?), "Account" => Ty::Account(parse_account_ty(&path)?), + "Program" => Ty::Program(parse_program_ty(&path)?), _ => return Err(ParseError::new(f.ty.span(), "invalid account type given")), }; @@ -167,6 +169,11 @@ fn parse_account_ty(path: &syn::Path) -> ParseResult { }) } +fn parse_program_ty(path: &syn::Path) -> ParseResult { + let account_type_path = parse_account(path)?; + Ok(ProgramTy { account_type_path }) +} + // TODO: this whole method is a hack. Do something more idiomatic. fn parse_account(mut path: &syn::Path) -> ParseResult { if parser::tts_to_string(path) diff --git a/spl/src/dex/cpi.rs b/spl/src/dex/cpi.rs index 79f1cf8fca..783cc2e2ca 100644 --- a/spl/src/dex/cpi.rs +++ b/spl/src/dex/cpi.rs @@ -1,8 +1,11 @@ use anchor_lang::solana_program::account_info::AccountInfo; use anchor_lang::solana_program::entrypoint::ProgramResult; +use anchor_lang::solana_program::program_error::ProgramError; +use anchor_lang::solana_program::pubkey::Pubkey; use anchor_lang::{Accounts, CpiContext, ToAccountInfos}; use serum_dex::instruction::SelfTradeBehavior; use serum_dex::matching::{OrderType, Side}; +use std::io::Write; use std::num::NonZeroU64; #[cfg(not(feature = "devnet"))] @@ -280,3 +283,29 @@ pub struct InitializeMarket<'info> { pub event_q: AccountInfo<'info>, pub rent: AccountInfo<'info>, } + +#[derive(Clone)] +pub struct Dex; + +impl anchor_lang::AccountDeserialize for Dex { + fn try_deserialize(buf: &mut &[u8]) -> Result { + Dex::try_deserialize_unchecked(buf) + } + + fn try_deserialize_unchecked(_buf: &mut &[u8]) -> Result { + Ok(Dex) + } +} + +impl anchor_lang::AccountSerialize for Dex { + fn try_serialize(&self, _writer: &mut W) -> Result<(), ProgramError> { + // no-op + Ok(()) + } +} + +impl anchor_lang::Id for Dex { + fn id() -> Pubkey { + ID + } +} diff --git a/spl/src/system.rs b/spl/src/system.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/spl/src/system.rs @@ -0,0 +1 @@ + diff --git a/spl/src/token.rs b/spl/src/token.rs index 44dbd0cabb..490843b95a 100644 --- a/spl/src/token.rs +++ b/spl/src/token.rs @@ -305,6 +305,25 @@ impl Deref for Mint { } } +#[derive(Clone)] +pub struct Token; + +impl anchor_lang::AccountDeserialize for Token { + fn try_deserialize(buf: &mut &[u8]) -> Result { + Token::try_deserialize_unchecked(buf) + } + + fn try_deserialize_unchecked(_buf: &mut &[u8]) -> Result { + Ok(Token) + } +} + +impl anchor_lang::Id for Token { + fn id() -> Pubkey { + ID + } +} + // Field parsers to save compute. All account validation is assumed to be done // outside of these methods. pub mod accessor { diff --git a/tests/cfo/programs/cfo/src/lib.rs b/tests/cfo/programs/cfo/src/lib.rs index c596cf16f3..98abcb9f88 100644 --- a/tests/cfo/programs/cfo/src/lib.rs +++ b/tests/cfo/programs/cfo/src/lib.rs @@ -1,10 +1,10 @@ // WIP. This program has been checkpointed and is not production ready. use anchor_lang::prelude::*; -use anchor_lang::solana_program::system_program; use anchor_lang::solana_program::sysvar::instructions as tx_instructions; -use anchor_spl::token::{self, Mint, TokenAccount}; -use anchor_spl::{dex, mint}; +use anchor_spl::dex::{self, Dex}; +use anchor_spl::mint; +use anchor_spl::token::{self, Mint, Token, TokenAccount}; use registry::{Registrar, RewardVendorKind}; use std::convert::TryInto; @@ -29,7 +29,7 @@ pub mod cfo { let officer = &mut ctx.accounts.officer; officer.authority = *ctx.accounts.authority.key; officer.swap_program = *ctx.accounts.swap_program.key; - officer.dex_program = *ctx.accounts.dex_program.key; + officer.dex_program = ctx.accounts.dex_program.key(); officer.distribution = d; officer.registrar = registrar; officer.msrm_registrar = msrm_registrar; @@ -60,10 +60,8 @@ pub mod cfo { /// Transfers fees from the dex to the CFO. pub fn sweep_fees<'info>(ctx: Context<'_, '_, '_, 'info, SweepFees<'info>>) -> Result<()> { - let seeds = [ - ctx.accounts.dex.dex_program.key.as_ref(), - &[ctx.accounts.officer.bumps.bump], - ]; + let dex_program = ctx.accounts.dex.dex_program.key(); + let seeds = [dex_program.as_ref(), &[ctx.accounts.officer.bumps.bump]]; let cpi_ctx = CpiContext::from(&*ctx.accounts); dex::sweep_fees(cpi_ctx.with_signer(&[&seeds[..]]))?; Ok(()) @@ -76,10 +74,8 @@ pub mod cfo { ctx: Context<'_, '_, '_, 'info, SwapToUsdc<'info>>, min_exchange_rate: ExchangeRate, ) -> Result<()> { - let seeds = [ - ctx.accounts.dex_program.key.as_ref(), - &[ctx.accounts.officer.bumps.bump], - ]; + let dex_program = ctx.accounts.dex_program.key(); + let seeds = [dex_program.as_ref(), &[ctx.accounts.officer.bumps.bump]]; let cpi_ctx = CpiContext::from(&*ctx.accounts); swap::cpi::swap( cpi_ctx.with_signer(&[&seeds[..]]), @@ -97,10 +93,8 @@ pub mod cfo { ctx: Context<'_, '_, '_, 'info, SwapToSrm<'info>>, min_exchange_rate: ExchangeRate, ) -> Result<()> { - let seeds = [ - ctx.accounts.dex_program.key.as_ref(), - &[ctx.accounts.officer.bumps.bump], - ]; + let dex_program = ctx.accounts.dex_program.key(); + let seeds = [dex_program.as_ref(), &[ctx.accounts.officer.bumps.bump]]; let cpi_ctx: CpiContext<'_, '_, '_, 'info, swap::Swap<'info>> = (&*ctx.accounts).into(); swap::cpi::swap( cpi_ctx.with_signer(&[&seeds[..]]), @@ -116,10 +110,8 @@ pub mod cfo { #[access_control(is_distribution_ready(&ctx.accounts))] pub fn distribute<'info>(ctx: Context<'_, '_, '_, 'info, Distribute<'info>>) -> Result<()> { let total_fees = ctx.accounts.srm_vault.amount; - let seeds = [ - ctx.accounts.dex_program.key.as_ref(), - &[ctx.accounts.officer.bumps.bump], - ]; + let dex_program = ctx.accounts.dex_program.key(); + let seeds = [dex_program.as_ref(), &[ctx.accounts.officer.bumps.bump]]; // Burn. let burn_amount: u64 = u128::from(total_fees) @@ -184,10 +176,8 @@ pub mod cfo { period_count, } }; - let seeds = [ - ctx.accounts.dex_program.key.as_ref(), - &[ctx.accounts.officer.bumps.bump], - ]; + let dex_program = ctx.accounts.dex_program.key(); + let seeds = [dex_program.as_ref(), &[ctx.accounts.officer.bumps.bump]]; // Total amount staked denominated in SRM (i.e. MSRM is converted to // SRM) @@ -238,7 +228,7 @@ pub mod cfo { ctx.accounts.srm.registrar.to_account_info().key.as_ref(), ctx.accounts.srm.vendor.to_account_info().key.as_ref(), ], - ctx.accounts.token_program.key, + &ctx.accounts.token_program.key(), ); registry::cpi::drop_reward( ctx.accounts.into_srm_reward().with_signer(&[&seeds[..]]), @@ -268,7 +258,7 @@ pub mod cfo { ctx.accounts.msrm.registrar.to_account_info().key.as_ref(), ctx.accounts.msrm.vendor.to_account_info().key.as_ref(), ], - ctx.accounts.token_program.key, + &ctx.accounts.token_program.key(), ); registry::cpi::drop_reward( ctx.accounts.into_msrm_reward().with_signer(&[&seeds[..]]), @@ -301,7 +291,7 @@ pub mod cfo { pub struct CreateOfficer<'info> { #[account( init, - seeds = [dex_program.key.as_ref()], + seeds = [dex_program.key().as_ref()], bump = bumps.bump, payer = authority, )] @@ -340,14 +330,11 @@ pub struct CreateOfficer<'info> { account(address = mint::SRM), )] mint: AccountInfo<'info>, - #[account(executable)] - dex_program: AccountInfo<'info>, - #[account(executable)] + dex_program: Program<'info, Dex>, + #[account(address = swap::ID)] swap_program: AccountInfo<'info>, - #[account(address = system_program::ID)] - system_program: AccountInfo<'info>, - #[account(address = spl_token::ID)] - token_program: AccountInfo<'info>, + system_program: Program<'info, System>, + token_program: Program<'info, Token>, rent: Sysvar<'info, Rent>, } @@ -368,10 +355,8 @@ pub struct CreateOfficerToken<'info> { mint: AccountInfo<'info>, #[account(mut, signer)] payer: AccountInfo<'info>, - #[account(address = system_program::ID)] - system_program: AccountInfo<'info>, - #[account(address = spl_token::ID)] - token_program: AccountInfo<'info>, + system_program: Program<'info, System>, + token_program: Program<'info, Token>, rent: Sysvar<'info, Rent>, } @@ -386,7 +371,7 @@ pub struct SetDistribution<'info> { #[derive(Accounts)] pub struct SweepFees<'info> { #[account( - seeds = [dex.dex_program.key.as_ref()], + seeds = [dex.dex_program.key().as_ref()], bump = officer.bumps.bump, )] officer: Account<'info, Officer>, @@ -398,20 +383,19 @@ pub struct SweepFees<'info> { )] sweep_vault: Account<'info, TokenAccount>, mint: AccountInfo<'info>, - dex: Dex<'info>, + dex: DexAccounts<'info>, } #[derive(Accounts)] -pub struct Dex<'info> { +pub struct DexAccounts<'info> { #[account(mut)] market: AccountInfo<'info>, #[account(mut)] pc_vault: AccountInfo<'info>, sweep_authority: AccountInfo<'info>, vault_signer: AccountInfo<'info>, - dex_program: AccountInfo<'info>, - #[account(address = spl_token::ID)] - token_program: AccountInfo<'info>, + dex_program: Program<'info, Dex>, + token_program: Program<'info, Token>, } #[derive(Accounts)] @@ -434,10 +418,8 @@ pub struct SwapToUsdc<'info> { usdc_vault: AccountInfo<'info>, #[account(address = swap::ID)] swap_program: AccountInfo<'info>, - #[account(address = dex::ID)] - dex_program: AccountInfo<'info>, - #[account(address = token::ID)] - token_program: AccountInfo<'info>, + dex_program: Program<'info, Dex>, + token_program: Program<'info, Token>, #[account(address = tx_instructions::ID)] instructions: AccountInfo<'info>, rent: Sysvar<'info, Rent>, @@ -468,10 +450,8 @@ pub struct SwapToSrm<'info> { srm_vault: AccountInfo<'info>, #[account(address = swap::ID)] swap_program: AccountInfo<'info>, - #[account(address = dex::ID)] - dex_program: AccountInfo<'info>, - #[account(address = token::ID)] - token_program: AccountInfo<'info>, + dex_program: Program<'info, Dex>, + token_program: Program<'info, Token>, #[account(address = tx_instructions::ID)] instructions: AccountInfo<'info>, rent: Sysvar<'info, Rent>, @@ -522,10 +502,8 @@ pub struct Distribute<'info> { srm_vault: Account<'info, TokenAccount>, #[account(address = mint::SRM)] mint: AccountInfo<'info>, - #[account(address = spl_token::ID)] - token_program: AccountInfo<'info>, - #[account(address = dex::ID)] - dex_program: AccountInfo<'info>, + token_program: Program<'info, Token>, + dex_program: Program<'info, Dex>, } #[derive(Accounts)] @@ -550,14 +528,12 @@ pub struct DropStakeReward<'info> { msrm: DropStakeRewardPool<'info>, #[account(owner = *registry_program.key)] msrm_registrar: Box>, - #[account(address = token::ID)] - token_program: AccountInfo<'info>, + token_program: Program<'info, Token>, #[account(address = registry::ID)] registry_program: AccountInfo<'info>, #[account(address = lockup::ID)] lockup_program: AccountInfo<'info>, - #[account(address = dex::ID)] - dex_program: AccountInfo<'info>, + dex_program: Program<'info, Dex>, clock: Sysvar<'info, Clock>, rent: Sysvar<'info, Rent>, } @@ -628,7 +604,7 @@ impl<'info> From<&SweepFees<'info>> for CpiContext<'_, '_, '_, 'info, dex::Sweep vault_signer: sweep.dex.vault_signer.to_account_info(), token_program: sweep.dex.token_program.to_account_info(), }; - CpiContext::new(program, accounts) + CpiContext::new(program.to_account_info(), accounts) } } @@ -655,7 +631,7 @@ impl<'info> From<&SwapToSrm<'info>> for CpiContext<'_, '_, '_, 'info, swap::Swap token_program: accs.token_program.to_account_info(), rent: accs.rent.to_account_info(), }; - CpiContext::new(program, accounts) + CpiContext::new(program.to_account_info(), accounts) } } @@ -682,7 +658,7 @@ impl<'info> From<&SwapToUsdc<'info>> for CpiContext<'_, '_, '_, 'info, swap::Swa token_program: accs.token_program.to_account_info(), rent: accs.rent.to_account_info(), }; - CpiContext::new(program, accounts) + CpiContext::new(program.to_account_info(), accounts) } } @@ -694,7 +670,7 @@ impl<'info> From<&Distribute<'info>> for CpiContext<'_, '_, '_, 'info, token::Bu to: accs.srm_vault.to_account_info(), authority: accs.officer.to_account_info(), }; - CpiContext::new(program, accounts) + CpiContext::new(program.to_account_info(), accounts) } } @@ -710,11 +686,11 @@ impl<'info> DropStakeReward<'info> { vendor_vault: CpiAccount::try_from(&self.srm.vendor_vault).unwrap(), depositor: self.stake.to_account_info(), depositor_authority: self.officer.to_account_info(), - token_program: self.token_program.clone(), + token_program: self.token_program.to_account_info(), clock: self.clock.clone(), rent: self.rent.clone(), }; - CpiContext::new(program, accounts) + CpiContext::new(program.to_account_info(), accounts) } fn into_msrm_reward(&self) -> CpiContext<'_, '_, '_, 'info, registry::DropReward<'info>> { @@ -728,43 +704,43 @@ impl<'info> DropStakeReward<'info> { vendor_vault: CpiAccount::try_from(&self.msrm.vendor_vault).unwrap(), depositor: self.stake.to_account_info(), depositor_authority: self.officer.to_account_info(), - token_program: self.token_program.clone(), + token_program: self.token_program.to_account_info(), clock: self.clock.clone(), rent: self.rent.clone(), }; - CpiContext::new(program, accounts) + CpiContext::new(program.to_account_info(), accounts) } } impl<'info> Distribute<'info> { fn into_burn(&self) -> CpiContext<'_, '_, '_, 'info, token::Burn<'info>> { - let program = self.token_program.clone(); + let program = self.token_program.to_account_info(); let accounts = token::Burn { mint: self.mint.clone(), to: self.srm_vault.to_account_info(), authority: self.officer.to_account_info(), }; - CpiContext::new(program, accounts) + CpiContext::new(program.to_account_info(), accounts) } fn into_stake_transfer(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> { - let program = self.token_program.clone(); + let program = self.token_program.to_account_info(); let accounts = token::Transfer { from: self.srm_vault.to_account_info(), to: self.stake.to_account_info(), authority: self.officer.to_account_info(), }; - CpiContext::new(program, accounts) + CpiContext::new(program.to_account_info(), accounts) } fn into_treasury_transfer(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> { - let program = self.token_program.clone(); + let program = self.token_program.to_account_info(); let accounts = token::Transfer { from: self.srm_vault.to_account_info(), to: self.treasury.to_account_info(), authority: self.officer.to_account_info(), }; - CpiContext::new(program, accounts) + CpiContext::new(program.to_account_info(), accounts) } } From cf43e247d299f4154bf288a3b4525ba00070e1dc Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Fri, 10 Sep 2021 17:18:21 -0700 Subject: [PATCH 02/15] update --- tests/cfo/programs/cfo/src/lib.rs | 42 +++++++++++++++++++------------ 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/tests/cfo/programs/cfo/src/lib.rs b/tests/cfo/programs/cfo/src/lib.rs index 98abcb9f88..0cec9c528b 100644 --- a/tests/cfo/programs/cfo/src/lib.rs +++ b/tests/cfo/programs/cfo/src/lib.rs @@ -60,8 +60,10 @@ pub mod cfo { /// Transfers fees from the dex to the CFO. pub fn sweep_fees<'info>(ctx: Context<'_, '_, '_, 'info, SweepFees<'info>>) -> Result<()> { - let dex_program = ctx.accounts.dex.dex_program.key(); - let seeds = [dex_program.as_ref(), &[ctx.accounts.officer.bumps.bump]]; + let seeds = [ + ctx.accounts.dex.dex_program.key.as_ref(), + &[ctx.accounts.officer.bumps.bump], + ]; let cpi_ctx = CpiContext::from(&*ctx.accounts); dex::sweep_fees(cpi_ctx.with_signer(&[&seeds[..]]))?; Ok(()) @@ -74,8 +76,10 @@ pub mod cfo { ctx: Context<'_, '_, '_, 'info, SwapToUsdc<'info>>, min_exchange_rate: ExchangeRate, ) -> Result<()> { - let dex_program = ctx.accounts.dex_program.key(); - let seeds = [dex_program.as_ref(), &[ctx.accounts.officer.bumps.bump]]; + let seeds = [ + ctx.accounts.dex_program.key.as_ref(), + &[ctx.accounts.officer.bumps.bump], + ]; let cpi_ctx = CpiContext::from(&*ctx.accounts); swap::cpi::swap( cpi_ctx.with_signer(&[&seeds[..]]), @@ -93,8 +97,10 @@ pub mod cfo { ctx: Context<'_, '_, '_, 'info, SwapToSrm<'info>>, min_exchange_rate: ExchangeRate, ) -> Result<()> { - let dex_program = ctx.accounts.dex_program.key(); - let seeds = [dex_program.as_ref(), &[ctx.accounts.officer.bumps.bump]]; + let seeds = [ + ctx.accounts.dex_program.key.as_ref(), + &[ctx.accounts.officer.bumps.bump], + ]; let cpi_ctx: CpiContext<'_, '_, '_, 'info, swap::Swap<'info>> = (&*ctx.accounts).into(); swap::cpi::swap( cpi_ctx.with_signer(&[&seeds[..]]), @@ -110,8 +116,10 @@ pub mod cfo { #[access_control(is_distribution_ready(&ctx.accounts))] pub fn distribute<'info>(ctx: Context<'_, '_, '_, 'info, Distribute<'info>>) -> Result<()> { let total_fees = ctx.accounts.srm_vault.amount; - let dex_program = ctx.accounts.dex_program.key(); - let seeds = [dex_program.as_ref(), &[ctx.accounts.officer.bumps.bump]]; + let seeds = [ + ctx.accounts.dex_program.key.as_ref(), + &[ctx.accounts.officer.bumps.bump], + ]; // Burn. let burn_amount: u64 = u128::from(total_fees) @@ -176,8 +184,10 @@ pub mod cfo { period_count, } }; - let dex_program = ctx.accounts.dex_program.key(); - let seeds = [dex_program.as_ref(), &[ctx.accounts.officer.bumps.bump]]; + let seeds = [ + ctx.accounts.dex_program.key.as_ref(), + &[ctx.accounts.officer.bumps.bump], + ]; // Total amount staked denominated in SRM (i.e. MSRM is converted to // SRM) @@ -228,7 +238,7 @@ pub mod cfo { ctx.accounts.srm.registrar.to_account_info().key.as_ref(), ctx.accounts.srm.vendor.to_account_info().key.as_ref(), ], - &ctx.accounts.token_program.key(), + ctx.accounts.token_program.key, ); registry::cpi::drop_reward( ctx.accounts.into_srm_reward().with_signer(&[&seeds[..]]), @@ -258,7 +268,7 @@ pub mod cfo { ctx.accounts.msrm.registrar.to_account_info().key.as_ref(), ctx.accounts.msrm.vendor.to_account_info().key.as_ref(), ], - &ctx.accounts.token_program.key(), + ctx.accounts.token_program.key, ); registry::cpi::drop_reward( ctx.accounts.into_msrm_reward().with_signer(&[&seeds[..]]), @@ -291,7 +301,7 @@ pub mod cfo { pub struct CreateOfficer<'info> { #[account( init, - seeds = [dex_program.key().as_ref()], + seeds = [dex_program.key.as_ref()], bump = bumps.bump, payer = authority, )] @@ -371,7 +381,7 @@ pub struct SetDistribution<'info> { #[derive(Accounts)] pub struct SweepFees<'info> { #[account( - seeds = [dex.dex_program.key().as_ref()], + seeds = [dex.dex_program.key.as_ref()], bump = officer.bumps.bump, )] officer: Account<'info, Officer>, @@ -401,7 +411,7 @@ pub struct DexAccounts<'info> { #[derive(Accounts)] pub struct SwapToUsdc<'info> { #[account( - seeds = [dex_program.key().as_ref()], + seeds = [dex_program.key.as_ref()], bump = officer.bumps.bump, )] officer: Account<'info, Officer>, @@ -428,7 +438,7 @@ pub struct SwapToUsdc<'info> { #[derive(Accounts)] pub struct SwapToSrm<'info> { #[account( - seeds = [dex_program.key().as_ref()], + seeds = [dex_program.key.as_ref()], bump = officer.bumps.bump, )] officer: Account<'info, Officer>, From 0c3294c57ec29e6c323c61a5002e45dafd982447 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Fri, 10 Sep 2021 17:21:43 -0700 Subject: [PATCH 03/15] update --- spl/src/system.rs | 1 - 1 file changed, 1 deletion(-) delete mode 100644 spl/src/system.rs diff --git a/spl/src/system.rs b/spl/src/system.rs deleted file mode 100644 index 8b13789179..0000000000 --- a/spl/src/system.rs +++ /dev/null @@ -1 +0,0 @@ - From 4348cc06bf29f38b073851e42dec618424187a93 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Fri, 10 Sep 2021 19:07:31 -0700 Subject: [PATCH 04/15] Update --- lang/syn/src/codegen/program/entry.rs | 28 +++++++++++++++++++++++++++ tests/cfo/programs/cfo/src/lib.rs | 12 +++++------- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/lang/syn/src/codegen/program/entry.rs b/lang/syn/src/codegen/program/entry.rs index 1e7cce2212..8ea106d0b0 100644 --- a/lang/syn/src/codegen/program/entry.rs +++ b/lang/syn/src/codegen/program/entry.rs @@ -1,8 +1,12 @@ use crate::program_codegen::dispatch; use crate::Program; +use heck::CamelCase; use quote::quote; pub fn generate(program: &Program) -> proc_macro2::TokenStream { + let name: proc_macro2::TokenStream = format!("{}", program.name.to_string().to_camel_case()) + .parse() + .unwrap(); let fallback_maybe = dispatch::gen_fallback(program).unwrap_or(quote! { Err(anchor_lang::__private::ErrorCode::InstructionMissing.into()); }); @@ -65,5 +69,29 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { e }) } + + pub mod program { + use super::*; + + /// Type representing the program. + #[derive(Clone)] + pub struct #name; + + impl anchor_lang::AccountDeserialize for #name { + fn try_deserialize(buf: &mut &[u8]) -> std::result::Result { + #name::try_deserialize_unchecked(buf) + } + + fn try_deserialize_unchecked(_buf: &mut &[u8]) -> std::result::Result { + Ok(#name) + } + } + + impl anchor_lang::Id for #name { + fn id() -> Pubkey { + ID + } + } + } } } diff --git a/tests/cfo/programs/cfo/src/lib.rs b/tests/cfo/programs/cfo/src/lib.rs index 0cec9c528b..7ce8e2c8ca 100644 --- a/tests/cfo/programs/cfo/src/lib.rs +++ b/tests/cfo/programs/cfo/src/lib.rs @@ -7,6 +7,7 @@ use anchor_spl::mint; use anchor_spl::token::{self, Mint, Token, TokenAccount}; use registry::{Registrar, RewardVendorKind}; use std::convert::TryInto; +use swap::program::Swap; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); @@ -339,10 +340,9 @@ pub struct CreateOfficer<'info> { not(feature = "test"), account(address = mint::SRM), )] - mint: AccountInfo<'info>, + mint: Box>, dex_program: Program<'info, Dex>, - #[account(address = swap::ID)] - swap_program: AccountInfo<'info>, + swap_program: Program<'info, Swap>, system_program: Program<'info, System>, token_program: Program<'info, Token>, rent: Sysvar<'info, Rent>, @@ -426,8 +426,7 @@ pub struct SwapToUsdc<'info> { quote_vault: AccountInfo<'info>, #[account(seeds = [officer.key().as_ref(), mint::USDC.as_ref()], bump)] usdc_vault: AccountInfo<'info>, - #[account(address = swap::ID)] - swap_program: AccountInfo<'info>, + swap_program: Program<'info, Swap>, dex_program: Program<'info, Dex>, token_program: Program<'info, Token>, #[account(address = tx_instructions::ID)] @@ -458,8 +457,7 @@ pub struct SwapToSrm<'info> { constraint = &officer.stake != from_vault.key, )] srm_vault: AccountInfo<'info>, - #[account(address = swap::ID)] - swap_program: AccountInfo<'info>, + swap_program: Program<'info, Swap>, dex_program: Program<'info, Dex>, token_program: Program<'info, Token>, #[account(address = tx_instructions::ID)] From 6d36d157d9432545dbf2708c0d6ecdc8d19fee11 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Fri, 10 Sep 2021 19:46:21 -0700 Subject: [PATCH 05/15] update --- tests/cfo/programs/cfo/src/lib.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/cfo/programs/cfo/src/lib.rs b/tests/cfo/programs/cfo/src/lib.rs index 7ce8e2c8ca..8952520e5a 100644 --- a/tests/cfo/programs/cfo/src/lib.rs +++ b/tests/cfo/programs/cfo/src/lib.rs @@ -5,6 +5,8 @@ use anchor_lang::solana_program::sysvar::instructions as tx_instructions; use anchor_spl::dex::{self, Dex}; use anchor_spl::mint; use anchor_spl::token::{self, Mint, Token, TokenAccount}; +use lockup::program::Lockup; +use registry::program::Registry; use registry::{Registrar, RewardVendorKind}; use std::convert::TryInto; use swap::program::Swap; @@ -534,13 +536,10 @@ pub struct DropStakeReward<'info> { mint: AccountInfo<'info>, srm: DropStakeRewardPool<'info>, msrm: DropStakeRewardPool<'info>, - #[account(owner = *registry_program.key)] msrm_registrar: Box>, token_program: Program<'info, Token>, - #[account(address = registry::ID)] - registry_program: AccountInfo<'info>, - #[account(address = lockup::ID)] - lockup_program: AccountInfo<'info>, + registry_program: Program<'info, Registry>, + lockup_program: Program<'info, Lockup>, dex_program: Program<'info, Dex>, clock: Sysvar<'info, Clock>, rent: Sysvar<'info, Rent>, From b75c408c8aa43d8155d254b64ca56d34e12780ae Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 11 Sep 2021 09:17:05 -0700 Subject: [PATCH 06/15] update --- .../basic-3/programs/puppet-master/src/lib.rs | 10 +++++----- examples/tutorial/basic-3/programs/puppet/src/lib.rs | 12 +++++------- examples/tutorial/basic-3/tests/basic-3.js | 2 +- lang/src/error.rs | 2 ++ lang/src/program.rs | 3 +++ tests/cfo/programs/cfo/src/lib.rs | 3 +-- ts/src/error.ts | 10 ++++++++++ 7 files changed, 27 insertions(+), 15 deletions(-) diff --git a/examples/tutorial/basic-3/programs/puppet-master/src/lib.rs b/examples/tutorial/basic-3/programs/puppet-master/src/lib.rs index f3d80b3e0c..9082027e64 100644 --- a/examples/tutorial/basic-3/programs/puppet-master/src/lib.rs +++ b/examples/tutorial/basic-3/programs/puppet-master/src/lib.rs @@ -1,6 +1,7 @@ // #region core use anchor_lang::prelude::*; -use puppet::{self, Puppet, SetData}; +use puppet::program::Puppet; +use puppet::{self, Data, SetData}; declare_id!("HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L"); @@ -8,7 +9,7 @@ declare_id!("HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L"); mod puppet_master { use super::*; pub fn pull_strings(ctx: Context, data: u64) -> ProgramResult { - let cpi_program = ctx.accounts.puppet_program.clone(); + let cpi_program = ctx.accounts.puppet_program.to_account_info(); let cpi_accounts = SetData { puppet: ctx.accounts.puppet.clone(), }; @@ -20,8 +21,7 @@ mod puppet_master { #[derive(Accounts)] pub struct PullStrings<'info> { #[account(mut)] - pub puppet: Account<'info, Puppet>, - #[account(address = puppet::ID)] - pub puppet_program: AccountInfo<'info>, + pub puppet: Account<'info, Data>, + pub puppet_program: Program<'info, Puppet>, } // #endregion core diff --git a/examples/tutorial/basic-3/programs/puppet/src/lib.rs b/examples/tutorial/basic-3/programs/puppet/src/lib.rs index d9d8d71b94..9abc07598a 100644 --- a/examples/tutorial/basic-3/programs/puppet/src/lib.rs +++ b/examples/tutorial/basic-3/programs/puppet/src/lib.rs @@ -1,12 +1,11 @@ use anchor_lang::prelude::*; -use anchor_lang::solana_program::system_program; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); #[program] pub mod puppet { use super::*; - pub fn initialize(ctx: Context) -> ProgramResult { + pub fn initialize(_ctx: Context) -> ProgramResult { Ok(()) } @@ -20,20 +19,19 @@ pub mod puppet { #[derive(Accounts)] pub struct Initialize<'info> { #[account(init, payer = user, space = 8 + 8)] - pub puppet: Account<'info, Puppet>, + pub puppet: Account<'info, Data>, #[account(signer)] pub user: AccountInfo<'info>, - #[account(address = system_program::ID)] - pub system_program: AccountInfo<'info>, + pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct SetData<'info> { #[account(mut)] - pub puppet: Account<'info, Puppet>, + pub puppet: Account<'info, Data>, } #[account] -pub struct Puppet { +pub struct Data { pub data: u64, } diff --git a/examples/tutorial/basic-3/tests/basic-3.js b/examples/tutorial/basic-3/tests/basic-3.js index 492a9d1405..9b8605af13 100644 --- a/examples/tutorial/basic-3/tests/basic-3.js +++ b/examples/tutorial/basic-3/tests/basic-3.js @@ -32,7 +32,7 @@ describe("basic-3", () => { }); // Check the state updated. - puppetAccount = await puppet.account.puppet.fetch(newPuppetAccount.publicKey); + puppetAccount = await puppet.account.data.fetch(newPuppetAccount.publicKey); assert.ok(puppetAccount.data.eq(new anchor.BN(111))); }); }); diff --git a/lang/src/error.rs b/lang/src/error.rs index 46fda08f95..18f8e657ef 100644 --- a/lang/src/error.rs +++ b/lang/src/error.rs @@ -68,6 +68,8 @@ pub enum ErrorCode { AccountNotProgramOwned, #[msg("Program ID was not as expected")] InvalidProgramId, + #[msg("Program account is not executable")] + InvalidProgramExecutable, // State. #[msg("The given state account does not have the correct address")] diff --git a/lang/src/program.rs b/lang/src/program.rs index 9f15a7ebd6..51e1d176f2 100644 --- a/lang/src/program.rs +++ b/lang/src/program.rs @@ -24,6 +24,9 @@ impl<'a, T: Id + AccountDeserialize + Clone> Program<'a, T> { if info.key != &T::id() { return Err(ErrorCode::InvalidProgramId.into()); } + if !info.executable { + return Err(ErrorCode::InvalidProgramExecutable.into()); + } // Programs have no data so use an empty slice. let mut empty = &[][..]; Ok(Program::new(info.clone(), T::try_deserialize(&mut empty)?)) diff --git a/tests/cfo/programs/cfo/src/lib.rs b/tests/cfo/programs/cfo/src/lib.rs index 8952520e5a..9944904a96 100644 --- a/tests/cfo/programs/cfo/src/lib.rs +++ b/tests/cfo/programs/cfo/src/lib.rs @@ -74,7 +74,7 @@ pub mod cfo { /// Convert the CFO's entire non-SRM token balance into USDC. /// Assumes USDC is the quote currency. - #[access_control(is_not_trading(&ctx.accounts.instructions))] + #[access_control(is_not_trading(&ctx.accounts.instrutions))] pub fn swap_to_usdc<'info>( ctx: Context<'_, '_, '_, 'info, SwapToUsdc<'info>>, min_exchange_rate: ExchangeRate, @@ -336,7 +336,6 @@ pub struct CreateOfficer<'info> { token::authority = officer, )] treasury: Box>, - #[account(signer)] authority: AccountInfo<'info>, #[cfg_attr( not(feature = "test"), diff --git a/ts/src/error.ts b/ts/src/error.ts index 7ee1eabdf5..6dcf995648 100644 --- a/ts/src/error.ts +++ b/ts/src/error.ts @@ -80,6 +80,8 @@ const LangErrorCode = { AccountNotEnoughKeys: 165, AccountNotMutable: 166, AccountNotProgramOwned: 167, + InvalidProgramId: 168, + InvalidProgramIdExecutable: 169, // State. StateInvalidAddress: 180, @@ -159,6 +161,14 @@ const LangErrorMessage = new Map([ LangErrorCode.AccountNotProgramOwned, "The given account is not owned by the executing program", ], + [ + LangErrorCode.InvalidProgramId, + "Program ID was not as expected", + ], + [ + LangErrorCode.InvalidProgramIdExecutable, + "Program account is not executable", + ], // State. [ From 9594e4567d635bd51cded1f9fa75544e0ea9678b Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 11 Sep 2021 09:37:11 -0700 Subject: [PATCH 07/15] update --- lang/syn/src/codegen/program/entry.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lang/syn/src/codegen/program/entry.rs b/lang/syn/src/codegen/program/entry.rs index 8ea106d0b0..9260ad4da8 100644 --- a/lang/syn/src/codegen/program/entry.rs +++ b/lang/syn/src/codegen/program/entry.rs @@ -4,9 +4,7 @@ use heck::CamelCase; use quote::quote; pub fn generate(program: &Program) -> proc_macro2::TokenStream { - let name: proc_macro2::TokenStream = format!("{}", program.name.to_string().to_camel_case()) - .parse() - .unwrap(); + let name: proc_macro2::TokenStream = program.name.to_string().to_camel_case().parse().unwrap(); let fallback_maybe = dispatch::gen_fallback(program).unwrap_or(quote! { Err(anchor_lang::__private::ErrorCode::InstructionMissing.into()); }); From 4397d7e21828e1a5544f0562de2b7c3d109151e3 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 11 Sep 2021 10:09:43 -0700 Subject: [PATCH 08/15] update --- tests/sysvars/Anchor.toml | 3 +++ tests/sysvars/programs/sysvars/src/lib.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/tests/sysvars/Anchor.toml b/tests/sysvars/Anchor.toml index 5b26d40cfe..37d9b30e0b 100644 --- a/tests/sysvars/Anchor.toml +++ b/tests/sysvars/Anchor.toml @@ -2,5 +2,8 @@ cluster = "localnet" wallet = "~/.config/solana/id.json" +[programs.localnet] +sysvars = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS" + [scripts] test = "mocha -t 1000000 tests/" diff --git a/tests/sysvars/programs/sysvars/src/lib.rs b/tests/sysvars/programs/sysvars/src/lib.rs index 408e7ce3bd..6a8b51eea4 100644 --- a/tests/sysvars/programs/sysvars/src/lib.rs +++ b/tests/sysvars/programs/sysvars/src/lib.rs @@ -1,5 +1,7 @@ use anchor_lang::prelude::*; +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + #[program] mod sysvars { use super::*; From ec96527dbe1f0788d522b4c2d8e36860486966d6 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 11 Sep 2021 10:19:24 -0700 Subject: [PATCH 09/15] Update --- tests/permissioned-markets/Anchor.toml | 4 ++++ .../programs/permissioned-markets-middleware/src/lib.rs | 2 ++ .../programs/permissioned-markets/src/lib.rs | 9 +++++---- tests/pyth/Anchor.toml | 3 +++ tests/pyth/programs/pyth/src/lib.rs | 2 ++ tests/typescript/Anchor.toml | 3 +++ tests/typescript/programs/typescript/src/lib.rs | 2 ++ 7 files changed, 21 insertions(+), 4 deletions(-) diff --git a/tests/permissioned-markets/Anchor.toml b/tests/permissioned-markets/Anchor.toml index c9d9af0cc4..4d2f1553d7 100644 --- a/tests/permissioned-markets/Anchor.toml +++ b/tests/permissioned-markets/Anchor.toml @@ -2,6 +2,10 @@ cluster = "localnet" wallet = "~/.config/solana/id.json" +[programs.localnet] +permissioned_markets = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS" +permissioned_markets_middleware = "HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L" + [[test.genesis]] address = "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin" program = "./deps/serum-dex/dex/target/deploy/serum_dex.so" diff --git a/tests/permissioned-markets/programs/permissioned-markets-middleware/src/lib.rs b/tests/permissioned-markets/programs/permissioned-markets-middleware/src/lib.rs index 98b1413cdf..cdd04a1c64 100644 --- a/tests/permissioned-markets/programs/permissioned-markets-middleware/src/lib.rs +++ b/tests/permissioned-markets/programs/permissioned-markets-middleware/src/lib.rs @@ -10,6 +10,8 @@ use solana_program::entrypoint::ProgramResult; use solana_program::pubkey::Pubkey; use solana_program::sysvar::rent; +declare_id!("HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L"); + /// # Permissioned Markets /// /// This demonstrates how to create "permissioned markets" on Serum via a proxy. diff --git a/tests/permissioned-markets/programs/permissioned-markets/src/lib.rs b/tests/permissioned-markets/programs/permissioned-markets/src/lib.rs index aa5e3d00f2..6d7cf07aaf 100644 --- a/tests/permissioned-markets/programs/permissioned-markets/src/lib.rs +++ b/tests/permissioned-markets/programs/permissioned-markets/src/lib.rs @@ -6,11 +6,12 @@ use serum_dex::instruction::MarketInstruction; use serum_dex::matching::Side; use serum_dex::state::OpenOrders; use solana_program::instruction::Instruction; -use solana_program::program; use solana_program::system_program; use solana_program::sysvar::rent; use std::mem::size_of; +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + /// A low level example of permissioned markets. /// /// It's recommended to instead study `programs/permissioned-markets-middleware` @@ -262,7 +263,7 @@ pub mod permissioned_markets { }) .collect(); let signers: Vec<&[&[u8]]> = tmp_signers.iter().map(|seeds| &seeds[..]).collect(); - program::invoke_signed(&ix, &accounts, &signers)?; + solana_program::program::invoke_signed(&ix, &accounts, &signers)?; } // CPI to the dex. @@ -290,7 +291,7 @@ pub mod permissioned_markets { dex_program = dex.key, market = market }; - program::invoke_signed(&ix, &acc_infos, &[seeds, seeds_init])?; + solana_program::program::invoke_signed(&ix, &acc_infos, &[seeds, seeds_init])?; // Execute post instruction. if let Some((ix, accounts, seeds)) = post_instruction { @@ -302,7 +303,7 @@ pub mod permissioned_markets { }) .collect(); let signers: Vec<&[&[u8]]> = tmp_signers.iter().map(|seeds| &seeds[..]).collect(); - program::invoke_signed(&ix, &accounts, &signers)?; + solana_program::program::invoke_signed(&ix, &accounts, &signers)?; } Ok(()) diff --git a/tests/pyth/Anchor.toml b/tests/pyth/Anchor.toml index 0355825da7..f2146b98f6 100644 --- a/tests/pyth/Anchor.toml +++ b/tests/pyth/Anchor.toml @@ -2,5 +2,8 @@ cluster = "localnet" wallet = "~/.config/solana/id.json" +[programs.localnet] +pyth = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS" + [scripts] test = "ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/tests/pyth/programs/pyth/src/lib.rs b/tests/pyth/programs/pyth/src/lib.rs index 0668909363..a25a0ffc86 100644 --- a/tests/pyth/programs/pyth/src/lib.rs +++ b/tests/pyth/programs/pyth/src/lib.rs @@ -2,6 +2,8 @@ use anchor_lang::prelude::*; mod pc; use pc::Price; +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + #[program] pub mod pyth { use super::*; diff --git a/tests/typescript/Anchor.toml b/tests/typescript/Anchor.toml index 8f3a162aff..ab4de60a01 100644 --- a/tests/typescript/Anchor.toml +++ b/tests/typescript/Anchor.toml @@ -2,6 +2,9 @@ cluster = "localnet" wallet = "~/.config/solana/id.json" +[programs.localnet] +typescript = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS" + [workspace] members = ["programs/typescript"] diff --git a/tests/typescript/programs/typescript/src/lib.rs b/tests/typescript/programs/typescript/src/lib.rs index 1f82096c57..43a312388d 100644 --- a/tests/typescript/programs/typescript/src/lib.rs +++ b/tests/typescript/programs/typescript/src/lib.rs @@ -3,6 +3,8 @@ use anchor_lang::prelude::*; +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + #[program] pub mod typescript { use super::*; From 5806366a1dfb1b25b49ccc8e4318f2e11ed53ad7 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 11 Sep 2021 10:52:04 -0700 Subject: [PATCH 10/15] ts lint --- ts/src/error.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ts/src/error.ts b/ts/src/error.ts index 6dcf995648..28242c9105 100644 --- a/ts/src/error.ts +++ b/ts/src/error.ts @@ -80,8 +80,8 @@ const LangErrorCode = { AccountNotEnoughKeys: 165, AccountNotMutable: 166, AccountNotProgramOwned: 167, - InvalidProgramId: 168, - InvalidProgramIdExecutable: 169, + InvalidProgramId: 168, + InvalidProgramIdExecutable: 169, // State. StateInvalidAddress: 180, @@ -161,10 +161,7 @@ const LangErrorMessage = new Map([ LangErrorCode.AccountNotProgramOwned, "The given account is not owned by the executing program", ], - [ - LangErrorCode.InvalidProgramId, - "Program ID was not as expected", - ], + [LangErrorCode.InvalidProgramId, "Program ID was not as expected"], [ LangErrorCode.InvalidProgramIdExecutable, "Program account is not executable", From bc1378ee977942c8a9c340c809c47352187cdbf9 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 11 Sep 2021 10:55:30 -0700 Subject: [PATCH 11/15] update --- tests/cfo/programs/cfo/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cfo/programs/cfo/src/lib.rs b/tests/cfo/programs/cfo/src/lib.rs index 9944904a96..85bb3d3547 100644 --- a/tests/cfo/programs/cfo/src/lib.rs +++ b/tests/cfo/programs/cfo/src/lib.rs @@ -74,7 +74,7 @@ pub mod cfo { /// Convert the CFO's entire non-SRM token balance into USDC. /// Assumes USDC is the quote currency. - #[access_control(is_not_trading(&ctx.accounts.instrutions))] + #[access_control(is_not_trading(&ctx.accounts.instructions))] pub fn swap_to_usdc<'info>( ctx: Context<'_, '_, '_, 'info, SwapToUsdc<'info>>, min_exchange_rate: ExchangeRate, From 9f58aed6a96f04fe042e3316bcf1826849c6682b Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 11 Sep 2021 11:06:27 -0700 Subject: [PATCH 12/15] update --- examples/tutorial/basic-0/Anchor.toml | 3 +++ examples/tutorial/basic-0/programs/basic-0/src/lib.rs | 2 ++ tests/swap/Anchor.toml | 3 +++ tests/swap/programs/swap/src/lib.rs | 2 ++ 4 files changed, 10 insertions(+) diff --git a/examples/tutorial/basic-0/Anchor.toml b/examples/tutorial/basic-0/Anchor.toml index 5b26d40cfe..8ebbc84657 100644 --- a/examples/tutorial/basic-0/Anchor.toml +++ b/examples/tutorial/basic-0/Anchor.toml @@ -2,5 +2,8 @@ cluster = "localnet" wallet = "~/.config/solana/id.json" +[programs.localnet] +basic_0 = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS" + [scripts] test = "mocha -t 1000000 tests/" diff --git a/examples/tutorial/basic-0/programs/basic-0/src/lib.rs b/examples/tutorial/basic-0/programs/basic-0/src/lib.rs index af04f02753..82f0bd0742 100644 --- a/examples/tutorial/basic-0/programs/basic-0/src/lib.rs +++ b/examples/tutorial/basic-0/programs/basic-0/src/lib.rs @@ -1,5 +1,7 @@ use anchor_lang::prelude::*; +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + #[program] mod basic_0 { use super::*; diff --git a/tests/swap/Anchor.toml b/tests/swap/Anchor.toml index c9d9af0cc4..d118927720 100644 --- a/tests/swap/Anchor.toml +++ b/tests/swap/Anchor.toml @@ -2,6 +2,9 @@ cluster = "localnet" wallet = "~/.config/solana/id.json" +[programs.localnet] +swap = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS" + [[test.genesis]] address = "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin" program = "./deps/serum-dex/dex/target/deploy/serum_dex.so" diff --git a/tests/swap/programs/swap/src/lib.rs b/tests/swap/programs/swap/src/lib.rs index 6d8182f9ac..c3274f14ee 100644 --- a/tests/swap/programs/swap/src/lib.rs +++ b/tests/swap/programs/swap/src/lib.rs @@ -14,6 +14,8 @@ use anchor_spl::dex::serum_dex::state::MarketState; use anchor_spl::token; use std::num::NonZeroU64; +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + #[program] pub mod swap { use super::*; From d27db6f5ac7491e8a02e529be39215f951962916 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 11 Sep 2021 11:08:35 -0700 Subject: [PATCH 13/15] Update --- tests/spl/token-proxy/Anchor.toml | 3 +++ tests/spl/token-proxy/programs/token-proxy/src/lib.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/tests/spl/token-proxy/Anchor.toml b/tests/spl/token-proxy/Anchor.toml index 5b26d40cfe..9af6776fde 100644 --- a/tests/spl/token-proxy/Anchor.toml +++ b/tests/spl/token-proxy/Anchor.toml @@ -2,5 +2,8 @@ cluster = "localnet" wallet = "~/.config/solana/id.json" +[programs.localnet] +token_proxy = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS" + [scripts] test = "mocha -t 1000000 tests/" diff --git a/tests/spl/token-proxy/programs/token-proxy/src/lib.rs b/tests/spl/token-proxy/programs/token-proxy/src/lib.rs index 4b3fe37de0..acb78fb567 100644 --- a/tests/spl/token-proxy/programs/token-proxy/src/lib.rs +++ b/tests/spl/token-proxy/programs/token-proxy/src/lib.rs @@ -3,6 +3,8 @@ use anchor_lang::prelude::*; use anchor_spl::token::{self, Burn, MintTo, SetAuthority, Transfer}; +declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); + #[program] mod token_proxy { use super::*; From 4318c4480852db007ec5f31531c2ad5474dac009 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 11 Sep 2021 12:52:30 -0700 Subject: [PATCH 14/15] Update --- tests/cfo/deps/stake | 2 +- tests/lockup/programs/lockup/src/lib.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/cfo/deps/stake b/tests/cfo/deps/stake index 9a257678df..28a7f1e0c1 160000 --- a/tests/cfo/deps/stake +++ b/tests/cfo/deps/stake @@ -1 +1 @@ -Subproject commit 9a257678dfd0bda0c222e516e8c1a778b401d71e +Subproject commit 28a7f1e0c134f16f99e201069970df78ec5d7e78 diff --git a/tests/lockup/programs/lockup/src/lib.rs b/tests/lockup/programs/lockup/src/lib.rs index 5cf94f5bd5..8b5916aab1 100644 --- a/tests/lockup/programs/lockup/src/lib.rs +++ b/tests/lockup/programs/lockup/src/lib.rs @@ -2,8 +2,8 @@ //! it's suggested to start with the other examples. use anchor_lang::prelude::*; +use anchor_lang::solana_program; use anchor_lang::solana_program::instruction::Instruction; -use anchor_lang::solana_program::program; use anchor_spl::token::{self, TokenAccount, Transfer}; mod calculator; @@ -477,7 +477,8 @@ pub fn whitelist_relay_cpi<'info>( let signer = &[&seeds[..]]; let mut accounts = transfer.to_account_infos(); accounts.extend_from_slice(&remaining_accounts); - program::invoke_signed(&relay_instruction, &accounts, signer).map_err(Into::into) + solana_program::program::invoke_signed(&relay_instruction, &accounts, signer) + .map_err(Into::into) } pub fn is_whitelisted<'info>(transfer: &WhitelistTransfer<'info>) -> Result<()> { From 77d04a7d7697fb9bace59e228aef61f1b45006b2 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Sat, 11 Sep 2021 12:56:10 -0700 Subject: [PATCH 15/15] Update --- CHANGELOG.md | 5 + .../basic-1/programs/basic-1/src/lib.rs | 5 +- .../basic-2/programs/basic-2/src/lib.rs | 11 +-- .../basic-3/programs/puppet/src/lib.rs | 4 +- .../basic-4/programs/basic-4/src/lib.rs | 3 +- lang/src/error.rs | 2 + lang/src/lib.rs | 4 +- lang/src/signer.rs | 97 +++++++++++++++++++ lang/syn/src/lib.rs | 8 ++ lang/syn/src/parser/accounts/mod.rs | 2 + tests/cfo/programs/cfo/src/lib.rs | 7 +- 11 files changed, 130 insertions(+), 18 deletions(-) create mode 100644 lang/src/signer.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 729deb0f8c..3f5e08bdb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ incremented for features. ## [Unreleased] +### Features + +* lang: `Program` type introduced for executable accounts ([#705](https://github.com/project-serum/anchor/pull/705)). +* lang: `Signer` type introduced for signing accounts where data is not used ([#705](https://github.com/project-serum/anchor/pull/705)). + ### Breaking Changes * lang: `#[account(owner = )]` now requires a `Pubkey` instead of an account ([#691](https://github.com/project-serum/anchor/pull/691)). diff --git a/examples/tutorial/basic-1/programs/basic-1/src/lib.rs b/examples/tutorial/basic-1/programs/basic-1/src/lib.rs index a1f2d9e77c..a7c5ec0587 100644 --- a/examples/tutorial/basic-1/programs/basic-1/src/lib.rs +++ b/examples/tutorial/basic-1/programs/basic-1/src/lib.rs @@ -23,8 +23,9 @@ mod basic_1 { pub struct Initialize<'info> { #[account(init, payer = user, space = 8 + 8)] pub my_account: Account<'info, MyAccount>, - pub user: AccountInfo<'info>, - pub system_program: AccountInfo<'info>, + #[account(mut)] + pub user: Signer<'info>, + pub system_program: Program<'info, System>, } #[derive(Accounts)] diff --git a/examples/tutorial/basic-2/programs/basic-2/src/lib.rs b/examples/tutorial/basic-2/programs/basic-2/src/lib.rs index 8e2c45ec9d..1c6140e2e6 100644 --- a/examples/tutorial/basic-2/programs/basic-2/src/lib.rs +++ b/examples/tutorial/basic-2/programs/basic-2/src/lib.rs @@ -1,5 +1,4 @@ use anchor_lang::prelude::*; -use anchor_lang::solana_program::system_program; declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); @@ -25,18 +24,16 @@ mod basic_2 { pub struct Create<'info> { #[account(init, payer = user, space = 8 + 40)] pub counter: Account<'info, Counter>, - #[account(signer)] - pub user: AccountInfo<'info>, - #[account(address = system_program::ID)] - pub system_program: AccountInfo<'info>, + #[account(mut)] + pub user: Signer<'info>, + pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct Increment<'info> { #[account(mut, has_one = authority)] pub counter: Account<'info, Counter>, - #[account(signer)] - pub authority: AccountInfo<'info>, + pub authority: Signer<'info>, } #[account] diff --git a/examples/tutorial/basic-3/programs/puppet/src/lib.rs b/examples/tutorial/basic-3/programs/puppet/src/lib.rs index 9abc07598a..1563479ea3 100644 --- a/examples/tutorial/basic-3/programs/puppet/src/lib.rs +++ b/examples/tutorial/basic-3/programs/puppet/src/lib.rs @@ -20,8 +20,8 @@ pub mod puppet { pub struct Initialize<'info> { #[account(init, payer = user, space = 8 + 8)] pub puppet: Account<'info, Data>, - #[account(signer)] - pub user: AccountInfo<'info>, + #[account(mut)] + pub user: Signer<'info>, pub system_program: Program<'info, System>, } diff --git a/examples/tutorial/basic-4/programs/basic-4/src/lib.rs b/examples/tutorial/basic-4/programs/basic-4/src/lib.rs index cd5ab26059..0c182a5042 100644 --- a/examples/tutorial/basic-4/programs/basic-4/src/lib.rs +++ b/examples/tutorial/basic-4/programs/basic-4/src/lib.rs @@ -33,8 +33,7 @@ pub mod basic_4 { #[derive(Accounts)] pub struct Auth<'info> { - #[account(signer)] - authority: AccountInfo<'info>, + authority: Signer<'info>, } // #endregion code diff --git a/lang/src/error.rs b/lang/src/error.rs index 18f8e657ef..b3f6786874 100644 --- a/lang/src/error.rs +++ b/lang/src/error.rs @@ -70,6 +70,8 @@ pub enum ErrorCode { InvalidProgramId, #[msg("Program account is not executable")] InvalidProgramExecutable, + #[msg("The given account did not sign")] + AccountNotSigner, // State. #[msg("The given state account does not have the correct address")] diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 5ce0080b46..0a3abea5e4 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -46,6 +46,7 @@ pub mod idl; mod loader; mod program; mod program_account; +mod signer; pub mod state; mod system_program; mod sysvar; @@ -67,6 +68,7 @@ pub use crate::program::Program; #[doc(hidden)] #[allow(deprecated)] pub use crate::program_account::ProgramAccount; +pub use crate::signer::Signer; #[doc(hidden)] #[allow(deprecated)] pub use crate::state::ProgramState; @@ -244,7 +246,7 @@ pub mod prelude { access_control, account, declare_id, emit, error, event, interface, program, require, state, zero_copy, Account, AccountDeserialize, AccountSerialize, Accounts, AccountsExit, AnchorDeserialize, AnchorSerialize, Context, CpiContext, Key, Loader, Owner, Program, - ProgramAccount, System, Sysvar, ToAccountInfo, ToAccountInfos, ToAccountMetas, + ProgramAccount, Signer, System, Sysvar, ToAccountInfo, ToAccountInfos, ToAccountMetas, }; #[allow(deprecated)] diff --git a/lang/src/signer.rs b/lang/src/signer.rs new file mode 100644 index 0000000000..33d5cf88f5 --- /dev/null +++ b/lang/src/signer.rs @@ -0,0 +1,97 @@ +use crate::error::ErrorCode; +use crate::*; +use solana_program::account_info::AccountInfo; +use solana_program::entrypoint::ProgramResult; +use solana_program::instruction::AccountMeta; +use solana_program::program_error::ProgramError; +use solana_program::pubkey::Pubkey; +use std::ops::Deref; + +/// Type validating that the account signed the transaction. No other ownership +/// or type checks are done. If this is used, one should not try to access the +/// underlying account data. +#[derive(Clone)] +pub struct Signer<'info> { + info: AccountInfo<'info>, +} + +impl<'info> Signer<'info> { + fn new(info: AccountInfo<'info>) -> Signer<'info> { + Self { info } + } + + /// Deserializes the given `info` into a `Signer`. + #[inline(never)] + pub fn try_from(info: &AccountInfo<'info>) -> Result, ProgramError> { + if !info.is_signer { + return Err(ErrorCode::AccountNotSigner.into()); + } + Ok(Signer::new(info.clone())) + } +} + +impl<'info> Accounts<'info> for Signer<'info> { + #[inline(never)] + fn try_accounts( + _program_id: &Pubkey, + accounts: &mut &[AccountInfo<'info>], + _ix_data: &[u8], + ) -> Result { + if accounts.is_empty() { + return Err(ErrorCode::AccountNotEnoughKeys.into()); + } + let account = &accounts[0]; + *accounts = &accounts[1..]; + Signer::try_from(account) + } +} + +impl<'info> AccountsExit<'info> for Signer<'info> { + fn exit(&self, _program_id: &Pubkey) -> ProgramResult { + // No-op. + Ok(()) + } +} + +impl<'info> ToAccountMetas for Signer<'info> { + fn to_account_metas(&self, is_signer: Option) -> Vec { + let is_signer = is_signer.unwrap_or(self.info.is_signer); + let meta = match self.info.is_writable { + false => AccountMeta::new_readonly(*self.info.key, is_signer), + true => AccountMeta::new(*self.info.key, is_signer), + }; + vec![meta] + } +} + +impl<'info> ToAccountInfos<'info> for Signer<'info> { + fn to_account_infos(&self) -> Vec> { + vec![self.info.clone()] + } +} + +impl<'info> ToAccountInfo<'info> for Signer<'info> { + fn to_account_info(&self) -> AccountInfo<'info> { + self.info.clone() + } +} + +impl<'info> AsRef> for Signer<'info> { + fn as_ref(&self) -> &AccountInfo<'info> { + &self.info + } +} + +impl<'info> Deref for Signer<'info> { + type Target = AccountInfo<'info>; + + fn deref(&self) -> &Self::Target { + &self.info + } +} + +impl<'info> Key for Signer<'info> { + fn key(&self) -> Pubkey { + *self.info.key + } +} diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index 0d4b7a8946..0fd457be12 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -178,6 +178,9 @@ impl Field { Ty::AccountInfo => quote! { AccountInfo }, + Ty::Signer => quote! { + Signer + }, Ty::Account(AccountTy { boxed, .. }) => { if *boxed { quote! { @@ -273,6 +276,7 @@ impl Field { Ty::ProgramState(_) => quote! { anchor_lang::ProgramState }, Ty::Program(_) => quote! { anchor_lang::Program }, Ty::AccountInfo => quote! {}, + Ty::Signer => quote! {}, } } @@ -282,6 +286,9 @@ impl Field { Ty::AccountInfo => quote! { AccountInfo }, + Ty::Signer => quote! { + Signer + }, Ty::ProgramAccount(ty) => { let ident = &ty.account_type_path; quote! { @@ -361,6 +368,7 @@ pub enum Ty { Sysvar(SysvarTy), Account(AccountTy), Program(ProgramTy), + Signer, } #[derive(Debug, PartialEq)] diff --git a/lang/syn/src/parser/accounts/mod.rs b/lang/syn/src/parser/accounts/mod.rs index 174b1ae2fd..93cacbce76 100644 --- a/lang/syn/src/parser/accounts/mod.rs +++ b/lang/syn/src/parser/accounts/mod.rs @@ -75,6 +75,7 @@ fn is_field_primitive(f: &syn::Field) -> ParseResult { | "Loader" | "Account" | "Program" + | "Signer" ); Ok(r) } @@ -94,6 +95,7 @@ fn parse_ty(f: &syn::Field) -> ParseResult { "Loader" => Ty::Loader(parse_program_account_zero_copy(&path)?), "Account" => Ty::Account(parse_account_ty(&path)?), "Program" => Ty::Program(parse_program_ty(&path)?), + "Signer" => Ty::Signer, _ => return Err(ParseError::new(f.ty.span(), "invalid account type given")), }; diff --git a/tests/cfo/programs/cfo/src/lib.rs b/tests/cfo/programs/cfo/src/lib.rs index 85bb3d3547..afa05da6e1 100644 --- a/tests/cfo/programs/cfo/src/lib.rs +++ b/tests/cfo/programs/cfo/src/lib.rs @@ -364,8 +364,8 @@ pub struct CreateOfficerToken<'info> { token: Account<'info, TokenAccount>, #[account(owner = spl_token::ID)] mint: AccountInfo<'info>, - #[account(mut, signer)] - payer: AccountInfo<'info>, + #[account(mut)] + payer: Signer<'info>, system_program: Program<'info, System>, token_program: Program<'info, Token>, rent: Sysvar<'info, Rent>, @@ -375,8 +375,7 @@ pub struct CreateOfficerToken<'info> { pub struct SetDistribution<'info> { #[account(has_one = authority)] officer: Account<'info, Officer>, - #[account(signer)] - authority: AccountInfo<'info>, + authority: Signer<'info>, } #[derive(Accounts)]