context.rs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. use crate::{Accounts, ToAccountInfos, ToAccountMetas};
  2. use solana_program::account_info::AccountInfo;
  3. use solana_program::instruction::AccountMeta;
  4. use solana_program::pubkey::Pubkey;
  5. /// Provides non-argument inputs to the program.
  6. pub struct Context<'a, 'b, 'c, 'info, T> {
  7. /// Currently executing program id.
  8. pub program_id: &'a Pubkey,
  9. /// Deserialized accounts.
  10. pub accounts: &'b mut T,
  11. /// Remaining accounts given but not deserialized or validated.
  12. /// Be very careful when using this directly.
  13. pub remaining_accounts: &'c [AccountInfo<'info>],
  14. }
  15. impl<'a, 'b, 'c, 'info, T: Accounts<'info>> Context<'a, 'b, 'c, 'info, T> {
  16. pub fn new(
  17. program_id: &'a Pubkey,
  18. accounts: &'b mut T,
  19. remaining_accounts: &'c [AccountInfo<'info>],
  20. ) -> Self {
  21. Self {
  22. program_id,
  23. accounts,
  24. remaining_accounts,
  25. }
  26. }
  27. }
  28. /// Context specifying non-argument inputs for cross-program-invocations.
  29. pub struct CpiContext<'a, 'b, 'c, 'info, T>
  30. where
  31. T: ToAccountMetas + ToAccountInfos<'info>,
  32. {
  33. pub accounts: T,
  34. pub remaining_accounts: Vec<AccountInfo<'info>>,
  35. pub program: AccountInfo<'info>,
  36. pub signer_seeds: &'a [&'b [&'c [u8]]],
  37. }
  38. impl<'a, 'b, 'c, 'info, T> CpiContext<'a, 'b, 'c, 'info, T>
  39. where
  40. T: ToAccountMetas + ToAccountInfos<'info>,
  41. {
  42. pub fn new(program: AccountInfo<'info>, accounts: T) -> Self {
  43. Self {
  44. accounts,
  45. program,
  46. remaining_accounts: Vec::new(),
  47. signer_seeds: &[],
  48. }
  49. }
  50. pub fn new_with_signer(
  51. program: AccountInfo<'info>,
  52. accounts: T,
  53. signer_seeds: &'a [&'b [&'c [u8]]],
  54. ) -> Self {
  55. Self {
  56. accounts,
  57. program,
  58. signer_seeds,
  59. remaining_accounts: Vec::new(),
  60. }
  61. }
  62. pub fn with_signer(mut self, signer_seeds: &'a [&'b [&'c [u8]]]) -> Self {
  63. self.signer_seeds = signer_seeds;
  64. self
  65. }
  66. pub fn with_remaining_accounts(mut self, ra: Vec<AccountInfo<'info>>) -> Self {
  67. self.remaining_accounts = ra;
  68. self
  69. }
  70. }
  71. impl<'info, T: Accounts<'info>> ToAccountInfos<'info> for CpiContext<'_, '_, '_, 'info, T> {
  72. fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
  73. let mut infos = self.accounts.to_account_infos();
  74. infos.extend_from_slice(&self.remaining_accounts);
  75. infos.push(self.program.clone());
  76. infos
  77. }
  78. }
  79. impl<'info, T: Accounts<'info>> ToAccountMetas for CpiContext<'_, '_, '_, 'info, T> {
  80. fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
  81. let mut metas = self.accounts.to_account_metas(is_signer);
  82. metas.append(
  83. &mut self
  84. .remaining_accounts
  85. .iter()
  86. .map(|acc| match acc.is_writable {
  87. false => AccountMeta::new_readonly(*acc.key, acc.is_signer),
  88. true => AccountMeta::new(*acc.key, acc.is_signer),
  89. })
  90. .collect(),
  91. );
  92. metas
  93. }
  94. }
  95. /// Context specifying non-argument inputs for cross-program-invocations
  96. /// targeted at program state instructions.
  97. pub struct CpiStateContext<'a, 'b, 'c, 'info, T: Accounts<'info>> {
  98. state: AccountInfo<'info>,
  99. cpi_ctx: CpiContext<'a, 'b, 'c, 'info, T>,
  100. }
  101. impl<'a, 'b, 'c, 'info, T: Accounts<'info>> CpiStateContext<'a, 'b, 'c, 'info, T> {
  102. pub fn new(program: AccountInfo<'info>, state: AccountInfo<'info>, accounts: T) -> Self {
  103. Self {
  104. state,
  105. cpi_ctx: CpiContext {
  106. accounts,
  107. program,
  108. signer_seeds: &[],
  109. remaining_accounts: Vec::new(),
  110. },
  111. }
  112. }
  113. pub fn new_with_signer(
  114. program: AccountInfo<'info>,
  115. state: AccountInfo<'info>,
  116. accounts: T,
  117. signer_seeds: &'a [&'b [&'c [u8]]],
  118. ) -> Self {
  119. Self {
  120. state,
  121. cpi_ctx: CpiContext {
  122. accounts,
  123. program,
  124. signer_seeds,
  125. remaining_accounts: Vec::new(),
  126. },
  127. }
  128. }
  129. pub fn with_signer(mut self, signer_seeds: &'a [&'b [&'c [u8]]]) -> Self {
  130. self.cpi_ctx = self.cpi_ctx.with_signer(signer_seeds);
  131. self
  132. }
  133. pub fn program(&self) -> &AccountInfo<'info> {
  134. &self.cpi_ctx.program
  135. }
  136. pub fn signer_seeds(&self) -> &[&[&[u8]]] {
  137. self.cpi_ctx.signer_seeds
  138. }
  139. }
  140. impl<'a, 'b, 'c, 'info, T: Accounts<'info>> ToAccountMetas
  141. for CpiStateContext<'a, 'b, 'c, 'info, T>
  142. {
  143. fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
  144. // State account is always first for state instructions.
  145. let mut metas = vec![match self.state.is_writable {
  146. false => AccountMeta::new_readonly(*self.state.key, false),
  147. true => AccountMeta::new(*self.state.key, false),
  148. }];
  149. metas.append(&mut self.cpi_ctx.accounts.to_account_metas(is_signer));
  150. metas
  151. }
  152. }
  153. impl<'a, 'b, 'c, 'info, T: Accounts<'info>> ToAccountInfos<'info>
  154. for CpiStateContext<'a, 'b, 'c, 'info, T>
  155. {
  156. fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
  157. let mut infos = self.cpi_ctx.accounts.to_account_infos();
  158. infos.push(self.state.clone());
  159. infos.push(self.cpi_ctx.program.clone());
  160. infos
  161. }
  162. }