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 /// Derives an address from provided seeds. Returns that address and a singular
138 /// seed.
139 ///
140 /// # Examples
141 ///
142 /// ```rust
143 /// use light_sdk::{address::v2::derive_address};
144 /// use solana_pubkey::pubkey;
145 ///
146 /// let program_id = pubkey!("GRLu2hKaAiMbxpkAM1HeXzks9YeGuz18SEgXEizVvPqX");
147 /// let address_tree_pubkey = pubkey!("amt2kaJA14v3urZbZvnc5v2np8jqvc4Z8zDep5wbtzx");
148 ///
149 /// let (address, address_seed) = derive_address(
150 /// &[b"my_compressed_account".as_slice()],
151 /// &address_tree_pubkey,
152 /// &program_id,
153 /// );
154 /// ```
155 pub fn derive_address(
156 seeds: &[&[u8]],
157 address_tree_pubkey: &Pubkey,
158 program_id: &Pubkey,
159 ) -> ([u8; 32], AddressSeed) {
160 light_sdk_types::address::v2::derive_address(
161 seeds,
162 &address_tree_pubkey.to_bytes(),
163 &program_id.to_bytes(),
164 )
165 }
166}
167
168#[cfg(test)]
169mod test {
170 use solana_pubkey::pubkey;
171
172 use super::v1::*;
173 use crate::instruction::AddressTreeInfo;
174
175 #[test]
176 fn test_derive_address_seed() {
177 let program_id = pubkey!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
178
179 let address_seed = derive_address_seed(&[b"foo", b"bar"], &program_id);
180 assert_eq!(
181 address_seed,
182 [
183 0, 246, 150, 3, 192, 95, 53, 123, 56, 139, 206, 179, 253, 133, 115, 103, 120, 155,
184 251, 72, 250, 47, 117, 217, 118, 59, 174, 207, 49, 101, 201, 110
185 ]
186 .into()
187 );
188
189 let address_seed = derive_address_seed(&[b"ayy", b"lmao"], &program_id);
190 assert_eq!(
191 address_seed,
192 [
193 0, 202, 44, 25, 221, 74, 144, 92, 69, 168, 38, 19, 206, 208, 29, 162, 53, 27, 120,
194 214, 152, 116, 15, 107, 212, 168, 33, 121, 187, 10, 76, 233
195 ]
196 .into()
197 );
198 }
199
200 #[test]
201 fn test_derive_address() {
202 let address_tree_info = AddressTreeInfo {
203 tree: pubkey!("11111111111111111111111111111111"),
204 queue: pubkey!("22222222222222222222222222222222222222222222"),
205 };
206 let program_id = pubkey!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
207
208 let seeds: &[&[u8]] = &[b"foo", b"bar"];
209 let expected_address_seed = [
210 0, 246, 150, 3, 192, 95, 53, 123, 56, 139, 206, 179, 253, 133, 115, 103, 120, 155, 251,
211 72, 250, 47, 117, 217, 118, 59, 174, 207, 49, 101, 201, 110,
212 ];
213 let expected_address = pubkey!("139uhyyBtEh4e1CBDJ68ooK5nCeWoncZf9HPyAfRrukA");
214
215 let address_seed = derive_address_seed(seeds, &program_id);
216 assert_eq!(address_seed, expected_address_seed.into());
217 let (address, address_seed) = derive_address(seeds, &address_tree_info.tree, &program_id);
218 assert_eq!(address_seed, expected_address_seed.into());
219 assert_eq!(address, expected_address.to_bytes());
220
221 let seeds: &[&[u8]] = &[b"ayy", b"lmao"];
222 let expected_address_seed = [
223 0, 202, 44, 25, 221, 74, 144, 92, 69, 168, 38, 19, 206, 208, 29, 162, 53, 27, 120, 214,
224 152, 116, 15, 107, 212, 168, 33, 121, 187, 10, 76, 233,
225 ];
226 let expected_address = pubkey!("12bhHm6PQjbNmEn3Yu1Gq9k7XwVn2rZpzYokmLwbFazN");
227
228 let address_seed = derive_address_seed(seeds, &program_id);
229 assert_eq!(address_seed, expected_address_seed.into());
230 let (address, address_seed) = derive_address(seeds, &address_tree_info.tree, &program_id);
231 assert_eq!(address_seed, expected_address_seed.into());
232 assert_eq!(address, expected_address.to_bytes());
233 }
234}