lib.rs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #![feature(adt_const_params)]
  2. #![feature(const_generics_defaults)]
  3. #![allow(warnings)]
  4. //! Client-specific code
  5. pub use solana_program::pubkey::Pubkey;
  6. use solana_program::sysvar::Sysvar as SolSysvar;
  7. pub use solana_sdk;
  8. pub use solana_sdk::{
  9. instruction::{
  10. AccountMeta,
  11. Instruction,
  12. },
  13. signature::{
  14. Keypair,
  15. Signer as SolSigner,
  16. },
  17. };
  18. use borsh::BorshSerialize;
  19. pub use solitaire::{
  20. processors::seeded::Seeded,
  21. Data,
  22. Derive,
  23. Keyed,
  24. Owned,
  25. Signer,
  26. };
  27. use solitaire::{
  28. AccountState,
  29. Info,
  30. Mut,
  31. Sysvar,
  32. };
  33. type StdResult<T, E> = std::result::Result<T, E>;
  34. pub type ErrBox = Box<dyn std::error::Error>;
  35. /// The sum type for clearly specifying the accounts required on client side.
  36. #[derive(Debug)]
  37. pub enum AccEntry {
  38. /// Least privileged account.
  39. Unprivileged(Pubkey),
  40. /// Least privileged account, read-only.
  41. UnprivilegedRO(Pubkey),
  42. /// Accounts that need to sign a Solana call
  43. Signer(Keypair),
  44. /// Accounts that need to sign a Solana call, read-only.
  45. SignerRO(Keypair),
  46. /// Program addresses for unprivileged cross calls
  47. CPIProgram(Pubkey),
  48. /// Program addresses for privileged cross calls
  49. CPIProgramSigner(Keypair),
  50. /// Key decided from SPL constants
  51. Sysvar(Pubkey),
  52. /// Key derived from constants and/or program address
  53. Derived(Pubkey),
  54. /// Key derived from constants and/or program address, read-only.
  55. DerivedRO(Pubkey),
  56. /// Empty value for nullables
  57. Empty,
  58. }
  59. /// Types implementing Wrap are those that can be turned into a
  60. /// partial account vector for a program call.
  61. pub trait Wrap {
  62. fn wrap(_: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox>;
  63. /// If the implementor wants to sign using other AccEntry
  64. /// variants, they should override this.
  65. fn keypair(a: AccEntry) -> Option<Keypair> {
  66. use AccEntry::*;
  67. match a {
  68. Signer(pair) => Some(pair),
  69. SignerRO(pair) => Some(pair),
  70. _other => None,
  71. }
  72. }
  73. }
  74. impl<T: Wrap> Wrap for Option<T> {
  75. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  76. match a {
  77. AccEntry::Empty => Ok(vec![AccountMeta::new_readonly(Pubkey::new_from_array([0u8; 32]), false)]),
  78. other => T::wrap(other)
  79. }
  80. }
  81. }
  82. impl<'a, 'b: 'a, T> Wrap for Signer<T>
  83. where
  84. T: Keyed<'a, 'b>,
  85. {
  86. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  87. use AccEntry::*;
  88. match a {
  89. Signer(pair) => Ok(vec![AccountMeta::new(pair.pubkey(), true)]),
  90. SignerRO(pair) => Ok(vec![AccountMeta::new_readonly(pair.pubkey(), true)]),
  91. other => Err(format!(
  92. "{} must be passed as Signer or SignerRO",
  93. std::any::type_name::<Self>()
  94. )
  95. .into()),
  96. }
  97. }
  98. }
  99. impl<'a, 'b: 'a, T, const Seed: &'static str> Wrap for Derive<T, Seed> {
  100. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  101. match a {
  102. AccEntry::Derived(program_id) => {
  103. let k = Self::key(None, program_id);
  104. Ok(vec![AccountMeta::new(k, false)])
  105. }
  106. AccEntry::DerivedRO(program_id) => {
  107. let k = Self::key(None, program_id);
  108. Ok(vec![AccountMeta::new_readonly(k, false)])
  109. }
  110. other => Err(format!(
  111. "{} must be passed as Derived or DerivedRO",
  112. std::any::type_name::<Self>()
  113. )
  114. .into()),
  115. }
  116. }
  117. }
  118. impl<'a, T, const IsInitialized: AccountState> Wrap for Data<'a, T, IsInitialized>
  119. where
  120. T: BorshSerialize + Owned + Default,
  121. {
  122. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  123. use AccEntry::*;
  124. use AccountState::*;
  125. match IsInitialized {
  126. Initialized => match a {
  127. Unprivileged(k) => Ok(vec![AccountMeta::new(*k, false)]),
  128. UnprivilegedRO(k) => Ok(vec![AccountMeta::new_readonly(*k, false)]),
  129. Signer(pair) => Ok(vec![AccountMeta::new(pair.pubkey(), true)]),
  130. SignerRO(pair) => Ok(vec![AccountMeta::new_readonly(pair.pubkey(), true)]),
  131. _other => Err(format!("{} with IsInitialized = {:?} must be passed as Unprivileged, Signer or the respective read-only variant", std::any::type_name::<Self>(), a).into())
  132. },
  133. Uninitialized => match a {
  134. Unprivileged(k) => Ok(vec![AccountMeta::new(*k, false)]),
  135. Signer(pair) => Ok(vec![AccountMeta::new(pair.pubkey(), true)]),
  136. _other => Err(format!("{} with IsInitialized = {:?} must be passed as Unprivileged or Signer (write access required for initialization)", std::any::type_name::<Self>(), a).into())
  137. }
  138. MaybeInitialized => match a {
  139. Unprivileged(k) => Ok(vec![AccountMeta::new(*k, false)]),
  140. Signer(pair) => Ok(vec![AccountMeta::new(pair.pubkey(), true)]),
  141. _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())
  142. }
  143. }
  144. }
  145. }
  146. impl<'b, Var> Wrap for Sysvar<'b, Var>
  147. where
  148. Var: SolSysvar,
  149. {
  150. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  151. if let AccEntry::Sysvar(k) = a {
  152. if Var::check_id(k) {
  153. Ok(vec![AccountMeta::new_readonly(k.clone(), false)])
  154. } else {
  155. Err(format!(
  156. "{} does not point at sysvar {}",
  157. k,
  158. std::any::type_name::<Var>()
  159. )
  160. .into())
  161. }
  162. } else {
  163. Err(format!("{} must be passed as Sysvar", std::any::type_name::<Self>()).into())
  164. }
  165. }
  166. }
  167. impl<'b> Wrap for Info<'b> {
  168. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  169. match a {
  170. AccEntry::UnprivilegedRO(k) => Ok(vec![AccountMeta::new_readonly(k.clone(), false)]),
  171. AccEntry::Unprivileged(k) => Ok(vec![AccountMeta::new(k.clone(), false)]),
  172. _other => Err(format!(
  173. "{} must be passed as Unprivileged or UnprivilegedRO",
  174. std::any::type_name::<Self>()
  175. )
  176. .into()),
  177. }
  178. }
  179. }
  180. impl<T: Wrap> Wrap for Mut<T> {
  181. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  182. match a {
  183. AccEntry::Unprivileged(_) | AccEntry::Signer(_) | AccEntry::Derived(_) => {
  184. Ok(T::wrap(a)?)
  185. }
  186. _other => Err(format!(
  187. "{} must be passed as Unprivileged, Signer or Derived (Must be mutable on-chain)",
  188. std::any::type_name::<Self>()
  189. )
  190. .into()),
  191. }
  192. }
  193. }
  194. /// Trait used on client side to easily validate a program accounts + ix_data for a bare Solana call
  195. pub trait ToInstruction {
  196. fn to_ix(
  197. self,
  198. program_id: Pubkey,
  199. ix_data: &[u8],
  200. ) -> StdResult<(Instruction, Vec<Keypair>), ErrBox>;
  201. }