lang, spl: Program and Signer types (#705)

This commit is contained in:
Armani Ferrante 2021-09-11 14:43:12 -07:00 committed by GitHub
parent e2bd41b967
commit b1ef7431ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 472 additions and 106 deletions

View File

@ -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 = <pubkey>)]` now requires a `Pubkey` instead of an account ([#691](https://github.com/project-serum/anchor/pull/691)).

View File

@ -2,5 +2,8 @@
cluster = "localnet"
wallet = "~/.config/solana/id.json"
[programs.localnet]
basic_0 = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
[scripts]
test = "mocha -t 1000000 tests/"

View File

@ -1,5 +1,7 @@
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
mod basic_0 {
use super::*;

View File

@ -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)]

View File

@ -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]

View File

@ -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<PullStrings>, 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

View File

@ -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<Initialize>) -> ProgramResult {
pub fn initialize(_ctx: Context<Initialize>) -> 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>,
#[account(signer)]
pub user: AccountInfo<'info>,
#[account(address = system_program::ID)]
pub system_program: AccountInfo<'info>,
pub puppet: Account<'info, Data>,
#[account(mut)]
pub user: Signer<'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,
}

View File

@ -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)));
});
});

View File

@ -33,8 +33,7 @@ pub mod basic_4 {
#[derive(Accounts)]
pub struct Auth<'info> {
#[account(signer)]
authority: AccountInfo<'info>,
authority: Signer<'info>,
}
// #endregion code

View File

@ -66,6 +66,12 @@ pub enum ErrorCode {
AccountNotMutable,
#[msg("The given account is not owned by the executing program")]
AccountNotProgramOwned,
#[msg("Program ID was not as expected")]
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")]

View File

@ -44,8 +44,11 @@ mod error;
#[doc(hidden)]
pub mod idl;
mod loader;
mod program;
mod program_account;
mod signer;
pub mod state;
mod system_program;
mod sysvar;
mod vec;
@ -61,12 +64,15 @@ 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;
pub use crate::signer::Signer;
#[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 +223,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 +245,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, Signer, System, Sysvar, ToAccountInfo, ToAccountInfos, ToAccountMetas,
};
#[allow(deprecated)]

97
lang/src/program.rs Normal file
View File

@ -0,0 +1,97 @@
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<Program<'a, T>, ProgramError> {
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)?))
}
}
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<Self, ProgramError> {
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<bool>) -> Vec<AccountMeta> {
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<AccountInfo<'info>> {
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<AccountInfo<'info>> 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(())
}
}

97
lang/src/signer.rs Normal file
View File

@ -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<Signer<'info>, 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<Self, ProgramError> {
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<bool>) -> Vec<AccountMeta> {
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<AccountInfo<'info>> {
vec![self.info.clone()]
}
}
impl<'info> ToAccountInfo<'info> for Signer<'info> {
fn to_account_info(&self) -> AccountInfo<'info> {
self.info.clone()
}
}
impl<'info> AsRef<AccountInfo<'info>> 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
}
}

View File

@ -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<Self, ProgramError> {
System::try_deserialize_unchecked(buf)
}
fn try_deserialize_unchecked(_buf: &mut &[u8]) -> Result<Self, ProgramError> {
Ok(System)
}
}
impl anchor_lang::Id for System {
fn id() -> Pubkey {
ID
}
}

View File

@ -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],
)?;

View File

@ -1,8 +1,10 @@
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 = 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 +67,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<Self, anchor_lang::solana_program::program_error::ProgramError> {
#name::try_deserialize_unchecked(buf)
}
fn try_deserialize_unchecked(_buf: &mut &[u8]) -> std::result::Result<Self, anchor_lang::solana_program::program_error::ProgramError> {
Ok(#name)
}
}
impl anchor_lang::Id for #name {
fn id() -> Pubkey {
ID
}
}
}
}
}

View File

@ -178,6 +178,9 @@ impl Field {
Ty::AccountInfo => quote! {
AccountInfo
},
Ty::Signer => quote! {
Signer
},
Ty::Account(AccountTy { boxed, .. }) => {
if *boxed {
quote! {
@ -271,7 +274,9 @@ 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! {},
Ty::Signer => quote! {},
}
}
@ -281,6 +286,9 @@ impl Field {
Ty::AccountInfo => quote! {
AccountInfo
},
Ty::Signer => quote! {
Signer
},
Ty::ProgramAccount(ty) => {
let ident = &ty.account_type_path;
quote! {
@ -329,6 +337,12 @@ impl Field {
SysvarTy::Instructions => quote! {Instructions},
SysvarTy::Rewards => quote! {Rewards},
},
Ty::Program(ty) => {
let program = &ty.account_type_path;
quote! {
#program
}
}
}
}
}
@ -353,6 +367,8 @@ pub enum Ty {
CpiAccount(CpiAccountTy),
Sysvar(SysvarTy),
Account(AccountTy),
Program(ProgramTy),
Signer,
}
#[derive(Debug, PartialEq)]
@ -405,6 +421,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,

View File

@ -74,6 +74,8 @@ fn is_field_primitive(f: &syn::Field) -> ParseResult<bool> {
| "CpiState"
| "Loader"
| "Account"
| "Program"
| "Signer"
);
Ok(r)
}
@ -92,6 +94,8 @@ fn parse_ty(f: &syn::Field) -> ParseResult<Ty> {
"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)?),
"Signer" => Ty::Signer,
_ => return Err(ParseError::new(f.ty.span(), "invalid account type given")),
};
@ -167,6 +171,11 @@ fn parse_account_ty(path: &syn::Path) -> ParseResult<AccountTy> {
})
}
fn parse_program_ty(path: &syn::Path) -> ParseResult<ProgramTy> {
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<syn::TypePath> {
if parser::tts_to_string(path)

View File

@ -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<Self, ProgramError> {
Dex::try_deserialize_unchecked(buf)
}
fn try_deserialize_unchecked(_buf: &mut &[u8]) -> Result<Self, ProgramError> {
Ok(Dex)
}
}
impl anchor_lang::AccountSerialize for Dex {
fn try_serialize<W: Write>(&self, _writer: &mut W) -> Result<(), ProgramError> {
// no-op
Ok(())
}
}
impl anchor_lang::Id for Dex {
fn id() -> Pubkey {
ID
}
}

View File

@ -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<Self, ProgramError> {
Token::try_deserialize_unchecked(buf)
}
fn try_deserialize_unchecked(_buf: &mut &[u8]) -> Result<Self, ProgramError> {
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 {

@ -1 +1 @@
Subproject commit 9a257678dfd0bda0c222e516e8c1a778b401d71e
Subproject commit 28a7f1e0c134f16f99e201069970df78ec5d7e78

View File

@ -1,12 +1,15 @@
// 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 lockup::program::Lockup;
use registry::program::Registry;
use registry::{Registrar, RewardVendorKind};
use std::convert::TryInto;
use swap::program::Swap;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
@ -29,7 +32,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;
@ -333,21 +336,16 @@ pub struct CreateOfficer<'info> {
token::authority = officer,
)]
treasury: Box<Account<'info, TokenAccount>>,
#[account(signer)]
authority: AccountInfo<'info>,
#[cfg_attr(
not(feature = "test"),
account(address = mint::SRM),
)]
mint: AccountInfo<'info>,
#[account(executable)]
dex_program: AccountInfo<'info>,
#[account(executable)]
swap_program: AccountInfo<'info>,
#[account(address = system_program::ID)]
system_program: AccountInfo<'info>,
#[account(address = spl_token::ID)]
token_program: AccountInfo<'info>,
mint: Box<Account<'info, Mint>>,
dex_program: Program<'info, Dex>,
swap_program: Program<'info, Swap>,
system_program: Program<'info, System>,
token_program: Program<'info, Token>,
rent: Sysvar<'info, Rent>,
}
@ -366,12 +364,10 @@ pub struct CreateOfficerToken<'info> {
token: Account<'info, TokenAccount>,
#[account(owner = spl_token::ID)]
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>,
#[account(mut)]
payer: Signer<'info>,
system_program: Program<'info, System>,
token_program: Program<'info, Token>,
rent: Sysvar<'info, Rent>,
}
@ -379,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)]
@ -398,26 +393,25 @@ 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)]
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>,
@ -432,12 +426,9 @@ 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>,
#[account(address = dex::ID)]
dex_program: AccountInfo<'info>,
#[account(address = token::ID)]
token_program: AccountInfo<'info>,
swap_program: Program<'info, Swap>,
dex_program: Program<'info, Dex>,
token_program: Program<'info, Token>,
#[account(address = tx_instructions::ID)]
instructions: AccountInfo<'info>,
rent: Sysvar<'info, Rent>,
@ -446,7 +437,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>,
@ -466,12 +457,9 @@ pub struct SwapToSrm<'info> {
constraint = &officer.stake != from_vault.key,
)]
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>,
swap_program: Program<'info, Swap>,
dex_program: Program<'info, Dex>,
token_program: Program<'info, Token>,
#[account(address = tx_instructions::ID)]
instructions: AccountInfo<'info>,
rent: Sysvar<'info, Rent>,
@ -522,10 +510,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)]
@ -548,16 +534,11 @@ pub struct DropStakeReward<'info> {
mint: AccountInfo<'info>,
srm: DropStakeRewardPool<'info>,
msrm: DropStakeRewardPool<'info>,
#[account(owner = *registry_program.key)]
msrm_registrar: Box<Account<'info, Registrar>>,
#[account(address = token::ID)]
token_program: AccountInfo<'info>,
#[account(address = registry::ID)]
registry_program: AccountInfo<'info>,
#[account(address = lockup::ID)]
lockup_program: AccountInfo<'info>,
#[account(address = dex::ID)]
dex_program: AccountInfo<'info>,
token_program: Program<'info, Token>,
registry_program: Program<'info, Registry>,
lockup_program: Program<'info, Lockup>,
dex_program: Program<'info, Dex>,
clock: Sysvar<'info, Clock>,
rent: Sysvar<'info, Rent>,
}
@ -628,7 +609,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 +636,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 +663,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 +675,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 +691,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 +709,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)
}
}

View File

@ -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<()> {

View File

@ -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"

View File

@ -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.

View File

@ -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(())

View File

@ -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"

View File

@ -2,6 +2,8 @@ use anchor_lang::prelude::*;
mod pc;
use pc::Price;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod pyth {
use super::*;

View File

@ -2,5 +2,8 @@
cluster = "localnet"
wallet = "~/.config/solana/id.json"
[programs.localnet]
token_proxy = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
[scripts]
test = "mocha -t 1000000 tests/"

View File

@ -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::*;

View File

@ -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"

View File

@ -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::*;

View File

@ -2,5 +2,8 @@
cluster = "localnet"
wallet = "~/.config/solana/id.json"
[programs.localnet]
sysvars = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
[scripts]
test = "mocha -t 1000000 tests/"

View File

@ -1,5 +1,7 @@
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
mod sysvars {
use super::*;

View File

@ -2,6 +2,9 @@
cluster = "localnet"
wallet = "~/.config/solana/id.json"
[programs.localnet]
typescript = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
[workspace]
members = ["programs/typescript"]

View File

@ -3,6 +3,8 @@
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod typescript {
use super::*;

View File

@ -80,6 +80,8 @@ const LangErrorCode = {
AccountNotEnoughKeys: 165,
AccountNotMutable: 166,
AccountNotProgramOwned: 167,
InvalidProgramId: 168,
InvalidProgramIdExecutable: 169,
// State.
StateInvalidAddress: 180,
@ -159,6 +161,11 @@ 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.
[