1use anchor_lang::{solana_program::pubkey::Pubkey, AnchorDeserialize, AnchorSerialize};
2use light_utils::{hash_to_bn254_field_size_be, hashv_to_bn254_field_size_be};
3
4use crate::merkle_context::{AddressMerkleContext, RemainingAccounts};
5
6#[derive(Debug, PartialEq, Default, Clone, AnchorDeserialize, AnchorSerialize)]
7pub struct NewAddressParams {
8 pub seed: [u8; 32],
9 pub address_queue_pubkey: Pubkey,
10 pub address_merkle_tree_pubkey: Pubkey,
11 pub address_merkle_tree_root_index: u16,
12}
13
14#[derive(Debug, PartialEq, Default, Clone, Copy, AnchorDeserialize, AnchorSerialize)]
15pub struct NewAddressParamsPacked {
16 pub seed: [u8; 32],
17 pub address_queue_account_index: u8,
18 pub address_merkle_tree_account_index: u8,
19 pub address_merkle_tree_root_index: u16,
20}
21
22pub struct AddressWithMerkleContext {
23 pub address: [u8; 32],
24 pub address_merkle_context: AddressMerkleContext,
25}
26
27pub fn pack_new_addresses_params(
28 addresses_params: &[NewAddressParams],
29 remaining_accounts: &mut RemainingAccounts,
30) -> Vec<NewAddressParamsPacked> {
31 addresses_params
32 .iter()
33 .map(|x| {
34 let address_queue_account_index =
35 remaining_accounts.insert_or_get(x.address_queue_pubkey);
36 let address_merkle_tree_account_index =
37 remaining_accounts.insert_or_get(x.address_merkle_tree_pubkey);
38 NewAddressParamsPacked {
39 seed: x.seed,
40 address_queue_account_index,
41 address_merkle_tree_account_index,
42 address_merkle_tree_root_index: x.address_merkle_tree_root_index,
43 }
44 })
45 .collect::<Vec<_>>()
46}
47
48pub fn pack_new_address_params(
49 address_params: NewAddressParams,
50 remaining_accounts: &mut RemainingAccounts,
51) -> NewAddressParamsPacked {
52 pack_new_addresses_params(&[address_params], remaining_accounts)[0]
53}
54
55pub fn derive_address_seed(seeds: &[&[u8]], program_id: &Pubkey) -> [u8; 32] {
69 let mut inputs = Vec::with_capacity(seeds.len() + 1);
70
71 let program_id = program_id.to_bytes();
72 inputs.push(program_id.as_slice());
73
74 inputs.extend(seeds);
75
76 let address = hashv_to_bn254_field_size_be(inputs.as_slice());
77 address
78}
79
80pub fn derive_address(
83 address_seed: &[u8; 32],
84 address_merkle_context: &AddressMerkleContext,
85) -> [u8; 32] {
86 let merkle_tree_pubkey = address_merkle_context.address_merkle_tree_pubkey.to_bytes();
87 let input = [merkle_tree_pubkey, *address_seed].concat();
88
89 hash_to_bn254_field_size_be(input.as_slice()).unwrap().0
93}
94
95#[cfg(test)]
96mod test {
97 use light_macros::pubkey;
98
99 use super::*;
100
101 #[test]
102 fn test_derive_address_seed() {
103 let program_id = pubkey!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
104
105 let address_seed = derive_address_seed(&[b"foo", b"bar"], &program_id);
106 assert_eq!(
107 address_seed,
108 [
109 0, 246, 150, 3, 192, 95, 53, 123, 56, 139, 206, 179, 253, 133, 115, 103, 120, 155,
110 251, 72, 250, 47, 117, 217, 118, 59, 174, 207, 49, 101, 201, 110
111 ]
112 );
113
114 let address_seed = derive_address_seed(&[b"ayy", b"lmao"], &program_id);
115 assert_eq!(
116 address_seed,
117 [
118 0, 202, 44, 25, 221, 74, 144, 92, 69, 168, 38, 19, 206, 208, 29, 162, 53, 27, 120,
119 214, 152, 116, 15, 107, 212, 168, 33, 121, 187, 10, 76, 233
120 ]
121 );
122 }
123
124 #[test]
125 fn test_derive_address() {
126 let address_merkle_context = AddressMerkleContext {
127 address_merkle_tree_pubkey: pubkey!("11111111111111111111111111111111"),
128 address_queue_pubkey: pubkey!("22222222222222222222222222222222222222222222"),
129 };
130 let program_id = pubkey!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
131
132 let address_seed = derive_address_seed(&[b"foo", b"bar"], &program_id);
133 let address = derive_address(&address_seed, &address_merkle_context);
134 let expected_address = pubkey!("139uhyyBtEh4e1CBDJ68ooK5nCeWoncZf9HPyAfRrukA");
135 assert_eq!(address, expected_address.to_bytes());
136
137 let address_seed = derive_address_seed(&[b"ayy", b"lmao"], &program_id);
138 let address = derive_address(&address_seed, &address_merkle_context);
139 let expected_address = pubkey!("12bhHm6PQjbNmEn3Yu1Gq9k7XwVn2rZpzYokmLwbFazN");
140 assert_eq!(address, expected_address.to_bytes());
141 }
142}