1
1
//! Contains the `Amount` type, which represents amounts of tokens transferred.
2
2
3
+ use crate :: prelude:: * ;
3
4
use core:: { ops:: Deref , str:: FromStr } ;
4
5
use derive_more:: { Display , From , Into } ;
5
6
@@ -28,6 +29,54 @@ impl parity_scale_codec::WrapperTypeDecode for Amount {
28
29
#[ cfg( feature = "parity-scale-codec" ) ]
29
30
impl parity_scale_codec:: WrapperTypeEncode for Amount { }
30
31
32
+ #[ cfg( feature = "borsh" ) ]
33
+ impl borsh:: BorshSerialize for Amount {
34
+ fn serialize < W : borsh:: maybestd:: io:: Write > (
35
+ & self ,
36
+ writer : & mut W ,
37
+ ) -> borsh:: maybestd:: io:: Result < ( ) > {
38
+ // Note: a "word" is 8 bytes (i.e. a u64)
39
+ let words = self . as_slice ( ) ;
40
+ let bytes: Vec < u8 > = words. iter ( ) . flat_map ( |word| word. to_be_bytes ( ) ) . collect ( ) ;
41
+
42
+ writer. write_all ( & bytes)
43
+ }
44
+ }
45
+ #[ cfg( feature = "borsh" ) ]
46
+ impl borsh:: BorshDeserialize for Amount {
47
+ fn deserialize_reader < R : borsh:: maybestd:: io:: Read > (
48
+ reader : & mut R ,
49
+ ) -> borsh:: maybestd:: io:: Result < Self > {
50
+ const NUM_BYTES_IN_U64 : usize = 8 ;
51
+ const NUM_WORDS_IN_U256 : usize = 4 ;
52
+
53
+ let mut buf = [ 0 ; 32 ] ;
54
+ let bytes_read = reader. read ( & mut buf) ?;
55
+ if bytes_read != 32 {
56
+ return Err ( borsh:: maybestd:: io:: Error :: new (
57
+ borsh:: maybestd:: io:: ErrorKind :: InvalidInput ,
58
+ format ! ( "Expected to read 32 bytes, read {bytes_read}" ) ,
59
+ ) ) ;
60
+ }
61
+
62
+ let words: Vec < u64 > = buf
63
+ . chunks_exact ( NUM_BYTES_IN_U64 )
64
+ . map ( |word| {
65
+ let word: [ u8 ; NUM_BYTES_IN_U64 ] = word
66
+ . try_into ( )
67
+ . expect ( "exact chunks of 8 bytes are expected to be 8 bytes" ) ;
68
+ u64:: from_be_bytes ( word)
69
+ } )
70
+ . collect ( ) ;
71
+
72
+ let four_words: [ u64 ; NUM_WORDS_IN_U256 ] = words
73
+ . try_into ( )
74
+ . expect ( "U256 is always 4 four words, and we confirmed that we read 32 bytes" ) ;
75
+
76
+ Ok ( four_words. into ( ) )
77
+ }
78
+ }
79
+
31
80
impl Deref for Amount {
32
81
type Target = [ u64 ; 4 ] ;
33
82
@@ -83,10 +132,10 @@ where
83
132
}
84
133
85
134
#[ cfg( test) ]
86
- #[ cfg( feature = "serde" ) ]
87
135
mod tests {
88
136
use super :: Amount ;
89
137
138
+ #[ cfg( feature = "serde" ) ]
90
139
#[ test]
91
140
fn serde_amount ( ) {
92
141
let value = Amount :: from ( 42 ) ;
@@ -96,4 +145,20 @@ mod tests {
96
145
let de: Amount = serde_json:: from_slice ( binary. as_ref ( ) ) . expect ( "can deserialize" ) ;
97
146
assert_eq ! ( de, value) ;
98
147
}
148
+
149
+ #[ cfg( feature = "borsh" ) ]
150
+ #[ test]
151
+ fn borsh_amount ( ) {
152
+ use borsh:: BorshDeserialize ;
153
+
154
+ let value = Amount :: from ( 42 ) ;
155
+ let serialized = borsh:: to_vec ( & value) . unwrap ( ) ;
156
+
157
+ // Amount is supposed to be a U256 according to the spec, which is 32 bytes
158
+ assert_eq ! ( serialized. len( ) , 32 ) ;
159
+
160
+ let value_deserialized = Amount :: try_from_slice ( & serialized) . unwrap ( ) ;
161
+
162
+ assert_eq ! ( value, value_deserialized) ;
163
+ }
99
164
}
0 commit comments