@@ -42,86 +42,120 @@ macro_rules! impl_compressed_mint_hash {
42
42
$is_decompressed: expr
43
43
$( , $deref_op: tt) ?
44
44
) => { {
45
- let hashed_spl_mint = $hash_cache. get_or_hash_mint( & $self. spl_mint. into( ) ) ?;
46
- let mut supply_bytes = [ 0u8 ; 32 ] ;
47
- $self. supply
48
- . as_bytes( )
49
- . iter( )
50
- . rev( )
51
- . zip( supply_bytes[ 24 ..] . iter_mut( ) )
52
- . for_each( |( x, y) | * y = * x) ;
45
+ // Extract authority values with optional dereferencing
46
+ let mint_authority = $self. mint_authority. as_ref( ) . map( |auth| ( $( $deref_op) ?auth) . clone( ) ) ;
47
+ let freeze_authority = $self. freeze_authority. as_ref( ) . map( |auth| ( $( $deref_op) ?auth) . clone( ) ) ;
53
48
54
- let hashed_mint_authority;
55
- let hashed_mint_authority_option =
56
- if let Some ( mint_authority) = $self. mint_authority. as_ref( ) {
57
- hashed_mint_authority = $hash_cache. get_or_hash_pubkey( & ( $( $deref_op) ?mint_authority) . to_bytes( ) ) ;
58
- Some ( & hashed_mint_authority)
59
- } else {
60
- None
61
- } ;
62
-
63
- let hashed_freeze_authority;
64
- let hashed_freeze_authority_option = if let Some ( freeze_authority) =
65
- $self. freeze_authority. as_ref( )
66
- {
67
- hashed_freeze_authority = $hash_cache. get_or_hash_pubkey( & ( $( $deref_op) ?freeze_authority) . to_bytes( ) ) ;
68
- Some ( & hashed_freeze_authority)
69
- } else {
70
- None
71
- } ;
72
-
73
- let mint_hash = CompressedMint :: hash_with_hashed_values(
74
- & hashed_spl_mint,
75
- & supply_bytes,
49
+ // Call unified function
50
+ compute_compressed_mint_hash_from_values(
51
+ $self. spl_mint,
52
+ $self. supply. as_bytes( ) ,
76
53
$self. decimals,
77
54
$is_decompressed,
78
- & hashed_mint_authority_option ,
79
- & hashed_freeze_authority_option ,
55
+ mint_authority ,
56
+ freeze_authority ,
80
57
$self. version,
81
- ) ?;
58
+ $self. extensions. as_ref( ) . map( |e| e. as_slice( ) ) ,
59
+ $hash_cache,
60
+ )
61
+ } } ;
62
+ }
82
63
83
- if let Some ( extensions) = $self. extensions. as_ref( ) {
84
- let mut extension_hashchain = [ 0u8 ; 32 ] ;
85
- for extension in extensions. as_slice( ) {
86
- let extension_hash = if $self. version == 0 {
87
- extension. hash:: <Poseidon >( ) ?
88
- } else if $self. version == 1 {
89
- extension. hash:: <Sha256BE >( ) ?
90
- } else {
91
- return Err ( CTokenError :: InvalidTokenDataVersion ) ;
92
- } ;
64
+ /// Unified function to compute compressed mint hash from extracted values.
65
+ /// This function contains the core logic that was previously duplicated
66
+ /// in both the macro and instruction processing code.
67
+ #[ allow( clippy:: too_many_arguments) ]
68
+ pub fn compute_compressed_mint_hash_from_values < ExtType , E > (
69
+ spl_mint : light_compressed_account:: Pubkey ,
70
+ supply_bytes : & [ u8 ] ,
71
+ decimals : u8 ,
72
+ is_decompressed : bool ,
73
+ mint_authority : Option < light_compressed_account:: Pubkey > ,
74
+ freeze_authority : Option < light_compressed_account:: Pubkey > ,
75
+ version : u8 ,
76
+ extensions : Option < & [ ExtType ] > ,
77
+ hash_cache : & mut HashCache ,
78
+ ) -> Result < [ u8 ; 32 ] , E >
79
+ where
80
+ ExtType : crate :: HashableExtension < E > ,
81
+ E : From < HasherError > + From < CTokenError > ,
82
+ {
83
+ // 1. Get cached hashes for common values
84
+ let hashed_spl_mint = hash_cache
85
+ . get_or_hash_mint ( & spl_mint. into ( ) )
86
+ . map_err ( E :: from) ?;
93
87
94
- if $self. version == 0 {
95
- extension_hashchain = Poseidon :: hashv( & [
96
- extension_hashchain. as_slice( ) ,
97
- extension_hash. as_slice( ) ,
98
- ] ) ?;
99
- } else if $self. version == 1 {
100
- extension_hashchain = Sha256BE :: hashv( & [
101
- extension_hashchain. as_slice( ) ,
102
- extension_hash. as_slice( ) ,
103
- ] ) ?;
104
- } else {
105
- return Err ( CTokenError :: InvalidTokenDataVersion ) ;
106
- }
107
- }
108
- if $self. version == 0 {
109
- Ok ( Poseidon :: hashv( & [
110
- mint_hash. as_slice( ) ,
111
- extension_hashchain. as_slice( ) ,
112
- ] ) ?)
113
- } else if $self. version == 1 {
114
- Ok ( Sha256BE :: hashv( & [
115
- mint_hash. as_slice( ) ,
116
- extension_hashchain. as_slice( ) ,
117
- ] ) ?)
88
+ // 2. Convert supply bytes to 32-byte array (big-endian, right-aligned)
89
+ let mut supply_bytes_32 = [ 0u8 ; 32 ] ;
90
+ supply_bytes
91
+ . iter ( )
92
+ . rev ( )
93
+ . zip ( supply_bytes_32[ 24 ..] . iter_mut ( ) )
94
+ . for_each ( |( x, y) | * y = * x) ;
95
+
96
+ // 3. Hash authorities if present
97
+ let hashed_mint_authority;
98
+ let hashed_mint_authority_option = if let Some ( mint_authority) = mint_authority. as_ref ( ) {
99
+ hashed_mint_authority = hash_cache. get_or_hash_pubkey ( & mint_authority. to_bytes ( ) ) ;
100
+ Some ( & hashed_mint_authority)
101
+ } else {
102
+ None
103
+ } ;
104
+
105
+ let hashed_freeze_authority;
106
+ let hashed_freeze_authority_option = if let Some ( freeze_authority) = freeze_authority. as_ref ( ) {
107
+ hashed_freeze_authority = hash_cache. get_or_hash_pubkey ( & freeze_authority. to_bytes ( ) ) ;
108
+ Some ( & hashed_freeze_authority)
109
+ } else {
110
+ None
111
+ } ;
112
+
113
+ // 4. Compute base mint hash using existing function
114
+ let mint_hash = CompressedMint :: hash_with_hashed_values (
115
+ & hashed_spl_mint,
116
+ & supply_bytes_32,
117
+ decimals,
118
+ is_decompressed,
119
+ & hashed_mint_authority_option,
120
+ & hashed_freeze_authority_option,
121
+ version,
122
+ )
123
+ . map_err ( E :: from) ?;
124
+
125
+ // 5. Handle extensions if present
126
+ if let Some ( extensions) = extensions {
127
+ let mut extension_hashchain = [ 0u8 ; 32 ] ;
128
+ for extension in extensions {
129
+ let extension_hash = if version == 0 {
130
+ extension. hash_with_hasher :: < Poseidon > ( & hashed_spl_mint, hash_cache)
131
+ } else if version == 1 {
132
+ extension. hash_with_hasher :: < Sha256BE > ( & hashed_spl_mint, hash_cache)
118
133
} else {
119
- return Err ( CTokenError :: InvalidTokenDataVersion ) ;
120
- }
121
- } else {
122
- Ok ( mint_hash)
134
+ Err ( CTokenError :: InvalidTokenDataVersion . into ( ) )
135
+ } ;
136
+ extension_hashchain = match version {
137
+ 0 => {
138
+ Poseidon :: hashv ( & [ extension_hashchain. as_slice ( ) , extension_hash?. as_slice ( ) ] ) ?
139
+ }
140
+ 1 => {
141
+ Sha256BE :: hashv ( & [ extension_hashchain. as_slice ( ) , extension_hash?. as_slice ( ) ] ) ?
142
+ }
143
+ _ => return Err ( CTokenError :: InvalidTokenDataVersion . into ( ) ) ,
144
+ } ;
123
145
}
124
- } } ;
146
+
147
+ // 6. Combine mint hash with extension hashchain
148
+ let final_hash = if version == 0 {
149
+ Poseidon :: hashv ( & [ mint_hash. as_slice ( ) , extension_hashchain. as_slice ( ) ] ) ?
150
+ } else if version == 1 {
151
+ Sha256BE :: hashv ( & [ mint_hash. as_slice ( ) , extension_hashchain. as_slice ( ) ] ) ?
152
+ } else {
153
+ return Err ( CTokenError :: InvalidTokenDataVersion . into ( ) ) ;
154
+ } ;
155
+ Ok ( final_hash)
156
+ } else {
157
+ Ok ( mint_hash)
158
+ }
125
159
}
126
160
127
161
// TODO: unify code if possible
0 commit comments