1use crate::xdr::*;
2
3use crate::types::AuthTokenNode;
4
5#[cfg(feature = "alloc")]
6use crate::types::AuthTokenPayload;
7
8pub trait MintableType: Sized + WriteXDR + for<'r> ReadXDR<'r> {
14 type Preimage;
15}
16
17pub struct AuthTokenPreimage<T> {
18 pub consumer: crate::types::ContractAddress,
19 pub data: T,
20}
21
22impl<T: WriteXDR> WriteXDR for AuthTokenPreimage<T> {
26 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
27 self.consumer.write_xdr(w)?;
28 self.data.write_xdr(w)
29 }
30
31 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
32 unsafe {
33 self.consumer.write_xdr_unchecked(w);
34 self.data.write_xdr_unchecked(w);
35 }
36 }
37}
38
39impl<'r, T: ReadXDR<'r>> ReadXDR<'r> for AuthTokenPreimage<T> {
40 fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
41 Ok(Self {
42 consumer: crate::types::ContractAddress::read_xdr(r)?,
43 data: T::read_xdr(r)?,
44 })
45 }
46}
47
48const AUTH_TOKEN_MAX_CHILDREN: usize =
49 thruput_xdr::auth_token::kAuthTokenMaxChildNodes as usize;
50
51pub type ChildNodeBuf = heapless::Vec<AuthTokenNode, AUTH_TOKEN_MAX_CHILDREN>;
52
53pub trait Mintable: MintableType
54where
55 Self::Preimage: WriteXDR + for<'r> ReadXDR<'r>,
56{
57 fn mint_into_parent(
58 preimage: Self::Preimage,
59 children: &mut ChildNodeBuf,
60 ) -> Self;
61}
62
63#[cfg(feature = "alloc")]
67pub fn build_auth_token_node<T: Mintable>(
68 preimage: AuthTokenPreimage<T::Preimage>,
69) -> AuthTokenNode
70where
71 T::Preimage: WriteXDR + for<'r> ReadXDR<'r>,
72{
73 let mut children = ChildNodeBuf::new();
74 let payload_value = T::mint_into_parent(preimage.data, &mut children);
75 AuthTokenNode {
76 consumer_address: preimage.consumer,
77 payload: encode_payload(&payload_value),
78 child_nodes: children_to_vecm(children),
79 }
80}
81
82#[cfg(feature = "alloc")]
83pub fn encode_payload<T: WriteXDR>(value: &T) -> AuthTokenPayload {
84 let buf = crate::internal::encode_xdr(value).unwrap_or_else(|e| {
85 crate::exn::library_throw(crate::AuthTokenError::MintEncodeFailure(
86 crate::exn::FaultString::from_display(e),
87 ))
88 });
89 let bytes: xdrs::BytesM<{ thruput_xdr::auth_token::kAuthTokenMaxLen }> =
90 buf.as_slice().try_into().unwrap_or_else(|_| {
91 crate::exn::library_throw(
92 crate::AuthTokenError::MintEncodeFailure(
93 crate::exn::FaultString::from_display(
94 "auth token payload exceeds max length",
95 ),
96 ),
97 )
98 });
99 AuthTokenPayload::from(bytes)
100}
101
102#[cfg(feature = "alloc")]
103fn children_to_vecm(
104 children: ChildNodeBuf,
105) -> xdrs::VecM<
106 AuthTokenNode,
107 { thruput_xdr::auth_token::kAuthTokenMaxChildNodes },
108> {
109 children.as_slice().try_into().unwrap_or_else(|_| {
110 crate::exn::library_throw(crate::AuthTokenError::MintEncodeFailure(
111 crate::exn::FaultString::from_display(format_args!(
112 "too many auth token children (max {})",
113 thruput_xdr::auth_token::kAuthTokenMaxChildNodes
114 )),
115 ))
116 })
117}
118
119#[cfg(feature = "alloc")]
120pub fn encode_auth_token_node(node: &AuthTokenNode) -> alloc::vec::Vec<u8> {
121 xdrs::txs::encode(node).unwrap_or_else(|e| {
122 crate::exn::library_throw(crate::AuthTokenError::MintEncodeFailure(
123 crate::exn::FaultString::from_display(e),
124 ))
125 })
126}
127
128macro_rules! impl_mintable_type_leaf {
131 ($($ty:ty),+ $(,)?) => {
132 $(
133 impl MintableType for $ty {
134 type Preimage = $ty;
135 }
136 )+
137 };
138}
139
140impl_mintable_type_leaf!(
141 u16,
142 u32,
143 u64,
144 u128,
145 i16,
146 i32,
147 i64,
148 i128,
149 bool,
150 (),
151 crate::types::ContractAddress,
152 crate::types::SHA256Hash,
153 crate::types::Ed25519PublicKey,
154 crate::types::Ed25519Signature,
155 crate::types::MlDsa65PublicKey,
156 crate::types::MlDsa65Signature,
157 crate::types::PublicKey,
158 crate::types::Signature,
159 crate::types::BlockHeight,
160 thruput_u256::U256,
161 thruput_u256::I256,
162 crate::types::ContractEntrypointID,
163);
164
165impl<const MAX: u32> MintableType for BytesM<MAX> {
166 type Preimage = BytesM<MAX>;
167}
168
169impl<const N: usize> MintableType for [u8; N] {
170 type Preimage = [u8; N];
171}
172
173impl<const N: usize, T: MintableType> MintableType for [T; N] {
174 type Preimage = [T::Preimage; N];
175}
176
177impl<T: MintableType> MintableType for Option<T> {
178 type Preimage = Option<T::Preimage>;
179}
180
181impl<const MAX: usize> MintableType for heapless::String<MAX> {
182 type Preimage = Self;
183}
184
185impl<const N: usize> MintableType for heapless::Vec<u8, N> {
186 type Preimage = Self;
187}
188
189#[cfg(feature = "alloc")]
190impl<T: MintableType + 'static, const MAX: u32> MintableType for VecM<T, MAX> {
191 type Preimage = VecM<T::Preimage, MAX>;
192}
193
194#[cfg(feature = "alloc")]
195impl<const MAX: u32> MintableType for StringM<MAX> {
196 type Preimage = StringM<MAX>;
197}
198
199#[cfg(feature = "alloc")]
200impl<T: MintableType> MintableType for alloc::vec::Vec<T> {
201 type Preimage = alloc::vec::Vec<T::Preimage>;
202}
203
204#[cfg(feature = "alloc")]
205impl<T: MintableType> MintableType for alloc::boxed::Box<T> {
206 type Preimage = alloc::boxed::Box<T::Preimage>;
207}
208
209macro_rules! impl_mintable_leaf {
212 ($($ty:ty),+ $(,)?) => {
213 $(
214 impl Mintable for $ty {
215 fn mint_into_parent(preimage: $ty, _children: &mut ChildNodeBuf) -> Self {
216 preimage
217 }
218 }
219 )+
220 };
221}
222
223impl_mintable_leaf!(
224 u16,
225 u32,
226 u64,
227 u128,
228 i16,
229 i32,
230 i64,
231 i128,
232 bool,
233 (),
234 crate::types::ContractAddress,
235 crate::types::SHA256Hash,
236 crate::types::Ed25519PublicKey,
237 crate::types::Ed25519Signature,
238 crate::types::MlDsa65PublicKey,
239 crate::types::MlDsa65Signature,
240 crate::types::PublicKey,
241 crate::types::Signature,
242 crate::types::BlockHeight,
243 thruput_u256::U256,
244 thruput_u256::I256,
245 crate::types::ContractEntrypointID,
246);
247
248impl<const MAX: u32> Mintable for BytesM<MAX> {
249 fn mint_into_parent(
250 preimage: BytesM<MAX>,
251 _children: &mut ChildNodeBuf,
252 ) -> Self {
253 preimage
254 }
255}
256
257#[cfg(feature = "alloc")]
258impl<const MAX: u32> Mintable for StringM<MAX> {
259 fn mint_into_parent(
260 preimage: StringM<MAX>,
261 _children: &mut ChildNodeBuf,
262 ) -> Self {
263 preimage
264 }
265}
266
267impl<const MAX: usize> Mintable for heapless::String<MAX> {
268 fn mint_into_parent(preimage: Self, _children: &mut ChildNodeBuf) -> Self {
269 preimage
270 }
271}
272
273impl<const N: usize> Mintable for heapless::Vec<u8, N> {
274 fn mint_into_parent(preimage: Self, _children: &mut ChildNodeBuf) -> Self {
275 preimage
276 }
277}
278
279impl<const N: usize> Mintable for [u8; N] {
280 fn mint_into_parent(
281 preimage: [u8; N],
282 _children: &mut ChildNodeBuf,
283 ) -> Self {
284 preimage
285 }
286}
287
288impl<T: Mintable> Mintable for Option<T>
289where
290 T::Preimage: WriteXDR + for<'r> ReadXDR<'r>,
291 Option<T::Preimage>: WriteXDR + for<'r> ReadXDR<'r>,
292{
293 fn mint_into_parent(
294 preimage: Option<T::Preimage>,
295 children: &mut ChildNodeBuf,
296 ) -> Self {
297 preimage.map(|inner| T::mint_into_parent(inner, children))
298 }
299}
300
301#[cfg(feature = "alloc")]
302impl<T: Mintable + 'static, const MAX: u32> Mintable for VecM<T, MAX>
303where
304 T::Preimage: WriteXDR + for<'r> ReadXDR<'r> + 'static,
305 VecM<T::Preimage, MAX>: WriteXDR + for<'r> ReadXDR<'r>,
306{
307 fn mint_into_parent(
308 preimage: VecM<T::Preimage, MAX>,
309 children: &mut ChildNodeBuf,
310 ) -> Self {
311 let v: alloc::vec::Vec<T> = preimage
312 .0
313 .into_iter()
314 .map(|item| T::mint_into_parent(item, children))
315 .collect();
316 VecM(v)
317 }
318}
319
320impl<const N: usize, T: Mintable> Mintable for [T; N]
321where
322 T::Preimage: WriteXDR + for<'r> ReadXDR<'r>,
323 [T::Preimage; N]: WriteXDR + for<'r> ReadXDR<'r>,
324{
325 fn mint_into_parent(
326 preimage: [T::Preimage; N],
327 children: &mut ChildNodeBuf,
328 ) -> Self {
329 preimage.map(|inner| T::mint_into_parent(inner, children))
330 }
331}
332
333#[cfg(feature = "alloc")]
334impl<T: Mintable> Mintable for alloc::vec::Vec<T>
335where
336 T::Preimage: WriteXDR + for<'r> ReadXDR<'r>,
337 alloc::vec::Vec<T::Preimage>: WriteXDR + for<'r> ReadXDR<'r>,
338{
339 fn mint_into_parent(
340 preimage: alloc::vec::Vec<T::Preimage>,
341 children: &mut ChildNodeBuf,
342 ) -> Self {
343 preimage
344 .into_iter()
345 .map(|item| T::mint_into_parent(item, children))
346 .collect()
347 }
348}
349
350#[cfg(feature = "alloc")]
351impl<T: Mintable> Mintable for alloc::boxed::Box<T>
352where
353 T::Preimage: Sized + WriteXDR + for<'r> ReadXDR<'r>,
354 alloc::boxed::Box<T::Preimage>: WriteXDR + for<'r> ReadXDR<'r>,
355{
356 fn mint_into_parent(
357 preimage: alloc::boxed::Box<T::Preimage>,
358 children: &mut ChildNodeBuf,
359 ) -> Self {
360 alloc::boxed::Box::new(T::mint_into_parent(*preimage, children))
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367 use crate::signer::Signed;
368
369 #[test]
370 fn primitive_mintable_builds_leaf_node() {
371 let node = build_auth_token_node::<u64>(AuthTokenPreimage {
372 consumer: crate::types::ContractAddress::default(),
373 data: 42u64,
374 });
375 assert!(node.child_nodes.is_empty());
376 }
377
378 #[test]
379 fn build_node_sets_consumer_from_preimage() {
380 let consumer = crate::types::ContractAddress::from([0xAB; 32]);
381 let node = build_auth_token_node::<u64>(AuthTokenPreimage {
382 consumer,
383 data: 42u64,
384 });
385 assert_eq!(node.consumer_address, consumer);
386 }
387
388 #[test]
389 fn primitive_mint_into_parent_no_children() {
390 let mut children = ChildNodeBuf::new();
391 let val = u64::mint_into_parent(42u64, &mut children);
392 assert_eq!(val, 42);
393 assert!(children.is_empty());
394 }
395
396 #[test]
397 fn signed_mint_into_parent_pushes_child() {
398 let mut children = ChildNodeBuf::new();
399 let consumer = crate::types::ContractAddress::default();
400 let val = <Signed<u64>>::mint_into_parent(
401 AuthTokenPreimage {
402 consumer,
403 data: 42u64,
404 },
405 &mut children,
406 );
407 assert_eq!(val.handle(), u32::MAX);
408 assert_eq!(children.len(), 1);
409 }
410
411 #[test]
412 fn option_none_no_children() {
413 let mut children = ChildNodeBuf::new();
414 let val = <Option<Signed<u64>>>::mint_into_parent(None, &mut children);
415 assert!(val.is_none());
416 assert!(children.is_empty());
417 }
418
419 #[test]
420 fn option_some_signed_pushes_child() {
421 let mut children = ChildNodeBuf::new();
422 let consumer = crate::types::ContractAddress::default();
423 let val = <Option<Signed<u64>>>::mint_into_parent(
424 Some(AuthTokenPreimage {
425 consumer,
426 data: 42u64,
427 }),
428 &mut children,
429 );
430 assert!(val.is_some());
431 assert_eq!(children.len(), 1);
432 }
433}