gmsol_solana_utils/
program_trait.rs1use solana_sdk::{
2 instruction::{AccountMeta, Instruction},
3 pubkey::Pubkey,
4};
5
6#[cfg(anchor_lang)]
7use anchor_lang::{Id, InstructionData, ToAccountMetas};
8
9pub trait Program {
11 fn id(&self) -> &Pubkey;
13}
14
15impl<P: Program> Program for &P {
16 fn id(&self) -> &Pubkey {
17 (**self).id()
18 }
19}
20
21pub trait ProgramExt: Program {
23 fn instruction(&self, data: Vec<u8>) -> InstructionBuilder<Self>
25 where
26 Self: Sized,
27 {
28 InstructionBuilder {
29 program: self,
30 data,
31 accounts: vec![],
32 }
33 }
34
35 #[cfg(anchor_lang)]
37 fn anchor_instruction(&self, args: impl InstructionData) -> InstructionBuilder<Self>
38 where
39 Self: Sized,
40 {
41 self.instruction(args.data())
42 }
43
44 #[cfg(anchor_lang)]
50 fn anchor_accounts(
51 &self,
52 accounts: impl ToAccountMetas,
53 convert_optional: bool,
54 ) -> Vec<AccountMeta>
55 where
56 Self: Id,
57 {
58 if convert_optional {
59 fix_optional_account_metas(accounts, &<Self as Id>::id(), self.id())
60 } else {
61 accounts.to_account_metas(None)
62 }
63 }
64}
65
66impl<P: ?Sized + Program> ProgramExt for P {}
67
68#[derive(Debug, Clone)]
70pub struct InstructionBuilder<'a, P> {
71 program: &'a P,
72 data: Vec<u8>,
73 accounts: Vec<AccountMeta>,
74}
75
76impl<P> InstructionBuilder<'_, P> {
77 pub fn accounts(mut self, mut accounts: Vec<AccountMeta>) -> Self {
79 self.accounts.append(&mut accounts);
80 self
81 }
82}
83
84impl<P: Program> InstructionBuilder<'_, P> {
85 pub fn build(self) -> Instruction {
87 Instruction {
88 program_id: *self.program.id(),
89 accounts: self.accounts,
90 data: self.data,
91 }
92 }
93}
94
95#[cfg(anchor_lang)]
96impl<P: Program + Id> InstructionBuilder<'_, P> {
97 pub fn anchor_accounts(self, accounts: impl ToAccountMetas, convert_optional: bool) -> Self {
99 let accounts = self.program.anchor_accounts(accounts, convert_optional);
100 self.accounts(accounts)
101 }
102}
103
104#[cfg(anchor_lang)]
115pub fn fix_optional_account_metas(
116 accounts: impl ToAccountMetas,
117 original: &Pubkey,
118 current: &Pubkey,
119) -> Vec<AccountMeta> {
120 let mut metas = accounts.to_account_metas(None);
121 if *original == *current {
122 return metas;
124 }
125 metas.iter_mut().for_each(|meta| {
126 if !meta.is_signer && !meta.is_writable && meta.pubkey == *original {
127 meta.pubkey = *current;
129 }
130 });
131 metas
132}