2022-01-13 05:29:19 -08:00
#![ feature(adt_const_params) ]
2021-06-08 07:50:43 -07:00
#![ feature(const_generics_defaults) ]
#![ allow(warnings) ]
//! Client-specific code
pub use solana_program ::pubkey ::Pubkey ;
2021-06-16 03:09:06 -07:00
use solana_program ::sysvar ::Sysvar as SolSysvar ;
2021-06-08 07:50:43 -07:00
pub use solana_sdk ;
pub use solana_sdk ::{
instruction ::{
AccountMeta ,
Instruction ,
} ,
signature ::{
Keypair ,
Signer as SolSigner ,
} ,
} ;
use borsh ::BorshSerialize ;
pub use solitaire ::{
2021-08-02 05:52:24 -07:00
processors ::seeded ::Seeded ,
2021-06-08 07:50:43 -07:00
Data ,
Derive ,
Keyed ,
Owned ,
Signer ,
} ;
2021-08-02 05:52:24 -07:00
use solitaire ::{
AccountState ,
Info ,
Mut ,
Sysvar ,
} ;
2021-06-08 07:50:43 -07:00
type StdResult < T , E > = std ::result ::Result < T , E > ;
pub type ErrBox = Box < dyn std ::error ::Error > ;
/// The sum type for clearly specifying the accounts required on client side.
2021-06-11 05:29:43 -07:00
#[ derive(Debug) ]
2021-06-08 07:50:43 -07:00
pub enum AccEntry {
/// Least privileged account.
Unprivileged ( Pubkey ) ,
2021-06-11 05:29:43 -07:00
/// Least privileged account, read-only.
UnprivilegedRO ( Pubkey ) ,
2021-06-08 07:50:43 -07:00
/// Accounts that need to sign a Solana call
Signer ( Keypair ) ,
2021-06-11 05:29:43 -07:00
/// Accounts that need to sign a Solana call, read-only.
2021-06-08 07:50:43 -07:00
SignerRO ( Keypair ) ,
2021-06-11 05:29:43 -07:00
/// Program addresses for unprivileged cross calls
2021-07-15 06:22:50 -07:00
CPIProgram ( Pubkey ) ,
2021-06-11 05:29:43 -07:00
/// Program addresses for privileged cross calls
2021-07-15 06:22:50 -07:00
CPIProgramSigner ( Keypair ) ,
2021-06-08 07:50:43 -07:00
2021-06-11 05:29:43 -07:00
/// Key decided from SPL constants
2021-06-16 03:09:06 -07:00
Sysvar ( Pubkey ) ,
2021-06-11 05:29:43 -07:00
/// Key derived from constants and/or program address
2021-06-08 07:50:43 -07:00
Derived ( Pubkey ) ,
2021-06-11 05:29:43 -07:00
/// Key derived from constants and/or program address, read-only.
2021-06-08 07:50:43 -07:00
DerivedRO ( Pubkey ) ,
}
2021-07-15 06:22:50 -07:00
/// Types implementing Wrap are those that can be turned into a
/// partial account vector for a program call.
2021-06-08 07:50:43 -07:00
pub trait Wrap {
fn wrap ( _ : & AccEntry ) -> StdResult < Vec < AccountMeta > , ErrBox > ;
/// If the implementor wants to sign using other AccEntry
2021-07-15 06:22:50 -07:00
/// variants, they should override this.
fn keypair ( a : AccEntry ) -> Option < Keypair > {
2021-06-08 07:50:43 -07:00
use AccEntry ::* ;
match a {
2021-07-15 06:22:50 -07:00
Signer ( pair ) = > Some ( pair ) ,
SignerRO ( pair ) = > Some ( pair ) ,
_other = > None ,
2021-06-08 07:50:43 -07:00
}
}
}
impl < ' a , ' b : ' a , T > Wrap for Signer < T >
where
T : Keyed < ' a , ' b > ,
{
fn wrap ( a : & AccEntry ) -> StdResult < Vec < AccountMeta > , ErrBox > {
use AccEntry ::* ;
match a {
Signer ( pair ) = > Ok ( vec! [ AccountMeta ::new ( pair . pubkey ( ) , true ) ] ) ,
SignerRO ( pair ) = > Ok ( vec! [ AccountMeta ::new_readonly ( pair . pubkey ( ) , true ) ] ) ,
other = > Err ( format! (
" {} must be passed as Signer or SignerRO " ,
std ::any ::type_name ::< Self > ( )
)
. into ( ) ) ,
}
}
}
impl < ' a , ' b : ' a , T , const Seed : & 'static str > Wrap for Derive < T , Seed > {
fn wrap ( a : & AccEntry ) -> StdResult < Vec < AccountMeta > , ErrBox > {
match a {
AccEntry ::Derived ( program_id ) = > {
2021-08-02 05:52:24 -07:00
let k = Self ::key ( None , program_id ) ;
2021-06-08 07:50:43 -07:00
Ok ( vec! [ AccountMeta ::new ( k , false ) ] )
}
AccEntry ::DerivedRO ( program_id ) = > {
2021-08-02 05:52:24 -07:00
let k = Self ::key ( None , program_id ) ;
2021-06-08 07:50:43 -07:00
Ok ( vec! [ AccountMeta ::new_readonly ( k , false ) ] )
}
other = > Err ( format! (
" {} must be passed as Derived or DerivedRO " ,
std ::any ::type_name ::< Self > ( )
)
. into ( ) ) ,
}
}
}
impl < ' a , T , const IsInitialized : AccountState > Wrap for Data < ' a , T , IsInitialized >
where
T : BorshSerialize + Owned + Default ,
{
fn wrap ( a : & AccEntry ) -> StdResult < Vec < AccountMeta > , ErrBox > {
2021-06-11 05:29:43 -07:00
use AccEntry ::* ;
use AccountState ::* ;
match IsInitialized {
Initialized = > match a {
Unprivileged ( k ) = > Ok ( vec! [ AccountMeta ::new ( * k , false ) ] ) ,
UnprivilegedRO ( k ) = > Ok ( vec! [ AccountMeta ::new_readonly ( * k , false ) ] ) ,
Signer ( pair ) = > Ok ( vec! [ AccountMeta ::new ( pair . pubkey ( ) , true ) ] ) ,
SignerRO ( pair ) = > Ok ( vec! [ AccountMeta ::new_readonly ( pair . pubkey ( ) , true ) ] ) ,
2021-06-14 09:58:12 -07:00
_other = > Err ( format! ( " {} with IsInitialized = {:?} must be passed as Unprivileged, Signer or the respective read-only variant " , std ::any ::type_name ::< Self > ( ) , a ) . into ( ) )
2021-06-11 05:29:43 -07:00
} ,
2021-07-15 06:22:50 -07:00
Uninitialized = > match a {
2021-06-11 05:29:43 -07:00
Unprivileged ( k ) = > Ok ( vec! [ AccountMeta ::new ( * k , false ) ] ) ,
Signer ( pair ) = > Ok ( vec! [ AccountMeta ::new ( pair . pubkey ( ) , true ) ] ) ,
2021-07-15 06:22:50 -07:00
_other = > Err ( format! ( " {} with IsInitialized = {:?} must be passed as Unprivileged or Signer (write access required for initialization) " , std ::any ::type_name ::< Self > ( ) , a ) . into ( ) )
}
MaybeInitialized = > match a {
Unprivileged ( k ) = > Ok ( vec! [ AccountMeta ::new ( * k , false ) ] ) ,
Signer ( pair ) = > Ok ( vec! [ AccountMeta ::new ( pair . pubkey ( ) , true ) ] ) ,
_other = > Err ( format! ( " {} with IsInitialized = {:?} must be passed as Unprivileged or Signer (write access required in case of initialization) " , std ::any ::type_name ::< Self > ( ) , a ) . into ( ) )
2021-06-14 09:58:12 -07:00
}
2021-06-11 05:29:43 -07:00
}
2021-06-08 07:50:43 -07:00
}
}
2021-06-16 03:09:06 -07:00
impl < ' b , Var > Wrap for Sysvar < ' b , Var >
where
Var : SolSysvar ,
{
fn wrap ( a : & AccEntry ) -> StdResult < Vec < AccountMeta > , ErrBox > {
if let AccEntry ::Sysvar ( k ) = a {
2021-06-18 05:34:31 -07:00
if Var ::check_id ( k ) {
Ok ( vec! [ AccountMeta ::new_readonly ( k . clone ( ) , false ) ] )
} else {
Err ( format! (
" {} does not point at sysvar {} " ,
k ,
std ::any ::type_name ::< Var > ( )
)
. into ( ) )
}
2021-06-16 03:09:06 -07:00
} else {
2021-06-18 05:34:31 -07:00
Err ( format! ( " {} must be passed as Sysvar " , std ::any ::type_name ::< Self > ( ) ) . into ( ) )
2021-06-16 03:09:06 -07:00
}
}
}
2021-06-25 07:05:03 -07:00
impl < ' b > Wrap for Info < ' b > {
fn wrap ( a : & AccEntry ) -> StdResult < Vec < AccountMeta > , ErrBox > {
match a {
AccEntry ::UnprivilegedRO ( k ) = > Ok ( vec! [ AccountMeta ::new_readonly ( k . clone ( ) , false ) ] ) ,
AccEntry ::Unprivileged ( k ) = > Ok ( vec! [ AccountMeta ::new ( k . clone ( ) , false ) ] ) ,
_other = > Err ( format! (
" {} must be passed as Unprivileged or UnprivilegedRO " ,
std ::any ::type_name ::< Self > ( )
)
. into ( ) ) ,
}
}
}
2021-08-02 05:52:24 -07:00
impl < T : Wrap > Wrap for Mut < T > {
fn wrap ( a : & AccEntry ) -> StdResult < Vec < AccountMeta > , ErrBox > {
match a {
AccEntry ::Unprivileged ( _ ) | AccEntry ::Signer ( _ ) | AccEntry ::Derived ( _ ) = > {
Ok ( T ::wrap ( a ) ? )
}
_other = > Err ( format! (
" {} must be passed as Unprivileged, Signer or Derived (Must be mutable on-chain) " ,
std ::any ::type_name ::< Self > ( )
)
. into ( ) ) ,
}
}
}
2021-07-15 06:22:50 -07:00
/// Trait used on client side to easily validate a program accounts + ix_data for a bare Solana call
pub trait ToInstruction {
2021-07-15 06:22:50 -07:00
fn to_ix (
2021-07-15 06:22:50 -07:00
self ,
2021-06-08 07:50:43 -07:00
program_id : Pubkey ,
ix_data : & [ u8 ] ,
) -> StdResult < ( Instruction , Vec < Keypair > ) , ErrBox > ;
}