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}