lib.rs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. }
  57. /// Types implementing Wrap are those that can be turned into a
  58. /// partial account vector for a program call.
  59. pub trait Wrap {
  60. fn wrap(_: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox>;
  61. /// If the implementor wants to sign using other AccEntry
  62. /// variants, they should override this.
  63. fn keypair(a: AccEntry) -> Option<Keypair> {
  64. use AccEntry::*;
  65. match a {
  66. Signer(pair) => Some(pair),
  67. SignerRO(pair) => Some(pair),
  68. _other => None,
  69. }
  70. }
  71. }
  72. impl<'a, 'b: 'a, T> Wrap for Signer<T>
  73. where
  74. T: Keyed<'a, 'b>,
  75. {
  76. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  77. use AccEntry::*;
  78. match a {
  79. Signer(pair) => Ok(vec![AccountMeta::new(pair.pubkey(), true)]),
  80. SignerRO(pair) => Ok(vec![AccountMeta::new_readonly(pair.pubkey(), true)]),
  81. other => Err(format!(
  82. "{} must be passed as Signer or SignerRO",
  83. std::any::type_name::<Self>()
  84. )
  85. .into()),
  86. }
  87. }
  88. }
  89. impl<'a, 'b: 'a, T, const Seed: &'static str> Wrap for Derive<T, Seed> {
  90. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  91. match a {
  92. AccEntry::Derived(program_id) => {
  93. let k = Self::key(None, program_id);
  94. Ok(vec![AccountMeta::new(k, false)])
  95. }
  96. AccEntry::DerivedRO(program_id) => {
  97. let k = Self::key(None, program_id);
  98. Ok(vec![AccountMeta::new_readonly(k, false)])
  99. }
  100. other => Err(format!(
  101. "{} must be passed as Derived or DerivedRO",
  102. std::any::type_name::<Self>()
  103. )
  104. .into()),
  105. }
  106. }
  107. }
  108. impl<'a, T, const IsInitialized: AccountState> Wrap for Data<'a, T, IsInitialized>
  109. where
  110. T: BorshSerialize + Owned + Default,
  111. {
  112. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  113. use AccEntry::*;
  114. use AccountState::*;
  115. match IsInitialized {
  116. Initialized => match a {
  117. Unprivileged(k) => Ok(vec![AccountMeta::new(*k, false)]),
  118. UnprivilegedRO(k) => Ok(vec![AccountMeta::new_readonly(*k, false)]),
  119. Signer(pair) => Ok(vec![AccountMeta::new(pair.pubkey(), true)]),
  120. SignerRO(pair) => Ok(vec![AccountMeta::new_readonly(pair.pubkey(), true)]),
  121. _other => Err(format!("{} with IsInitialized = {:?} must be passed as Unprivileged, Signer or the respective read-only variant", std::any::type_name::<Self>(), a).into())
  122. },
  123. Uninitialized => match a {
  124. Unprivileged(k) => Ok(vec![AccountMeta::new(*k, false)]),
  125. Signer(pair) => Ok(vec![AccountMeta::new(pair.pubkey(), true)]),
  126. _other => Err(format!("{} with IsInitialized = {:?} must be passed as Unprivileged or Signer (write access required for initialization)", std::any::type_name::<Self>(), a).into())
  127. }
  128. MaybeInitialized => match a {
  129. Unprivileged(k) => Ok(vec![AccountMeta::new(*k, false)]),
  130. Signer(pair) => Ok(vec![AccountMeta::new(pair.pubkey(), true)]),
  131. _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())
  132. }
  133. }
  134. }
  135. }
  136. impl<'b, Var> Wrap for Sysvar<'b, Var>
  137. where
  138. Var: SolSysvar,
  139. {
  140. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  141. if let AccEntry::Sysvar(k) = a {
  142. if Var::check_id(k) {
  143. Ok(vec![AccountMeta::new_readonly(k.clone(), false)])
  144. } else {
  145. Err(format!(
  146. "{} does not point at sysvar {}",
  147. k,
  148. std::any::type_name::<Var>()
  149. )
  150. .into())
  151. }
  152. } else {
  153. Err(format!("{} must be passed as Sysvar", std::any::type_name::<Self>()).into())
  154. }
  155. }
  156. }
  157. impl<'b> Wrap for Info<'b> {
  158. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  159. match a {
  160. AccEntry::UnprivilegedRO(k) => Ok(vec![AccountMeta::new_readonly(k.clone(), false)]),
  161. AccEntry::Unprivileged(k) => Ok(vec![AccountMeta::new(k.clone(), false)]),
  162. _other => Err(format!(
  163. "{} must be passed as Unprivileged or UnprivilegedRO",
  164. std::any::type_name::<Self>()
  165. )
  166. .into()),
  167. }
  168. }
  169. }
  170. impl<T: Wrap> Wrap for Mut<T> {
  171. fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
  172. match a {
  173. AccEntry::Unprivileged(_) | AccEntry::Signer(_) | AccEntry::Derived(_) => {
  174. Ok(T::wrap(a)?)
  175. }
  176. _other => Err(format!(
  177. "{} must be passed as Unprivileged, Signer or Derived (Must be mutable on-chain)",
  178. std::any::type_name::<Self>()
  179. )
  180. .into()),
  181. }
  182. }
  183. }
  184. /// Trait used on client side to easily validate a program accounts + ix_data for a bare Solana call
  185. pub trait ToInstruction {
  186. fn to_ix(
  187. self,
  188. program_id: Pubkey,
  189. ix_data: &[u8],
  190. ) -> StdResult<(Instruction, Vec<Keypair>), ErrBox>;
  191. }