light_sdk/address.rs
1//! ## Addresses
2//! Address seed is 32 bytes. Multiple seeds are hashed
3//! into a single 32 bytes seed that is passed into the light system program for address creation.
4//! Addresses are created independently from compressed accounts.
5//! This means that an address can be used in a compressed account but does not have to be used.
6//!
7//! ### Address uniqueness
8//! Every address can only be created once per address tree.
9//! Addresses over all address trees are unique but
10//! address seeds can be reused in different address trees.
11//! If your program security requires global address uniqueness over all address trees,
12//! the used address Merkle tree must be checked.
13//! If your program just requires addresses to identify accounts but not uniqueness over all address trees
14//! the used address Merkle tree does not need to be checked.
15//!
16//!
17//! ### Create address example
18//! ```ignore
19//! let packed_address_tree_info = instruction_data.address_tree_info;
20//! let tree_accounts = cpi_accounts.tree_accounts();
21//!
22//! let address_tree_pubkey = tree_accounts[address_tree_info
23//! .address_merkle_tree_pubkey_index as usize]
24//! .key();
25//!
26//! let (address, address_seed) = derive_address(
27//! &[b"counter"],
28//! &address_tree_pubkey,
29//! &crate::ID,
30//! );
31//!
32//! // Used in cpi to light-system program
33//! // to insert the new address into the address merkle tree.
34//! let new_address_params = packed_address_tree_info
35//! .into_new_address_params_packed(address_seed);
36//! ```
37
38pub use light_compressed_account::instruction_data::data::NewAddressParams;
39/// Struct passed into the light system program cpi to create a new address.
40pub use light_compressed_account::instruction_data::data::NewAddressParamsPacked as PackedNewAddressParams;
41#[cfg(feature = "v2")]
42pub use light_compressed_account::instruction_data::data::{
43 NewAddressParamsAssigned, NewAddressParamsAssignedPacked, PackedReadOnlyAddress,
44 ReadOnlyAddress,
45};
46pub use light_sdk_types::address::AddressSeed;
47
48pub mod v1 {
49
50 use light_sdk_types::address::AddressSeed;
51
52 use crate::Pubkey;
53
54 /// Derives a single address seed for a compressed account, based on the
55 /// provided multiple `seeds`, `program_id` and `address_tree_pubkey`.
56 ///
57 /// # Examples
58 ///
59 /// ```ignore
60 /// use light_sdk::{address::derive_address, pubkey};
61 ///
62 /// let address = derive_address(
63 /// &[b"my_compressed_account"],
64 /// &crate::ID,
65 /// );
66 /// ```
67 pub fn derive_address_seed(seeds: &[&[u8]], program_id: &Pubkey) -> AddressSeed {
68 light_sdk_types::address::v1::derive_address_seed(seeds, &program_id.to_bytes())
69 }
70
71 /// Derives an address from provided seeds. Returns that address and a singular
72 /// seed.
73 ///
74 /// # Examples
75 ///
76 /// ```ignore
77 /// use light_sdk::{address::derive_address, pubkey};
78 ///
79 /// let address_tree_info = {
80 /// address_merkle_tree_pubkey: pubkey!("amt1Ayt45jfbdw5YSo7iz6WZxUmnZsQTYXy82hVwyC2"),
81 /// address_queue_pubkey: pubkey!("aq1S9z4reTSQAdgWHGD2zDaS39sjGrAxbR31vxJ2F4F"),
82 /// };
83 /// let (address, address_seed) = derive_address(
84 /// &[b"my_compressed_account"],
85 /// &address_tree_info,
86 /// &crate::ID,
87 /// );
88 /// ```
89 pub fn derive_address(
90 seeds: &[&[u8]],
91 address_tree_pubkey: &Pubkey,
92 program_id: &Pubkey,
93 ) -> ([u8; 32], AddressSeed) {
94 light_sdk_types::address::v1::derive_address(
95 seeds,
96 &address_tree_pubkey.to_bytes(),
97 &program_id.to_bytes(),
98 )
99 }
100}
101
102#[cfg(feature = "v2")]
103pub mod v2 {
104 use light_sdk_types::address::AddressSeed;
105 use solana_pubkey::Pubkey;
106
107 /// Derives a single address seed for a compressed account, based on the
108 /// provided multiple `seeds`, and `address_tree_pubkey`.
109 ///
110 /// # Examples
111 ///
112 /// ```rust
113 /// use light_sdk::address::v2::derive_address_seed;
114 ///
115 /// let address = derive_address_seed(
116 /// &[b"my_compressed_account".as_slice()],
117 /// );
118 /// ```
119 pub fn derive_address_seed(seeds: &[&[u8]]) -> AddressSeed {
120 light_sdk_types::address::v2::derive_address_seed(seeds)
121 }
122
123 /// Derives an address for a compressed account, based on the provided singular
124 /// `seed` and `address_tree_pubkey`:
125 pub fn derive_address_from_seed(
126 address_seed: &AddressSeed,
127 address_tree_pubkey: &Pubkey,
128 program_id: &Pubkey,
129 ) -> [u8; 32] {
130 light_sdk_types::address::v2::derive_address_from_seed(
131 address_seed,
132 &address_tree_pubkey.to_bytes(),
133 &program_id.to_bytes(),
134 )
135 }
136
137 /// Derive address from PDA using Pubkey types.
138 pub fn derive_compressed_address(
139 account_address: &Pubkey,
140 address_tree_pubkey: &Pubkey,
141 program_id: &Pubkey,
142 ) -> [u8; 32] {
143 derive_address(
144 &[account_address.to_bytes().as_ref()],
145 address_tree_pubkey,
146 program_id,
147 )
148 .0
149 }
150
151 /// Derives an address from provided seeds. Returns that address and a singular
152 /// seed.
153 ///
154 /// # Examples
155 ///
156 /// ```rust
157 /// use light_sdk::{address::v2::derive_address};
158 /// use solana_pubkey::pubkey;
159 ///
160 /// let program_id = pubkey!("GRLu2hKaAiMbxpkAM1HeXzks9YeGuz18SEgXEizVvPqX");
161 /// let address_tree_pubkey = pubkey!("amt2kaJA14v3urZbZvnc5v2np8jqvc4Z8zDep5wbtzx");
162 ///
163 /// let (address, address_seed) = derive_address(
164 /// &[b"my_compressed_account".as_slice()],
165 /// &address_tree_pubkey,
166 /// &program_id,
167 /// );
168 /// ```
169 pub fn derive_address(
170 seeds: &[&[u8]],
171 address_tree_pubkey: &Pubkey,
172 program_id: &Pubkey,
173 ) -> ([u8; 32], AddressSeed) {
174 light_sdk_types::address::v2::derive_address(
175 seeds,
176 &address_tree_pubkey.to_bytes(),
177 &program_id.to_bytes(),
178 )
179 }
180}
181
182#[cfg(test)]
183mod test {
184 use solana_pubkey::pubkey;
185
186 use super::v1::*;
187 use crate::instruction::AddressTreeInfo;
188
189 #[test]
190 fn test_derive_address_seed() {
191 let program_id = pubkey!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
192
193 let address_seed = derive_address_seed(&[b"foo", b"bar"], &program_id);
194 assert_eq!(
195 address_seed,
196 [
197 0, 246, 150, 3, 192, 95, 53, 123, 56, 139, 206, 179, 253, 133, 115, 103, 120, 155,
198 251, 72, 250, 47, 117, 217, 118, 59, 174, 207, 49, 101, 201, 110
199 ]
200 .into()
201 );
202
203 let address_seed = derive_address_seed(&[b"ayy", b"lmao"], &program_id);
204 assert_eq!(
205 address_seed,
206 [
207 0, 202, 44, 25, 221, 74, 144, 92, 69, 168, 38, 19, 206, 208, 29, 162, 53, 27, 120,
208 214, 152, 116, 15, 107, 212, 168, 33, 121, 187, 10, 76, 233
209 ]
210 .into()
211 );
212 }
213
214 #[test]
215 fn test_derive_address() {
216 let address_tree_info = AddressTreeInfo {
217 tree: pubkey!("11111111111111111111111111111111"),
218 queue: pubkey!("22222222222222222222222222222222222222222222"),
219 };
220 let program_id = pubkey!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
221
222 let seeds: &[&[u8]] = &[b"foo", b"bar"];
223 let expected_address_seed = [
224 0, 246, 150, 3, 192, 95, 53, 123, 56, 139, 206, 179, 253, 133, 115, 103, 120, 155, 251,
225 72, 250, 47, 117, 217, 118, 59, 174, 207, 49, 101, 201, 110,
226 ];
227 let expected_address = pubkey!("139uhyyBtEh4e1CBDJ68ooK5nCeWoncZf9HPyAfRrukA");
228
229 let address_seed = derive_address_seed(seeds, &program_id);
230 assert_eq!(address_seed, expected_address_seed.into());
231 let (address, address_seed) = derive_address(seeds, &address_tree_info.tree, &program_id);
232 assert_eq!(address_seed, expected_address_seed.into());
233 assert_eq!(address, expected_address.to_bytes());
234
235 let seeds: &[&[u8]] = &[b"ayy", b"lmao"];
236 let expected_address_seed = [
237 0, 202, 44, 25, 221, 74, 144, 92, 69, 168, 38, 19, 206, 208, 29, 162, 53, 27, 120, 214,
238 152, 116, 15, 107, 212, 168, 33, 121, 187, 10, 76, 233,
239 ];
240 let expected_address = pubkey!("12bhHm6PQjbNmEn3Yu1Gq9k7XwVn2rZpzYokmLwbFazN");
241
242 let address_seed = derive_address_seed(seeds, &program_id);
243 assert_eq!(address_seed, expected_address_seed.into());
244 let (address, address_seed) = derive_address(seeds, &address_tree_info.tree, &program_id);
245 assert_eq!(address_seed, expected_address_seed.into());
246 assert_eq!(address, expected_address.to_bytes());
247 }
248}