concordium_cis2/
lib.rs

1//! This library provides types and functions for working with the [Concordium
2//! Token Standard CIS2](https://proposals.concordium.software/CIS/cis-2.html).
3//!
4//! It contains types for the parameters for each of the contract functions and
5//! types for each event. Each type have implemented serialization according to
6//! CIS2.
7//! Additionally the crate exports an CIS2Error wrapper type which can be used
8//! to wrap and extend a custom error type. This will ensure the CIS2 errors
9//! have the correct error codes.
10//!
11//! # Example using `TransferParams`
12//!
13//! ```ignore
14//! type TransferParameter = TransferParams<TokenIdVec>;
15//!
16//! #[receive(contract = "MyTokenContract", name = "transfer", parameter = "TransferParameter", enable_logger)]
17//! fn contract_transfer<A: HasActions>(
18//!     ctx: &impl HasReceiveContext,
19//!     logger: &mut impl HasLogger,
20//!     state: &mut State,
21//! ) -> ContractResult<A> {
22//!     // Parse the parameter.
23//!     let TransferParams(transfers) = ctx.parameter_cursor().get()?;
24//!     // ...
25//!     Ok(A::accept())
26//! }
27//! ```
28//!
29//! # Features
30//!
31//! This crate has features `std`, `u256_amount`, and `serde`. The first one is
32//! default. When the `u256_amount` feature is enabled the type
33//! [`TokenAmountU256`] is defined and implements the [`IsTokenAmount`]
34//! interface. The `serde` features derives `serde::Serialize` and
35//! `serde::Deserialize` for a variety of types.
36#![cfg_attr(not(feature = "std"), no_std)]
37
38mod cis2_client;
39pub use cis2_client::{Cis2Client, Cis2ClientError};
40
41use concordium_std::{collections::BTreeMap, schema::SchemaType, *};
42// Re-export for backward compatibility.
43pub use concordium_std::MetadataUrl;
44#[cfg(not(feature = "std"))]
45use core::{fmt, ops, str::FromStr};
46#[cfg(feature = "serde")]
47use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
48#[cfg(feature = "std")]
49use std::{fmt, ops, str::FromStr};
50
51use convert::TryFrom;
52
53/// The standard identifier for the CIS-0: Standard Detection.
54pub const CIS0_STANDARD_IDENTIFIER: StandardIdentifier<'static> =
55    StandardIdentifier::new_unchecked("CIS-0");
56
57/// The standard identifier for the CIS-1: Concordium Token Standard.
58pub const CIS1_STANDARD_IDENTIFIER: StandardIdentifier<'static> =
59    StandardIdentifier::new_unchecked("CIS-1");
60
61/// The standard identifier for the CIS-2: Concordium Token Standard 2.
62pub const CIS2_STANDARD_IDENTIFIER: StandardIdentifier<'static> =
63    StandardIdentifier::new_unchecked("CIS-2");
64
65/// Tag for the CIS2 Transfer event.
66pub const TRANSFER_EVENT_TAG: u8 = u8::MAX;
67/// Tag for the CIS2 Mint event.
68pub const MINT_EVENT_TAG: u8 = u8::MAX - 1;
69/// Tag for the CIS2 Burn event.
70pub const BURN_EVENT_TAG: u8 = u8::MAX - 2;
71/// Tag for the CIS2 UpdateOperator event.
72pub const UPDATE_OPERATOR_EVENT_TAG: u8 = u8::MAX - 3;
73/// Tag for the CIS2 TokenMetadata event.
74pub const TOKEN_METADATA_EVENT_TAG: u8 = u8::MAX - 4;
75
76/// Trait for marking types as CIS2 token IDs.
77/// For a type to be a valid CIS2 token ID it must implement
78/// `SchemaType` and `Serialize`, such that the first
79/// byte indicates how many bytes is used to represent the token ID, followed by
80/// this many bytes for the token ID.
81///
82/// Note: The reason for introducing such a trait instead of representing every
83/// token ID using `Vec<u8>` is to allow smart contracts to use specialized
84/// token ID implementations avoiding allocations.
85pub trait IsTokenId: Serialize + schema::SchemaType {}
86
87/// Trait for marking types as CIS2 token amounts.
88/// For a type to be a valid CIS2 token amount it must implement SchemaType and
89/// Serialize, using the LEB128 unsigned integer encoding constrained to at most
90/// 37 bytes.
91///
92/// Note: The reason for introducing such a trait instead of representing every
93/// token amount using `[u8; 37]` is to allow smart contracts to use specialized
94/// token amount implementations avoiding doing arithmetics of large integers.
95pub trait IsTokenAmount: Serialize + schema::SchemaType {}
96
97/// Token Identifier, which combined with the address of the contract instance,
98/// forms the unique identifier of a token type.
99///
100/// This token ID type can represent every possible token ID but requires
101/// allocating a Vec. Using a fixed size token ID type (such as `TokenIdFixed`)
102/// will avoid this.
103///
104/// The CIS2 specification allows for up to 255 bytes for the token ID, but
105/// unless the bytes have some significant meaning, it is most likely better to
106/// use a smaller fixed size token ID such as `TokenIdU8`.
107#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Serialize)]
108#[cfg_attr(
109    feature = "serde",
110    derive(SerdeSerialize, SerdeDeserialize),
111    serde(into = "String", try_from = "String")
112)]
113pub struct TokenIdVec(#[concordium(size_length = 1)] pub Vec<u8>);
114
115impl IsTokenId for TokenIdVec {}
116
117impl schema::SchemaType for TokenIdVec {
118    fn get_type() -> schema::Type { schema::Type::ByteList(schema::SizeLength::U8) }
119}
120
121/// Display the token ID as a uppercase hex string
122impl fmt::Display for TokenIdVec {
123    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124        for byte in &self.0 {
125            write!(f, "{:02X}", byte)?;
126        }
127        Ok(())
128    }
129}
130
131#[cfg(feature = "serde")]
132impl From<TokenIdVec> for String {
133    fn from(id: TokenIdVec) -> Self { id.to_string() }
134}
135
136#[cfg(feature = "serde")]
137impl TryFrom<String> for TokenIdVec {
138    type Error = ParseError;
139
140    fn try_from(s: String) -> Result<Self, Self::Error> { s.parse() }
141}
142
143/// Parse the token ID from a hex string
144impl FromStr for TokenIdVec {
145    type Err = ParseError;
146
147    fn from_str(s: &str) -> Result<Self, Self::Err> {
148        if s.len() % 2 != 0 || !s.is_ascii() {
149            return Err(ParseError {});
150        }
151
152        let mut id = Vec::with_capacity(s.len() / 2);
153        for i in (0..s.len()).step_by(2) {
154            let byte = u8::from_str_radix(&s[i..i + 2], 16).map_err(|_| ParseError {})?;
155            id.push(byte);
156        }
157
158        Ok(Self(id))
159    }
160}
161
162/// Token Identifier, which combined with the address of the contract instance,
163/// forms the unique identifier of a token type.
164///
165/// The CIS2 specification allows for up to 255 bytes for the token ID, but for
166/// most cases using a smaller token ID is fine and can reduce contract energy
167/// costs.
168///
169/// This token ID uses an array for representing the token ID bytes which means
170/// the token ID space is fixed to `N` number of bytes and some token IDs cannot
171/// be represented. For a more general token ID type see `TokenIdVec`.
172/// For fixed sized token IDs with integer representations see `TokenIdU8`,
173/// `TokenIdU16`, `TokenIdU32` and `TokenIdU64`.
174#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Copy, Clone)]
175#[cfg_attr(
176    feature = "serde",
177    derive(SerdeSerialize, SerdeDeserialize),
178    serde(into = "String", try_from = "String")
179)]
180pub struct TokenIdFixed<const N: usize>(pub [u8; N]);
181
182impl<const N: usize> IsTokenId for TokenIdFixed<N> {}
183
184impl<const N: usize> schema::SchemaType for TokenIdFixed<N> {
185    fn get_type() -> schema::Type { schema::Type::ByteList(schema::SizeLength::U8) }
186}
187
188impl<const N: usize> From<[u8; N]> for TokenIdFixed<N> {
189    fn from(id: [u8; N]) -> Self { TokenIdFixed(id) }
190}
191
192/// The `TokenIdFixed` is serialized as the value of the first byte represents
193/// the number of bytes followed for the rest of the token ID.
194impl<const N: usize> Serial for TokenIdFixed<N> {
195    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
196        let len = u8::try_from(N).map_err(|_| W::Err::default())?;
197        out.write_u8(len)?;
198        out.write_all(&self.0)?;
199        Ok(())
200    }
201}
202
203/// The `TokenIdFixed` is deserialized by reading the first byte represents the
204/// number of bytes and ensuring this value corresponds with the number of bytes
205/// to use for the token ID.
206impl<const N: usize> Deserial for TokenIdFixed<N> {
207    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
208        let byte_length = source.read_u8()?;
209        if usize::from(byte_length) != N {
210            return Err(ParseError::default());
211        }
212        let bytes: [u8; N] = source.get()?;
213        Ok(TokenIdFixed(bytes))
214    }
215}
216
217/// Display the token ID as a uppercase hex string
218impl<const N: usize> fmt::Display for TokenIdFixed<N> {
219    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
220        for byte in &self.0 {
221            write!(f, "{:02X}", byte)?;
222        }
223        Ok(())
224    }
225}
226
227#[cfg(feature = "serde")]
228impl<const N: usize> From<TokenIdFixed<N>> for String {
229    fn from(id: TokenIdFixed<N>) -> Self { id.to_string() }
230}
231
232#[cfg(feature = "serde")]
233impl<const N: usize> TryFrom<String> for TokenIdFixed<N> {
234    type Error = ParseError;
235
236    fn try_from(s: String) -> Result<Self, Self::Error> { s.parse() }
237}
238
239/// Parse the token ID from a hex string
240impl<const N: usize> FromStr for TokenIdFixed<N> {
241    type Err = ParseError;
242
243    fn from_str(s: &str) -> Result<Self, Self::Err> { parse_bytes_exact(s).map(Self) }
244}
245
246/// Token Identifier, which combined with the address of the contract instance,
247/// forms the unique identifier of a token type.
248///
249/// The CIS2 specification allows for up to 255 bytes for the token ID, but for
250/// most cases using a smaller token ID is fine and can reduce contract energy
251/// costs.
252///
253/// This token ID uses u64 for representing the token ID bytes which means the
254/// token ID space is fixed to 8 bytes and some token IDs cannot be represented.
255/// For a more general token ID type see `TokenIdVec`.
256#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Copy, Clone)]
257#[cfg_attr(
258    feature = "serde",
259    derive(SerdeSerialize, SerdeDeserialize),
260    serde(into = "String", try_from = "String")
261)]
262pub struct TokenIdU64(pub u64);
263
264impl IsTokenId for TokenIdU64 {}
265
266impl schema::SchemaType for TokenIdU64 {
267    fn get_type() -> schema::Type { schema::Type::ByteList(schema::SizeLength::U8) }
268}
269
270impl From<u64> for TokenIdU64 {
271    fn from(id: u64) -> Self { TokenIdU64(id) }
272}
273
274/// The `TokenIdU64` is serialized with one byte with the value 8 followed by 8
275/// bytes to encode a u64 in little endian.
276impl Serial for TokenIdU64 {
277    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
278        out.write_u8(8)?;
279        out.write_u64(self.0)
280    }
281}
282
283/// The `TokenIdU64` will deserialize one byte ensuring this contains the value
284/// 8 and then deserialize a u64 as little endian. It will result in an error if
285/// the first byte is not 8.
286impl Deserial for TokenIdU64 {
287    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
288        let byte_length = source.read_u8()?;
289        if byte_length == 8 {
290            Ok(TokenIdU64(source.read_u64()?))
291        } else {
292            Err(ParseError::default())
293        }
294    }
295}
296
297/// Display the token ID as a uppercase hex string
298impl fmt::Display for TokenIdU64 {
299    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
300        for byte in &self.0.to_le_bytes() {
301            write!(f, "{:02X}", byte)?;
302        }
303        Ok(())
304    }
305}
306
307#[cfg(feature = "serde")]
308impl From<TokenIdU64> for String {
309    fn from(id: TokenIdU64) -> Self { id.to_string() }
310}
311
312#[cfg(feature = "serde")]
313impl TryFrom<String> for TokenIdU64 {
314    type Error = ParseError;
315
316    fn try_from(s: String) -> Result<Self, Self::Error> { s.parse() }
317}
318
319/// Parse the token ID from a hex string
320impl FromStr for TokenIdU64 {
321    type Err = ParseError;
322
323    fn from_str(s: &str) -> Result<Self, Self::Err> {
324        let bytes = parse_bytes_exact(s)?;
325        Ok(Self(u64::from_le_bytes(bytes)))
326    }
327}
328
329/// Token Identifier, which combined with the address of the contract instance,
330/// forms the unique identifier of a token type.
331///
332/// The CIS2 specification allows for up to 255 bytes for the token ID, but for
333/// most cases using a smaller token ID is fine and can reduce contract energy
334/// costs.
335///
336/// This token ID uses u32 for representing the token ID bytes which means the
337/// token ID space is fixed to 4 bytes and some token IDs cannot be represented.
338/// For a more general token ID type see `TokenIdVec`.
339#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Copy, Clone)]
340#[cfg_attr(
341    feature = "serde",
342    derive(SerdeSerialize, SerdeDeserialize),
343    serde(into = "String", try_from = "String")
344)]
345pub struct TokenIdU32(pub u32);
346
347impl IsTokenId for TokenIdU32 {}
348
349impl schema::SchemaType for TokenIdU32 {
350    fn get_type() -> schema::Type { schema::Type::ByteList(schema::SizeLength::U8) }
351}
352
353impl From<u32> for TokenIdU32 {
354    fn from(id: u32) -> Self { TokenIdU32(id) }
355}
356
357/// The `TokenIdU32` is serialized with one byte with the value 4 followed by 4
358/// bytes to encode a u32 in little endian.
359impl Serial for TokenIdU32 {
360    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
361        out.write_u8(4)?;
362        out.write_u32(self.0)
363    }
364}
365
366/// The `TokenIdU32` will deserialize one byte ensuring this contains the value
367/// 4 and then deserialize a u32 as little endian. It will result in an error if
368/// the first byte is not 4.
369impl Deserial for TokenIdU32 {
370    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
371        let byte_length = source.read_u8()?;
372        if byte_length == 4 {
373            Ok(TokenIdU32(source.read_u32()?))
374        } else {
375            Err(ParseError::default())
376        }
377    }
378}
379
380/// Display the token ID as a uppercase hex string
381impl fmt::Display for TokenIdU32 {
382    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
383        for byte in &self.0.to_le_bytes() {
384            write!(f, "{:02X}", byte)?;
385        }
386        Ok(())
387    }
388}
389
390#[cfg(feature = "serde")]
391impl From<TokenIdU32> for String {
392    fn from(id: TokenIdU32) -> Self { id.to_string() }
393}
394
395#[cfg(feature = "serde")]
396impl TryFrom<String> for TokenIdU32 {
397    type Error = ParseError;
398
399    fn try_from(s: String) -> Result<Self, Self::Error> { s.parse() }
400}
401
402/// Parse the token ID from a hex string
403impl FromStr for TokenIdU32 {
404    type Err = ParseError;
405
406    fn from_str(s: &str) -> Result<Self, Self::Err> {
407        let bytes = parse_bytes_exact(s)?;
408        Ok(Self(u32::from_le_bytes(bytes)))
409    }
410}
411
412/// Token Identifier, which combined with the address of the contract instance,
413/// forms the unique identifier of a token type.
414///
415/// The CIS2 specification allows for up to 255 bytes for the token ID, but for
416/// most cases using a smaller token ID is fine and can reduce contract energy
417/// costs.
418///
419/// This token ID uses u16 for representing the token ID bytes which means the
420/// token ID space is fixed to 2 bytes and some token IDs cannot be represented.
421/// For a more general token ID type see `TokenIdVec`.
422#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Copy, Clone)]
423#[cfg_attr(
424    feature = "serde",
425    derive(SerdeSerialize, SerdeDeserialize),
426    serde(into = "String", try_from = "String")
427)]
428pub struct TokenIdU16(pub u16);
429
430impl IsTokenId for TokenIdU16 {}
431
432impl schema::SchemaType for TokenIdU16 {
433    fn get_type() -> schema::Type { schema::Type::ByteList(schema::SizeLength::U8) }
434}
435
436impl From<u16> for TokenIdU16 {
437    fn from(id: u16) -> Self { TokenIdU16(id) }
438}
439
440/// The `TokenIdU16` is serialized with one byte with the value 2 followed by 2
441/// bytes to encode a u16 in little endian.
442impl Serial for TokenIdU16 {
443    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
444        out.write_u8(2)?;
445        out.write_u16(self.0)
446    }
447}
448
449/// The `TokenIdU16` will deserialize one byte ensuring this contains the value
450/// 2 and then deserialize a u16 as little endian. It will result in an error if
451/// the first byte is not 2.
452impl Deserial for TokenIdU16 {
453    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
454        let byte_length = source.read_u8()?;
455        if byte_length == 2 {
456            Ok(TokenIdU16(source.read_u16()?))
457        } else {
458            Err(ParseError::default())
459        }
460    }
461}
462
463/// Display the token ID as a uppercase hex string
464impl fmt::Display for TokenIdU16 {
465    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
466        for byte in &self.0.to_le_bytes() {
467            write!(f, "{:02X}", byte)?;
468        }
469        Ok(())
470    }
471}
472
473#[cfg(feature = "serde")]
474impl From<TokenIdU16> for String {
475    fn from(id: TokenIdU16) -> Self { id.to_string() }
476}
477
478#[cfg(feature = "serde")]
479impl TryFrom<String> for TokenIdU16 {
480    type Error = ParseError;
481
482    fn try_from(s: String) -> Result<Self, Self::Error> { s.parse() }
483}
484
485/// Parse the token ID from a hex string
486impl FromStr for TokenIdU16 {
487    type Err = ParseError;
488
489    fn from_str(s: &str) -> Result<Self, Self::Err> {
490        let bytes = parse_bytes_exact(s)?;
491        Ok(Self(u16::from_le_bytes(bytes)))
492    }
493}
494
495/// Token Identifier, which combined with the address of the contract instance,
496/// forms the unique identifier of a token type.
497///
498/// The CIS2 specification allows for up to 255 bytes for the token ID, but for
499/// most cases using a smaller token ID is fine and can reduce contract energy
500/// costs.
501///
502/// This token ID uses u8 for representing the token ID bytes which means the
503/// token ID space is fixed to 1 byte and some token IDs cannot be represented.
504/// For a more general token ID type see `TokenIdVec`.
505#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Copy, Clone)]
506#[cfg_attr(
507    feature = "serde",
508    derive(SerdeSerialize, SerdeDeserialize),
509    serde(into = "String", try_from = "String")
510)]
511pub struct TokenIdU8(pub u8);
512
513impl IsTokenId for TokenIdU8 {}
514
515impl schema::SchemaType for TokenIdU8 {
516    fn get_type() -> schema::Type { schema::Type::ByteList(schema::SizeLength::U8) }
517}
518
519impl From<u8> for TokenIdU8 {
520    fn from(id: u8) -> Self { TokenIdU8(id) }
521}
522
523/// The `TokenIdU8` is serialized with one byte with the value 1 followed by 1
524/// bytes to encode a u8 in little endian.
525impl Serial for TokenIdU8 {
526    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
527        out.write_u8(1)?;
528        out.write_u8(self.0)
529    }
530}
531
532/// The `TokenIdU8` will deserialize one byte ensuring this contains the value 1
533/// and then deserialize a u8 as little endian. It will result in an error if
534/// the first byte is not 1.
535impl Deserial for TokenIdU8 {
536    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
537        let byte_length = source.read_u8()?;
538        if byte_length == 1 {
539            Ok(TokenIdU8(source.read_u8()?))
540        } else {
541            Err(ParseError::default())
542        }
543    }
544}
545
546/// Display the token ID as a uppercase hex string
547impl fmt::Display for TokenIdU8 {
548    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
549        for byte in &self.0.to_le_bytes() {
550            write!(f, "{:02X}", byte)?;
551        }
552        Ok(())
553    }
554}
555
556#[cfg(feature = "serde")]
557impl From<TokenIdU8> for String {
558    fn from(id: TokenIdU8) -> Self { id.to_string() }
559}
560
561#[cfg(feature = "serde")]
562impl TryFrom<String> for TokenIdU8 {
563    type Error = ParseError;
564
565    fn try_from(s: String) -> Result<Self, Self::Error> { s.parse() }
566}
567
568/// Parse the token ID from a hex string
569impl FromStr for TokenIdU8 {
570    type Err = ParseError;
571
572    fn from_str(s: &str) -> Result<Self, Self::Err> {
573        let bytes = parse_bytes_exact::<1>(s)?;
574        Ok(Self(bytes[0]))
575    }
576}
577
578/// Parses a hex string as a little endian array of bytes of length `N`.
579fn parse_bytes_exact<const N: usize>(s: &str) -> Result<[u8; N], ParseError> {
580    if s.len() != 2 * N || !s.is_ascii() {
581        return Err(ParseError {});
582    }
583
584    let mut bytes = [0; N];
585    for (i, place) in bytes.iter_mut().enumerate() {
586        *place = u8::from_str_radix(&s[(2 * i)..(2 * i + 2)], 16).map_err(|_| ParseError {})?;
587    }
588
589    Ok(bytes)
590}
591
592/// Token Identifier, which combined with the address of the contract instance,
593/// forms the unique identifier of a token type.
594///
595/// The CIS2 specification allows for up to 255 bytes for the token ID, but for
596/// most cases using a smaller token ID is fine and can reduce contract energy
597/// costs.
598///
599/// This token ID uses Unit for representing token IDs, which means only one
600/// token ID can be represented with this type and other token IDs cannot be
601/// represented. For a more general token ID type see `TokenIdVec`.
602#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Copy, Clone)]
603#[cfg_attr(
604    feature = "serde",
605    derive(SerdeSerialize, SerdeDeserialize),
606    serde(into = "String", try_from = "String")
607)]
608pub struct TokenIdUnit();
609
610impl IsTokenId for TokenIdUnit {}
611
612impl schema::SchemaType for TokenIdUnit {
613    fn get_type() -> schema::Type { schema::Type::ByteList(schema::SizeLength::U8) }
614}
615
616/// The `TokenIdUnit` is serialized with one byte with the value 0.
617impl Serial for TokenIdUnit {
618    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> { out.write_u8(0) }
619}
620
621/// The `TokenIdUnit` will deserialize one byte ensuring this contains the value
622/// 0. It will result in an error if the byte is not 0.
623impl Deserial for TokenIdUnit {
624    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
625        let byte_length = source.read_u8()?;
626        if byte_length == 0 {
627            Ok(TokenIdUnit())
628        } else {
629            Err(ParseError::default())
630        }
631    }
632}
633
634#[cfg(feature = "serde")]
635impl From<TokenIdUnit> for String {
636    fn from(_id: TokenIdUnit) -> Self { String::from("") }
637}
638
639#[cfg(feature = "serde")]
640impl TryFrom<String> for TokenIdUnit {
641    type Error = ParseError;
642
643    fn try_from(s: String) -> Result<Self, Self::Error> {
644        if s == "" {
645            Ok(Self())
646        } else {
647            Err(ParseError {})
648        }
649    }
650}
651
652macro_rules! token_amount_wrapper {
653    ($name:ident, $wrapped:ty) => {
654        #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Default)]
655        #[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
656        #[repr(transparent)]
657        pub struct $name(pub $wrapped);
658
659        impl ops::Add<Self> for $name {
660            type Output = Self;
661
662            fn add(self, rhs: Self) -> Self::Output { $name(self.0 + rhs.0) }
663        }
664
665        impl ops::AddAssign for $name {
666            fn add_assign(&mut self, other: Self) { *self = *self + other; }
667        }
668
669        impl ops::Sub<Self> for $name {
670            type Output = Self;
671
672            fn sub(self, rhs: Self) -> Self::Output { $name(self.0 - rhs.0) }
673        }
674
675        impl ops::SubAssign for $name {
676            fn sub_assign(&mut self, other: Self) { *self = *self - other; }
677        }
678
679        impl ops::Mul<$wrapped> for $name {
680            type Output = Self;
681
682            fn mul(self, rhs: $wrapped) -> Self::Output { $name(self.0 * rhs) }
683        }
684
685        impl ops::Mul<$name> for $wrapped {
686            type Output = $name;
687
688            fn mul(self, rhs: $name) -> Self::Output { $name(self * rhs.0) }
689        }
690
691        impl ops::MulAssign<$wrapped> for $name {
692            fn mul_assign(&mut self, other: $wrapped) { *self = *self * other; }
693        }
694
695        impl ops::Rem<$wrapped> for $name {
696            type Output = Self;
697
698            fn rem(self, other: $wrapped) -> Self::Output { $name(self.0 % other) }
699        }
700
701        impl ops::RemAssign<$wrapped> for $name {
702            fn rem_assign(&mut self, other: $wrapped) { *self = *self % other; }
703        }
704
705        impl iter::Sum for $name {
706            fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { iter.fold($name(0), ops::Add::add) }
707        }
708
709        impl IsTokenAmount for $name {}
710
711        /// Uses the ULeb128 encoding with up to 37 bytes for the encoding as
712        /// according to CIS-2 specification.
713        impl schema::SchemaType for $name {
714            fn get_type() -> schema::Type { schema::Type::ULeb128(37) }
715        }
716
717        impl Serial for $name {
718            fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
719                let mut value = self.0;
720                loop {
721                    let mut byte = (value as u8) & 0b0111_1111;
722                    value >>= 7;
723                    if value != 0 {
724                        byte |= 0b1000_0000;
725                    }
726                    out.write_u8(byte)?;
727
728                    if value == 0 {
729                        return Ok(());
730                    }
731                }
732            }
733        }
734
735        impl Deserial for $name {
736            fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
737                let mut result: $wrapped = 0;
738                for i in 0..37 {
739                    let byte = source.read_u8()?;
740                    let value_byte = (byte & 0b0111_1111) as $wrapped;
741                    result = result.checked_add(value_byte << (i * 7)).ok_or(ParseError {})?;
742
743                    if byte & 0b1000_0000 == 0 {
744                        return Ok($name(result));
745                    }
746                }
747                Err(ParseError {})
748            }
749        }
750
751        impl From<$wrapped> for $name {
752            fn from(v: $wrapped) -> $name { $name(v) }
753        }
754
755        impl From<$name> for $wrapped {
756            fn from(v: $name) -> $wrapped { v.0 }
757        }
758    };
759}
760
761token_amount_wrapper!(TokenAmountU128, u128);
762token_amount_wrapper!(TokenAmountU64, u64);
763token_amount_wrapper!(TokenAmountU32, u32);
764token_amount_wrapper!(TokenAmountU16, u16);
765token_amount_wrapper!(TokenAmountU8, u8);
766
767#[cfg(feature = "u256_amount")]
768mod u256_token {
769    use super::*;
770    use primitive_types::U256;
771    #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Default)]
772    #[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
773    #[cfg_attr(docsrs, cfg(feature = "u256_amount"))]
774    #[repr(transparent)]
775    pub struct TokenAmountU256(pub U256);
776
777    impl ops::Add<Self> for TokenAmountU256 {
778        type Output = Self;
779
780        fn add(self, rhs: Self) -> Self::Output { TokenAmountU256(self.0 + rhs.0) }
781    }
782
783    impl ops::AddAssign for TokenAmountU256 {
784        fn add_assign(&mut self, other: Self) { *self = *self + other; }
785    }
786
787    impl ops::Sub<Self> for TokenAmountU256 {
788        type Output = Self;
789
790        fn sub(self, rhs: Self) -> Self::Output { TokenAmountU256(self.0 - rhs.0) }
791    }
792
793    impl ops::SubAssign for TokenAmountU256 {
794        fn sub_assign(&mut self, other: Self) { *self = *self - other; }
795    }
796
797    impl ops::Mul<U256> for TokenAmountU256 {
798        type Output = Self;
799
800        fn mul(self, rhs: U256) -> Self::Output { TokenAmountU256(self.0 * rhs) }
801    }
802
803    impl ops::Mul<TokenAmountU256> for U256 {
804        type Output = TokenAmountU256;
805
806        fn mul(self, rhs: TokenAmountU256) -> Self::Output { TokenAmountU256(self * rhs.0) }
807    }
808
809    impl ops::MulAssign<U256> for TokenAmountU256 {
810        fn mul_assign(&mut self, other: U256) { *self = *self * other; }
811    }
812
813    impl ops::Rem<U256> for TokenAmountU256 {
814        type Output = Self;
815
816        fn rem(self, other: U256) -> Self::Output { TokenAmountU256(self.0 % other) }
817    }
818
819    impl ops::RemAssign<U256> for TokenAmountU256 {
820        fn rem_assign(&mut self, other: U256) { *self = *self % other; }
821    }
822
823    impl iter::Sum for TokenAmountU256 {
824        fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
825            iter.fold(TokenAmountU256(U256::zero()), ops::Add::add)
826        }
827    }
828
829    impl IsTokenAmount for TokenAmountU256 {}
830
831    /// Uses the ULeb128 encoding with up to 37 bytes for the encoding as
832    /// according to CIS-2 specification.
833    impl schema::SchemaType for TokenAmountU256 {
834        fn get_type() -> schema::Type { schema::Type::ULeb128(37) }
835    }
836
837    impl Serial for TokenAmountU256 {
838        fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
839            let mut value = self.0;
840            loop {
841                let mut byte = (value.low_u32() as u8) & 0b0111_1111;
842                value >>= 7;
843                if value != U256::zero() {
844                    byte |= 0b1000_0000;
845                }
846                out.write_u8(byte)?;
847
848                if value.is_zero() {
849                    return Ok(());
850                }
851            }
852        }
853    }
854
855    impl Deserial for TokenAmountU256 {
856        fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
857            let mut result: U256 = U256::zero();
858            for i in 0..36 {
859                let byte = source.read_u8()?;
860                let value_byte = <U256>::from(byte & 0b0111_1111);
861                result = result.checked_add(value_byte << (i * 7)).ok_or(ParseError {})?;
862                if byte & 0b1000_0000 == 0 {
863                    return Ok(TokenAmountU256(result));
864                }
865            }
866            let byte = source.read_u8()?;
867            let value_byte = byte & 0b0111_1111;
868            if value_byte & 0b1111_0000 != 0 {
869                Err(ParseError {})
870            } else {
871                let value_byte = <U256>::from(value_byte);
872                result = result.checked_add(value_byte << (36 * 7)).ok_or(ParseError {})?;
873                if byte & 0b1000_0000 == 0 {
874                    Ok(TokenAmountU256(result))
875                } else {
876                    Err(ParseError {})
877                }
878            }
879        }
880    }
881
882    impl From<U256> for TokenAmountU256 {
883        fn from(v: U256) -> TokenAmountU256 { TokenAmountU256(v) }
884    }
885
886    impl From<TokenAmountU256> for U256 {
887        fn from(v: TokenAmountU256) -> U256 { v.0 }
888    }
889
890    #[cfg(test)]
891    mod tests {
892        use super::*;
893        #[test]
894        fn serial_token_amount256_max_test() {
895            let v = TokenAmountU256(U256([u64::MAX; 4]));
896            let bytes = to_bytes(&v);
897            assert_eq!(Ok(v), from_bytes(&bytes));
898        }
899        #[test]
900        fn serial_token_amount256_0_test() {
901            let v = TokenAmountU256(U256([0; 4]));
902            let bytes = to_bytes(&v);
903            assert_eq!(Ok(v), from_bytes(&bytes));
904        }
905        #[test]
906        fn serial_token_amount_test() {
907            let v = TokenAmountU256(U256([u64::MAX, 1, 1, 1]));
908            let bytes = to_bytes(&v);
909            assert_eq!(Ok(v), from_bytes(&bytes));
910        }
911        #[test]
912        fn serial_token_amount_invalid() {
913            // fail if overflowing.
914            let mut max = to_bytes(&TokenAmountU256(U256([u64::MAX; 4])));
915            max[36] |= 0b1000_0000;
916            max.push(0b0000_1111);
917            assert_eq!(Err(ParseError {}), from_bytes::<TokenAmountU256>(&max));
918        }
919    }
920}
921
922#[cfg(feature = "u256_amount")]
923pub use u256_token::*;
924
925/// An untagged event of a transfer of some amount of tokens from one address to
926/// another. For a tagged version, use `Cis2Event`.
927// Note: For the serialization to be derived according to the CIS2
928// specification, the order of the fields cannot be changed.
929#[derive(Debug, Serialize, SchemaType, PartialEq, Eq)]
930pub struct TransferEvent<T: IsTokenId, A: IsTokenAmount> {
931    /// The ID of the token being transferred.
932    pub token_id: T,
933    /// The amount of tokens being transferred.
934    pub amount:   A,
935    /// The address owning these tokens before the transfer.
936    pub from:     Address,
937    /// The address to receive these tokens after the transfer.
938    pub to:       Address,
939}
940
941/// An untagged event of tokens being minted, could be a new token type or
942/// extending the total supply of existing token.
943/// For a tagged version, use `Cis2Event`.
944// Note: For the serialization to be derived according to the CIS2
945// specification, the order of the fields cannot be changed.
946#[derive(Debug, Serialize, SchemaType, PartialEq, Eq)]
947pub struct MintEvent<T: IsTokenId, A: IsTokenAmount> {
948    /// The ID of the token being minted, (possibly a new token ID).
949    pub token_id: T,
950    /// The number of tokens being minted, this is allowed to be 0 as well.
951    pub amount:   A,
952    /// The initial owner of these newly minted amount of tokens.
953    pub owner:    Address,
954}
955
956/// An untagged event of some amount of a token type being burned.
957/// For a tagged version, use `Cis2Event`.
958// Note: For the serialization to be derived according to the CIS2
959// specification, the order of the fields cannot be changed.
960#[derive(Debug, Serialize, SchemaType, PartialEq, Eq)]
961pub struct BurnEvent<T: IsTokenId, A: IsTokenAmount> {
962    /// The ID of the token where an amount is being burned.
963    pub token_id: T,
964    /// The amount of tokens being burned.
965    pub amount:   A,
966    /// The owner of the tokens being burned.
967    pub owner:    Address,
968}
969
970/// An untagged event of an update to an operator address for an owner address.
971/// For a tagged version, use `Cis2Event`.
972// Note: For the serialization to be derived according to the CIS2
973// specification, the order of the fields cannot be changed.
974#[derive(Debug, Serialize, SchemaType, PartialEq, Eq)]
975pub struct UpdateOperatorEvent {
976    /// The update to the operator.
977    pub update:   OperatorUpdate,
978    /// The address for whom, the operator is updated.
979    pub owner:    Address,
980    /// The address who is the operator being updated.
981    pub operator: Address,
982}
983
984/// An untagged event for setting the metadata for a token.
985/// For a tagged version, use `Cis2Event`.
986// Note: For the serialization to be derived according to the CIS2
987// specification, the order of the fields cannot be changed.
988#[derive(Debug, Serialize, SchemaType, PartialEq, Eq)]
989pub struct TokenMetadataEvent<T: IsTokenId> {
990    /// The ID of the token.
991    pub token_id:     T,
992    /// The location of the metadata.
993    pub metadata_url: MetadataUrl,
994}
995
996/// Tagged CIS2 event to be serialized for the event log.
997#[derive(Debug, Serialize, PartialEq, Eq)]
998#[concordium(repr(u8))]
999pub enum Cis2Event<T: IsTokenId, A: IsTokenAmount> {
1000    /// A transfer between two addresses of some amount of tokens.
1001    #[concordium(tag = 255)]
1002    Transfer(TransferEvent<T, A>),
1003    /// Creation of new tokens, could be both adding some amounts to an existing
1004    /// token or introduce an entirely new token ID.
1005    #[concordium(tag = 254)]
1006    Mint(MintEvent<T, A>),
1007    /// Destruction of tokens removing some amounts of a token.
1008    #[concordium(tag = 253)]
1009    Burn(BurnEvent<T, A>),
1010    /// Updates to an operator for a specific address and token id.
1011    #[concordium(tag = 252)]
1012    UpdateOperator(UpdateOperatorEvent),
1013    /// Setting the metadata for a token.
1014    #[concordium(tag = 251)]
1015    TokenMetadata(TokenMetadataEvent<T>),
1016}
1017
1018// Implemented manually to use named fields in the schema thereby simplifying
1019// it.
1020impl<T: IsTokenId, A: IsTokenAmount> schema::SchemaType for Cis2Event<T, A> {
1021    fn get_type() -> schema::Type {
1022        let mut event_map = BTreeMap::new();
1023        event_map.insert(
1024            TRANSFER_EVENT_TAG,
1025            (
1026                "Transfer".to_string(),
1027                schema::Fields::Named(vec![
1028                    (String::from("token_id"), T::get_type()),
1029                    (String::from("amount"), A::get_type()),
1030                    (String::from("from"), Address::get_type()),
1031                    (String::from("to"), Address::get_type()),
1032                ]),
1033            ),
1034        );
1035        event_map.insert(
1036            MINT_EVENT_TAG,
1037            (
1038                "Mint".to_string(),
1039                schema::Fields::Named(vec![
1040                    (String::from("token_id"), T::get_type()),
1041                    (String::from("amount"), A::get_type()),
1042                    (String::from("owner"), Address::get_type()),
1043                ]),
1044            ),
1045        );
1046        event_map.insert(
1047            BURN_EVENT_TAG,
1048            (
1049                "Burn".to_string(),
1050                schema::Fields::Named(vec![
1051                    (String::from("token_id"), T::get_type()),
1052                    (String::from("amount"), A::get_type()),
1053                    (String::from("owner"), Address::get_type()),
1054                ]),
1055            ),
1056        );
1057        event_map.insert(
1058            UPDATE_OPERATOR_EVENT_TAG,
1059            (
1060                "UpdateOperator".to_string(),
1061                schema::Fields::Named(vec![
1062                    (String::from("update"), OperatorUpdate::get_type()),
1063                    (String::from("owner"), Address::get_type()),
1064                    (String::from("operator"), Address::get_type()),
1065                ]),
1066            ),
1067        );
1068        event_map.insert(
1069            TOKEN_METADATA_EVENT_TAG,
1070            (
1071                "TokenMetadata".to_string(),
1072                schema::Fields::Named(vec![
1073                    (String::from("token_id"), T::get_type()),
1074                    (String::from("metadata_url"), MetadataUrl::get_type()),
1075                ]),
1076            ),
1077        );
1078        schema::Type::TaggedEnum(event_map)
1079    }
1080}
1081
1082/// The different errors the contract can produce.
1083#[derive(Debug, PartialEq, Eq, SchemaType, Serial, Deserial)]
1084pub enum Cis2Error<R> {
1085    /// Invalid token id (Error code: -42000001).
1086    InvalidTokenId,
1087    /// The balance of the token owner is insufficient for the transfer (Error
1088    /// code: -42000002).
1089    InsufficientFunds,
1090    /// Sender is unauthorized to call this function (Error code: -42000003).
1091    Unauthorized,
1092    /// Custom error
1093    Custom(R),
1094}
1095
1096/// Convert `Cis2Error` into a reject with error code:
1097/// - InvalidTokenId: -42000001
1098/// - InsufficientFunds: -42000002
1099/// - Unauthorized: -42000003
1100/// - Custom: The error code of `R`.
1101///
1102/// Also serializes the `Cis2Error` and adds it as the return value.
1103impl<R: Into<Reject> + Serial> From<Cis2Error<R>> for Reject {
1104    fn from(err: Cis2Error<R>) -> Self {
1105        let return_value = Some(to_bytes(&err));
1106        let error_code = match err {
1107            Cis2Error::InvalidTokenId => unsafe {
1108                crate::num::NonZeroI32::new_unchecked(-42000001)
1109            },
1110            Cis2Error::InsufficientFunds => unsafe {
1111                crate::num::NonZeroI32::new_unchecked(-42000002)
1112            },
1113            Cis2Error::Unauthorized => unsafe { crate::num::NonZeroI32::new_unchecked(-42000003) },
1114            Cis2Error::Custom(reject) => reject.into().error_code,
1115        };
1116        Self {
1117            error_code,
1118            return_value,
1119        }
1120    }
1121}
1122
1123impl<X> From<LogError> for Cis2Error<X>
1124where
1125    X: From<LogError>,
1126{
1127    #[inline]
1128    /// Converts the error by wrapping it in [Self::Custom].
1129    fn from(err: LogError) -> Self { Cis2Error::Custom(X::from(err)) }
1130}
1131
1132impl<X> From<ParseError> for Cis2Error<X>
1133where
1134    X: From<ParseError>,
1135{
1136    #[inline]
1137    /// Converts the error by wrapping it in [Self::Custom].
1138    fn from(err: ParseError) -> Self { Cis2Error::Custom(X::from(err)) }
1139}
1140
1141impl<T, X> From<CallContractError<T>> for Cis2Error<X>
1142where
1143    X: From<CallContractError<T>>,
1144{
1145    #[inline]
1146    /// Converts the error by wrapping it in [Self::Custom].
1147    fn from(err: CallContractError<T>) -> Self { Cis2Error::Custom(X::from(err)) }
1148}
1149
1150impl<X> From<TransferError> for Cis2Error<X>
1151where
1152    X: From<TransferError>,
1153{
1154    #[inline]
1155    /// Converts the error by wrapping it in [Self::Custom].
1156    fn from(err: TransferError) -> Self { Cis2Error::Custom(X::from(err)) }
1157}
1158
1159impl<X> From<UpgradeError> for Cis2Error<X>
1160where
1161    X: From<UpgradeError>,
1162{
1163    #[inline]
1164    /// Converts the error by wrapping it in [Self::Custom].
1165    fn from(err: UpgradeError) -> Self { Cis2Error::Custom(X::from(err)) }
1166}
1167
1168impl<X> From<QueryAccountBalanceError> for Cis2Error<X>
1169where
1170    X: From<QueryAccountBalanceError>,
1171{
1172    #[inline]
1173    /// Converts the error by wrapping it in [Self::Custom].
1174    fn from(err: QueryAccountBalanceError) -> Self { Cis2Error::Custom(X::from(err)) }
1175}
1176
1177impl<X> From<QueryContractBalanceError> for Cis2Error<X>
1178where
1179    X: From<QueryContractBalanceError>,
1180{
1181    #[inline]
1182    /// Converts the error by wrapping it in [Self::Custom].
1183    fn from(err: QueryContractBalanceError) -> Self { Cis2Error::Custom(X::from(err)) }
1184}
1185
1186impl<X> From<NewReceiveNameError> for Cis2Error<X>
1187where
1188    X: From<NewReceiveNameError>,
1189{
1190    #[inline]
1191    /// Converts the error by wrapping it in [Self::Custom].
1192    fn from(err: NewReceiveNameError) -> Self { Cis2Error::Custom(X::from(err)) }
1193}
1194
1195impl<X> From<CheckAccountSignatureError> for Cis2Error<X>
1196where
1197    X: From<CheckAccountSignatureError>,
1198{
1199    #[inline]
1200    /// Converts the error by wrapping it in [Self::Custom].
1201    fn from(err: CheckAccountSignatureError) -> Self { Cis2Error::Custom(X::from(err)) }
1202}
1203
1204impl<X> From<QueryAccountPublicKeysError> for Cis2Error<X>
1205where
1206    X: From<QueryAccountPublicKeysError>,
1207{
1208    #[inline]
1209    /// Converts the error by wrapping it in [Self::Custom].
1210    fn from(err: QueryAccountPublicKeysError) -> Self { Cis2Error::Custom(X::from(err)) }
1211}
1212
1213impl<X> From<NewContractNameError> for Cis2Error<X>
1214where
1215    X: From<NewContractNameError>,
1216{
1217    #[inline]
1218    /// Converts the error by wrapping it in [Self::Custom].
1219    fn from(err: NewContractNameError) -> Self { Cis2Error::Custom(X::from(err)) }
1220}
1221
1222/// The receiving address for a transfer, similar to the Address type, but
1223/// contains extra information when the receiver address is a contract.
1224// Note: For the serialization to be derived according to the CIS2
1225// specification, the order of the variants and the order of their fields
1226// cannot be changed.
1227#[derive(Debug, Serialize, Clone, SchemaType)]
1228#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
1229pub enum Receiver {
1230    /// The receiver is an account address.
1231    Account(
1232        /// The receiving address.
1233        AccountAddress,
1234    ),
1235    /// The receiver is a contract address.
1236    Contract(
1237        /// The receiving address.
1238        ContractAddress,
1239        /// The function to call on the receiving contract.
1240        OwnedEntrypointName,
1241    ),
1242}
1243
1244impl Receiver {
1245    /// Construct a receiver from an account address.
1246    pub fn from_account(address: AccountAddress) -> Self { Receiver::Account(address) }
1247
1248    /// Construct a receiver from a contract address.
1249    pub fn from_contract(address: ContractAddress, function: OwnedEntrypointName) -> Self {
1250        Receiver::Contract(address, function)
1251    }
1252
1253    /// Get the Address of the receiver.
1254    pub fn address(&self) -> Address {
1255        match self {
1256            Receiver::Account(address) => Address::Account(*address),
1257            Receiver::Contract(address, ..) => Address::Contract(*address),
1258        }
1259    }
1260}
1261
1262impl From<AccountAddress> for Receiver {
1263    fn from(address: AccountAddress) -> Self { Self::from_account(address) }
1264}
1265
1266/// Additional information to include with a transfer.
1267#[derive(Debug, Serialize, Clone)]
1268#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
1269#[concordium(transparent)]
1270pub struct AdditionalData(#[concordium(size_length = 2)] Vec<u8>);
1271
1272// Implemented manually to display the AdditionalData as a hex string.
1273impl schema::SchemaType for AdditionalData {
1274    fn get_type() -> schema::Type { schema::Type::ByteList(schema::SizeLength::U16) }
1275}
1276
1277impl AdditionalData {
1278    /// Construct an AdditionalData containing no data.
1279    pub fn empty() -> Self { AdditionalData(Vec::new()) }
1280}
1281
1282impl From<Vec<u8>> for AdditionalData {
1283    fn from(data: Vec<u8>) -> Self { AdditionalData(data) }
1284}
1285
1286impl AsRef<[u8]> for AdditionalData {
1287    fn as_ref(&self) -> &[u8] { &self.0 }
1288}
1289
1290/// A single transfer of some amount of a token.
1291// Note: For the serialization to be derived according to the CIS2
1292// specification, the order of the fields cannot be changed.
1293#[derive(Debug, Serialize, Clone, SchemaType)]
1294#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
1295pub struct Transfer<T: IsTokenId, A: IsTokenAmount> {
1296    /// The ID of the token being transferred.
1297    pub token_id: T,
1298    /// The amount of tokens being transferred.
1299    pub amount:   A,
1300    /// The address owning the tokens being transferred.
1301    pub from:     Address,
1302    /// The address receiving the tokens being transferred.
1303    pub to:       Receiver,
1304    /// Additional data to include in the transfer.
1305    /// Can be used for additional arguments.
1306    pub data:     AdditionalData,
1307}
1308
1309/// The parameter type for the contract function `transfer`.
1310#[derive(Debug, Serialize, Clone, SchemaType)]
1311#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
1312#[concordium(transparent)]
1313pub struct TransferParams<T: IsTokenId, A: IsTokenAmount>(
1314    #[concordium(size_length = 2)] pub Vec<Transfer<T, A>>,
1315);
1316
1317impl<T: IsTokenId, A: IsTokenAmount> From<Vec<Transfer<T, A>>> for TransferParams<T, A> {
1318    fn from(transfers: Vec<Transfer<T, A>>) -> Self { TransferParams(transfers) }
1319}
1320
1321impl<T: IsTokenId, A: IsTokenAmount> AsRef<[Transfer<T, A>]> for TransferParams<T, A> {
1322    fn as_ref(&self) -> &[Transfer<T, A>] { &self.0 }
1323}
1324
1325/// The update to an the operator.
1326// Note: For the serialization to be derived according to the CIS2
1327// specification, the order of the variants cannot be changed.
1328#[derive(Debug, Serialize, Clone, Copy, SchemaType, PartialEq, Eq)]
1329#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
1330pub enum OperatorUpdate {
1331    /// Remove the operator.
1332    Remove,
1333    /// Add an address as an operator.
1334    Add,
1335}
1336
1337/// A single update of an operator.
1338// Note: For the serialization to be derived according to the CIS2
1339// specification, the order of the fields cannot be changed.
1340#[derive(Debug, Serialize, Clone, SchemaType, PartialEq, Eq)]
1341#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
1342pub struct UpdateOperator {
1343    /// The update for this operator.
1344    pub update:   OperatorUpdate,
1345    /// The address which is either added or removed as an operator.
1346    /// Note: The address for whom this will become an operator is the sender of
1347    /// the contract transaction.
1348    pub operator: Address,
1349}
1350
1351/// The parameter type for the contract function `updateOperator`.
1352#[derive(Debug, Serialize, Clone, SchemaType)]
1353#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
1354#[concordium(transparent)]
1355pub struct UpdateOperatorParams(#[concordium(size_length = 2)] pub Vec<UpdateOperator>);
1356
1357/// A query for the balance of a given address for a given token.
1358// Note: For the serialization to be derived according to the CIS2
1359// specification, the order of the fields cannot be changed.
1360#[derive(Debug, Serialize, SchemaType)]
1361pub struct BalanceOfQuery<T: IsTokenId> {
1362    /// The ID of the token for which to query the balance of.
1363    pub token_id: T,
1364    /// The address for which to query the balance of.
1365    pub address:  Address,
1366}
1367
1368/// The parameter type for the contract function `balanceOf`.
1369// Note: For the serialization to be derived according to the CIS2
1370// specification, the order of the fields cannot be changed.
1371#[derive(Debug, Serialize, SchemaType)]
1372#[concordium(transparent)]
1373pub struct BalanceOfQueryParams<T: IsTokenId> {
1374    /// List of balance queries.
1375    #[concordium(size_length = 2)]
1376    pub queries: Vec<BalanceOfQuery<T>>,
1377}
1378
1379/// The response which is sent back when calling the contract function
1380/// `balanceOf`.
1381/// It consists of the list of results corresponding to the list of queries.
1382#[derive(Debug, Serialize, SchemaType, PartialEq, Eq)]
1383#[concordium(transparent)]
1384pub struct BalanceOfQueryResponse<A: IsTokenAmount>(#[concordium(size_length = 2)] pub Vec<A>);
1385
1386impl<A: IsTokenAmount> From<Vec<A>> for BalanceOfQueryResponse<A> {
1387    fn from(results: Vec<A>) -> Self { BalanceOfQueryResponse(results) }
1388}
1389
1390impl<A: IsTokenAmount> AsRef<[A]> for BalanceOfQueryResponse<A> {
1391    fn as_ref(&self) -> &[A] { &self.0 }
1392}
1393
1394/// A query for the operator of a given address for a given token.
1395// Note: For the serialization to be derived according to the CIS2
1396// specification, the order of the fields cannot be changed.
1397#[derive(Debug, Serialize, SchemaType)]
1398pub struct OperatorOfQuery {
1399    /// The owner address to inspect.
1400    pub owner:   Address,
1401    /// The address for which to check for being an operator of the owner.
1402    pub address: Address,
1403}
1404
1405/// The parameter type for the contract function `operatorOf`.
1406#[derive(Debug, Serialize, SchemaType)]
1407#[concordium(transparent)]
1408pub struct OperatorOfQueryParams {
1409    /// List of operatorOf queries.
1410    #[concordium(size_length = 2)]
1411    pub queries: Vec<OperatorOfQuery>,
1412}
1413
1414/// The response which is sent back when calling the contract function
1415/// `operatorOf`.
1416/// It consists of the list of result in the same order and length as the
1417/// queries in the parameter.
1418#[derive(Debug, Serialize, SchemaType, PartialEq, Eq)]
1419#[concordium(transparent)]
1420pub struct OperatorOfQueryResponse(#[concordium(size_length = 2)] pub Vec<bool>);
1421
1422impl From<Vec<bool>> for OperatorOfQueryResponse {
1423    fn from(results: Vec<bool>) -> Self { OperatorOfQueryResponse(results) }
1424}
1425
1426impl AsRef<[bool]> for OperatorOfQueryResponse {
1427    fn as_ref(&self) -> &[bool] { &self.0 }
1428}
1429
1430/// The parameter type for the contract function `tokenMetadata`.
1431// Note: For the serialization to be derived according to the CIS2
1432// specification, the order of the fields cannot be changed.
1433#[derive(Debug, Serialize, SchemaType)]
1434#[concordium(transparent)]
1435pub struct TokenMetadataQueryParams<T: IsTokenId> {
1436    /// List of balance queries.
1437    #[concordium(size_length = 2)]
1438    pub queries: Vec<T>,
1439}
1440
1441/// The response which is sent back when calling the contract function
1442/// `tokenMetadata`.
1443/// It consists of the list of results corresponding to the list of queries.
1444#[derive(Debug, Serialize, SchemaType)]
1445#[concordium(transparent)]
1446pub struct TokenMetadataQueryResponse(#[concordium(size_length = 2)] pub Vec<MetadataUrl>);
1447
1448impl From<Vec<MetadataUrl>> for TokenMetadataQueryResponse {
1449    fn from(results: Vec<MetadataUrl>) -> Self { TokenMetadataQueryResponse(results) }
1450}
1451
1452impl AsRef<[MetadataUrl]> for TokenMetadataQueryResponse {
1453    fn as_ref(&self) -> &[MetadataUrl] { &self.0 }
1454}
1455
1456/// Generic parameter type for a contract function which receives CIS2 tokens.
1457// Note: For the serialization to be derived according to the CIS2
1458// specification, the order of the fields cannot be changed.
1459#[derive(Debug, Serialize, SchemaType)]
1460#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
1461pub struct OnReceivingCis2Params<T, A> {
1462    /// The ID of the token received.
1463    pub token_id: T,
1464    /// The amount of tokens received.
1465    pub amount:   A,
1466    /// The previous owner of the tokens.
1467    pub from:     Address,
1468    /// Some extra information which was sent as part of the transfer.
1469    pub data:     AdditionalData,
1470}
1471
1472/// Specific parameter type for a contract function which receives CIS2 tokens
1473/// with a specific type D for the AdditionalData.
1474// Note: For the serialization to be derived according to the CIS2
1475// specification, the order of the fields cannot be changed.
1476#[derive(Debug)]
1477#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
1478pub struct OnReceivingCis2DataParams<T, A, D> {
1479    /// The ID of the token received.
1480    pub token_id: T,
1481    /// The amount of tokens received.
1482    pub amount:   A,
1483    /// The previous owner of the tokens.
1484    pub from:     Address,
1485    /// Some extra information which was sent as part of the transfer.
1486    pub data:     D,
1487}
1488
1489/// Deserial trait for OnReceivingCis2DataParams<T, A, D>.
1490impl<T: Deserial, A: Deserial, D: Deserial> Deserial for OnReceivingCis2DataParams<T, A, D> {
1491    fn deserial<R: Read>(source: &mut R) -> ParseResult<Self> {
1492        let params: OnReceivingCis2Params<T, A> = source.get()?;
1493        let additional_data_type: D = from_bytes(params.data.as_ref())?;
1494        Ok(OnReceivingCis2DataParams {
1495            token_id: params.token_id,
1496            amount:   params.amount,
1497            from:     params.from,
1498            data:     additional_data_type,
1499        })
1500    }
1501}
1502
1503/// Serial trait for OnReceivingCis2DataParams<T, A, D>.
1504impl<T: Serial, A: Serial, D: Serial> Serial for OnReceivingCis2DataParams<T, A, D> {
1505    fn serial<W: Write>(&self, out: &mut W) -> Result<(), W::Err> {
1506        self.token_id.serial(out)?;
1507        self.amount.serial(out)?;
1508        self.from.serial(out)?;
1509        let add = AdditionalData(to_bytes(&self.data));
1510        add.serial(out)?;
1511        Ok(())
1512    }
1513}
1514
1515/// SchemaType trait for OnReceivingCis2DataParams<T, A, D>.
1516impl<T: SchemaType, A: SchemaType, D> SchemaType for OnReceivingCis2DataParams<T, A, D> {
1517    fn get_type() -> schema::Type {
1518        schema::Type::Struct(schema::Fields::Named(vec![
1519            (String::from("token_id"), T::get_type()),
1520            (String::from("amount"), A::get_type()),
1521            (String::from("from"), Address::get_type()),
1522            // The data field is serialized the same as AdditionalData.
1523            (String::from("data"), AdditionalData::get_type()),
1524        ]))
1525    }
1526}
1527
1528/// Identifier for a smart contract standard.
1529/// Consists of a string of ASCII characters up to a length of 255.
1530///
1531/// See [StandardIdentifierOwned] for the owned version.
1532#[derive(Debug, Serial, PartialEq, Eq)]
1533pub struct StandardIdentifier<'a> {
1534    #[concordium(size_length = 1)]
1535    id: &'a str,
1536}
1537
1538/// String is not a valid standard identifier. Ensure the length is less than
1539/// 256 and it only contains ASCII characters.
1540#[derive(Default)]
1541pub struct InvalidStandardIdentifierError;
1542
1543impl<'a> StandardIdentifier<'a> {
1544    /// Validate and construct a standard identifier.
1545    pub fn new(id: &'a str) -> Result<Self, InvalidStandardIdentifierError> {
1546        if id.len() > 255 || !id.is_ascii() {
1547            Err(InvalidStandardIdentifierError)
1548        } else {
1549            Ok(Self {
1550                id,
1551            })
1552        }
1553    }
1554
1555    /// Construct a standard identifier without validation.
1556    pub const fn new_unchecked(id: &'a str) -> Self {
1557        Self {
1558            id,
1559        }
1560    }
1561
1562    /// Convert to owned standard identifier.
1563    pub fn to_owned(&self) -> StandardIdentifierOwned {
1564        StandardIdentifierOwned::new_unchecked(self.id.to_string())
1565    }
1566}
1567
1568/// Owned identifier for a smart contract standard.
1569/// Consists of a string of ASCII characters up to a length of 255.
1570///
1571/// See [StandardIdentifier] for the borrowed version.
1572#[derive(Debug, Serialize, PartialEq, Eq, SchemaType, Clone)]
1573#[concordium(transparent)]
1574pub struct StandardIdentifierOwned {
1575    #[concordium(size_length = 1)]
1576    id: String,
1577}
1578
1579impl StandardIdentifierOwned {
1580    /// Validate and construct a standard identifier.
1581    pub fn new(id: String) -> Result<Self, InvalidStandardIdentifierError> {
1582        if id.len() > 255 || !id.is_ascii() {
1583            Err(InvalidStandardIdentifierError)
1584        } else {
1585            Ok(Self {
1586                id,
1587            })
1588        }
1589    }
1590
1591    /// Construct a standard identifier without validation.
1592    pub fn new_unchecked(id: String) -> Self {
1593        Self {
1594            id,
1595        }
1596    }
1597
1598    /// Convert to standard identifier.
1599    pub fn as_standard_identifier(&self) -> StandardIdentifier {
1600        StandardIdentifier::new_unchecked(&self.id)
1601    }
1602}
1603
1604/// The parameter type for the contract function `supports`.
1605#[derive(Debug, Serialize, SchemaType)]
1606#[concordium(transparent)]
1607pub struct SupportsQueryParams {
1608    /// The list of support queries.
1609    #[concordium(size_length = 2)]
1610    pub queries: Vec<StandardIdentifierOwned>,
1611}
1612
1613/// The query result type for whether a smart contract supports a standard.
1614// Note: For the serialization to be derived according to the CIS0
1615// specification, the order of the variants and their fields cannot be changed.
1616#[derive(Debug, Serialize, SchemaType)]
1617pub enum SupportResult {
1618    /// The standard is not supported.
1619    NoSupport,
1620    /// The standard is supported by the current contract address.
1621    Support,
1622    /// The standard is supported by using another contract address.
1623    SupportBy(#[concordium(size_length = 1)] Vec<ContractAddress>),
1624}
1625
1626/// The response which is sent back when calling the contract function
1627/// `supports`. It consists of a list of results corresponding to the list of
1628/// queries.
1629#[derive(Debug, Serialize, SchemaType)]
1630#[concordium(transparent)]
1631pub struct SupportsQueryResponse {
1632    /// List of support results corresponding to the list of queries.
1633    #[concordium(size_length = 2)]
1634    pub results: Vec<SupportResult>,
1635}
1636
1637impl From<Vec<SupportResult>> for SupportsQueryResponse {
1638    fn from(results: Vec<SupportResult>) -> Self {
1639        SupportsQueryResponse {
1640            results,
1641        }
1642    }
1643}
1644
1645impl AsRef<[SupportResult]> for SupportsQueryResponse {
1646    fn as_ref(&self) -> &[SupportResult] { &self.results }
1647}
1648
1649#[cfg(test)]
1650mod test {
1651    use super::*;
1652
1653    #[test]
1654    fn serial_token_amount128_127_test() {
1655        let amount = TokenAmountU128::from(127);
1656        let bytes = to_bytes(&amount);
1657        assert_eq!(bytes, vec![127])
1658    }
1659
1660    #[test]
1661    fn serial_token_amount128_max_test() {
1662        let amount = TokenAmountU128::from(u128::MAX);
1663        let bytes = to_bytes(&amount);
1664        assert_eq!(bytes, vec![
1665            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1666            255, 0b00000011
1667        ])
1668    }
1669
1670    #[test]
1671    fn deserial_token_amount128_127_test() {
1672        let amount: TokenAmountU128 = from_bytes(&[127]).expect("Failed to parse bytes");
1673        assert_eq!(amount, TokenAmountU128::from(127))
1674    }
1675
1676    #[test]
1677    fn deserial_token_amount128_max_test() {
1678        let amount: TokenAmountU128 = from_bytes(&[
1679            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1680            255, 0b00000011,
1681        ])
1682        .expect("Failed to parse bytes");
1683        assert_eq!(amount, TokenAmountU128::from(u128::MAX))
1684    }
1685
1686    #[test]
1687    fn serial_token_amount64_127_test() {
1688        let amount = TokenAmountU64::from(127);
1689        let bytes = to_bytes(&amount);
1690        assert_eq!(bytes, vec![127])
1691    }
1692
1693    #[test]
1694    fn serial_token_amount64_max_test() {
1695        let amount = TokenAmountU64::from(u64::MAX);
1696        let bytes = to_bytes(&amount);
1697        assert_eq!(bytes, vec![255, 255, 255, 255, 255, 255, 255, 255, 255, 0b00000001])
1698    }
1699
1700    #[test]
1701    fn deserial_token_amount64_127_test() {
1702        let amount: TokenAmountU64 = from_bytes(&[127]).expect("Failed to parse bytes");
1703        assert_eq!(amount, TokenAmountU64::from(127))
1704    }
1705
1706    #[test]
1707    fn deserial_token_amount64_max_test() {
1708        let amount: TokenAmountU64 =
1709            from_bytes(&[255, 255, 255, 255, 255, 255, 255, 255, 255, 0b00000001])
1710                .expect("Failed to parse bytes");
1711        assert_eq!(amount, TokenAmountU64::from(u64::MAX))
1712    }
1713
1714    #[test]
1715    fn serial_token_amount32_127_test() {
1716        let amount = TokenAmountU32::from(127);
1717        let bytes = to_bytes(&amount);
1718        assert_eq!(bytes, vec![127])
1719    }
1720
1721    #[test]
1722    fn serial_token_amount32_max_test() {
1723        let amount = TokenAmountU32::from(u32::MAX);
1724        let bytes = to_bytes(&amount);
1725        assert_eq!(bytes, vec![255, 255, 255, 255, 0b00001111])
1726    }
1727
1728    #[test]
1729    fn deserial_token_amount32_127_test() {
1730        let amount: TokenAmountU32 = from_bytes(&[127]).expect("Failed to parse bytes");
1731        assert_eq!(amount, TokenAmountU32::from(127))
1732    }
1733
1734    #[test]
1735    fn deserial_token_amount32_max_test() {
1736        let amount: TokenAmountU32 =
1737            from_bytes(&[255, 255, 255, 255, 0b00001111]).expect("Failed to parse bytes");
1738        assert_eq!(amount, TokenAmountU32::from(u32::MAX))
1739    }
1740
1741    #[test]
1742    fn serial_token_amount16_127_test() {
1743        let amount = TokenAmountU16::from(127);
1744        let bytes = to_bytes(&amount);
1745        assert_eq!(bytes, vec![127])
1746    }
1747
1748    #[test]
1749    fn serial_token_amount16_max_test() {
1750        let amount = TokenAmountU16::from(u16::MAX);
1751        let bytes = to_bytes(&amount);
1752        assert_eq!(bytes, vec![255, 255, 0b00000011])
1753    }
1754
1755    #[test]
1756    fn deserial_token_amount16_127_test() {
1757        let amount: TokenAmountU16 = from_bytes(&[127]).expect("Failed to parse bytes");
1758        assert_eq!(amount, TokenAmountU16::from(127))
1759    }
1760
1761    #[test]
1762    fn deserial_token_amount16_max_test() {
1763        let amount: TokenAmountU16 =
1764            from_bytes(&[255, 255, 0b00000011]).expect("Failed to parse bytes");
1765        assert_eq!(amount, TokenAmountU16::from(u16::MAX))
1766    }
1767
1768    #[test]
1769    fn serial_token_amount8_127_test() {
1770        let amount = TokenAmountU8::from(127);
1771        let bytes = to_bytes(&amount);
1772        assert_eq!(bytes, vec![127])
1773    }
1774
1775    #[test]
1776    fn serial_token_amount8_max_test() {
1777        let amount = TokenAmountU8::from(u8::MAX);
1778        let bytes = to_bytes(&amount);
1779        assert_eq!(bytes, vec![255, 0b00000001])
1780    }
1781
1782    #[test]
1783    fn deserial_token_amount8_127_test() {
1784        let amount: TokenAmountU8 = from_bytes(&[127]).expect("Failed to parse bytes");
1785        assert_eq!(amount, TokenAmountU8::from(127))
1786    }
1787
1788    #[test]
1789    fn deserial_token_amount8_max_test() {
1790        let amount: TokenAmountU8 = from_bytes(&[255, 0b00000001]).expect("Failed to parse bytes");
1791        assert_eq!(amount, TokenAmountU8::from(u8::MAX))
1792    }
1793
1794    #[test]
1795    fn token_id_vec_from_str_test() {
1796        let id = TokenIdVec(vec![1, 2, 3, 255]);
1797        assert_eq!(id.to_string().parse(), Ok(id))
1798    }
1799
1800    #[test]
1801    fn parse_bytes_exact_test() {
1802        // the hex string "deadBEEF" corresponds to `0xDEADBEEF_u32.to_be_bytes()`,
1803        // since the strings are written in little endian order, i.e. "de" is the first
1804        // byte, "ad" is the second, etc.
1805        assert_eq!(parse_bytes_exact::<4>("deadBEEF"), Ok(0xDEADBEEF_u32.to_be_bytes()));
1806        // odd number of characters fails
1807        assert!(parse_bytes_exact::<3>("deadBEE").is_err());
1808        // invalid character fails
1809        assert!(parse_bytes_exact::<4>("deadBEEK").is_err());
1810    }
1811}