2021-06-08 07:50:43 -07:00
#![ feature(const_generics) ]
#![ feature(const_generics_defaults) ]
#![ allow(warnings) ]
//! Client-specific code
pub use solana_program ::pubkey ::Pubkey ;
pub use solana_sdk ;
pub use solana_sdk ::{
instruction ::{
AccountMeta ,
Instruction ,
} ,
signature ::{
Keypair ,
Signer as SolSigner ,
} ,
} ;
use borsh ::BorshSerialize ;
use solitaire ::AccountState ;
pub use solitaire ::{
Data ,
Derive ,
Keyed ,
Owned ,
Signer ,
} ;
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-06-08 07:50:43 -07:00
CPIProgram ( Pubkey ) ,
2021-06-11 05:29:43 -07:00
/// Program addresses for privileged cross calls
2021-06-08 07:50:43 -07:00
CPIProgramSigner ( Keypair ) ,
2021-06-11 05:29:43 -07:00
/// Key decided from SPL constants
2021-06-08 07:50:43 -07:00
Sysvar ,
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 ) ,
}
/// Types implementing Wrap are those that can be turned into a
2021-06-11 05:29:43 -07:00
/// 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
/// variants, they should override this.
fn keypair ( a : AccEntry ) -> Option < Keypair > {
use AccEntry ::* ;
match a {
Signer ( pair ) = > Some ( pair ) ,
SignerRO ( pair ) = > Some ( pair ) ,
_other = > None ,
}
}
}
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 ) = > {
let ( k , extra_seed ) = Pubkey ::find_program_address ( & [ Seed . as_bytes ( ) ] , & program_id ) ;
Ok ( vec! [ AccountMeta ::new ( k , false ) ] )
}
AccEntry ::DerivedRO ( program_id ) = > {
let ( k , extra_seed ) = Pubkey ::find_program_address ( & [ Seed . as_bytes ( ) ] , & program_id ) ;
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
} ,
Uninitialized = > match a {
Unprivileged ( k ) = > Ok ( vec! [ AccountMeta ::new ( * k , false ) ] ) ,
Signer ( pair ) = > Ok ( vec! [ AccountMeta ::new ( pair . pubkey ( ) , true ) ] ) ,
2021-06-14 09:58:12 -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 ( ) )
}
2021-06-11 05:29:43 -07:00
MaybeInitialized = > match a {
Unprivileged ( k ) = > Ok ( vec! [ AccountMeta ::new ( * k , false ) ] ) ,
Signer ( pair ) = > Ok ( vec! [ AccountMeta ::new ( pair . pubkey ( ) , true ) ] ) ,
2021-06-14 09:58:12 -07:00
_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-11 05:29:43 -07:00
}
2021-06-08 07:50:43 -07:00
}
}
/// Trait used on client side to easily validate a program accounts + ix_data for a bare Solana call
pub trait ToInstruction {
fn to_ix (
self ,
program_id : Pubkey ,
ix_data : & [ u8 ] ,
) -> StdResult < ( Instruction , Vec < Keypair > ) , ErrBox > ;
}