poseidon_client/transactions/
pda.rs1use crate::{
2 AccountMeta, Instruction, PdaPublicKey, PoseidonError, PoseidonResult, PublicKey,
3 SystemInstruction, MAX_SEED_LEN, PDA_MARKER,
4};
5use core::fmt;
6use serde::{Deserialize, Serialize};
7
8#[derive(Serialize, Deserialize)]
24pub struct PdaBuilder {
25 from_public_key: PublicKey,
26 to_public_key: PublicKey,
27 base: PublicKey,
28 space: u64,
29 owner: PublicKey,
30 seed: String,
31 lamports: u64,
32}
33
34impl PdaBuilder {
35 pub fn new() -> Self {
36 PdaBuilder {
37 from_public_key: PublicKey::default(),
38 to_public_key: PublicKey::default(),
39 base: PublicKey::default(),
40 space: u64::default(),
41 owner: PublicKey::default(),
42 seed: String::default(),
43 lamports: u64::default(),
44 }
45 }
46
47 pub fn add_from(&mut self, public_key: PublicKey) -> &mut Self {
48 self.from_public_key = public_key;
49
50 self
51 }
52
53 pub fn add_base(&mut self, public_key: PublicKey) -> &mut Self {
54 self.base = public_key;
55
56 self
57 }
58
59 pub fn add_space(&mut self, space: u64) -> &mut Self {
60 self.space = space;
61
62 self
63 }
64
65 pub fn add_owner(&mut self, public_key: PublicKey) -> &mut Self {
66 self.owner = public_key;
67
68 self
69 }
70
71 pub fn add_seed(&mut self, seed: &str) -> &mut Self {
72 self.seed = seed.to_owned();
73
74 self
75 }
76
77 pub fn add_lamports(&mut self, lamports: u64) -> &mut Self {
78 self.lamports = lamports;
79
80 self
81 }
82
83 pub fn derive_public_key(&mut self) -> PoseidonResult<PdaPublicKey> {
84 use sha2::{Digest, Sha256};
85
86 if self.seed.len() > MAX_SEED_LEN {
87 return Err(PoseidonError::MaxSeedLengthExceeded);
88 }
89
90 if self.owner.len() >= PDA_MARKER.len() {
91 let slice = &self.owner[self.owner.len() - PDA_MARKER.len()..];
92 if slice == PDA_MARKER {
93 return Err(PoseidonError::IllegalOwner);
94 }
95 }
96
97 let mut hasher = Sha256::new();
98 hasher.update(&self.base);
99 hasher.update(&self.seed);
100 hasher.update(&self.owner);
101
102 let sha256_pda: [u8; 32] = hasher.finalize().into();
103
104 self.to_public_key = sha256_pda;
105
106 Ok(sha256_pda)
107 }
108
109 pub fn pda_pk_base58(&self) -> String {
110 bs58::encode(&self.to_public_key).into_string()
111 }
112
113 pub fn build(&self) -> PoseidonResult<Instruction> {
114 let system_instruction = SystemInstruction::CreateAccountWithSeed {
115 base: self.base,
116 seed: self.seed.to_owned(),
117 lamports: self.lamports,
118 space: self.space,
119 owner: self.owner,
120 };
121
122 let data = bincode::serialize(&system_instruction)?;
123
124 Ok(Instruction {
125 program_id: crate::SYSTEM_PROGRAM_ID,
126 accounts: vec![
127 AccountMeta::new(self.from_public_key, true),
128 AccountMeta::new(self.to_public_key, false),
129 AccountMeta::new_readonly(self.from_public_key, true),
130 ],
131 data,
132 })
133 }
134}
135
136impl fmt::Debug for PdaBuilder {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.debug_struct("PdaBuilder")
139 .field(
140 "from_public_key",
141 &bs58::encode(&self.from_public_key).into_string(),
142 )
143 .field(
144 "to_public_key",
145 &bs58::encode(&self.to_public_key).into_string(),
146 )
147 .field("base", &bs58::encode(&self.base).into_string())
148 .field("space", &self.space)
149 .field("owner", &bs58::encode(&self.owner).into_string())
150 .field("seed", &self.seed)
151 .field("lamports", &self.lamports)
152 .finish()
153 }
154}