1use core::ops::Range;
2
3use crate::api::*;
4use crate::uninit_buf;
5
6#[inline(always)]
12pub fn is_buffer_equal<const GUARD_ID: u32>(buf_1: &[u8], buf_2: &[u8]) -> bool {
13 let buf1_len = buf_1.len();
14
15 if buf1_len != buf_2.len() {
16 return false;
17 };
18
19 let mut i = 0;
21 while {
22 _g(GUARD_ID, buf1_len as u32 + 1);
23 i < buf1_len
24 } {
25 if buf_1[i] != buf_2[i] {
26 return false;
27 }
28 i += 1;
29 }
30
31 true
32}
33
34#[inline(always)]
40pub fn buffer_zeroize<const GUARD_ID: u32>(buf: &mut [u8]) {
41 let buf_len = buf.len();
42 let mut i = 0;
44 while {
45 _g(GUARD_ID, buf_len as u32 + 1);
46 i < buf_len
47 } {
48 buf[0] = 0;
49 i += 1;
50 }
51}
52
53#[inline(always)]
59pub fn is_txn_outgoing<const GUARD_ID: u32>(
60 hook_acc_id: &mut AccountId,
61 otnx_acc_id: &mut AccountId,
62) -> Result<bool> {
63 match hook_account(hook_acc_id) {
64 Err(e) => return Err(e),
65 Ok(_) => {}
66 }
67
68 match otxn_field(otnx_acc_id, FieldId::Account) {
69 Err(e) => return Err(e),
70 Ok(_) => {}
71 }
72
73 Ok(is_buffer_equal::<GUARD_ID>(
74 &hook_acc_id[..],
75 &otnx_acc_id[..],
76 ))
77}
78
79#[inline(always)]
85pub fn is_txn_ingoing<const GUARD_ID: u32>(
86 hook_acc_id: &mut AccountId,
87 otnx_acc_id: &mut AccountId,
88) -> Result<bool> {
89 match is_txn_outgoing::<GUARD_ID>(hook_acc_id, otnx_acc_id) {
90 Err(e) => Err(e),
91 Ok(res) => Ok(!res),
92 }
93}
94
95#[inline(always)]
97pub const fn amount_to_drops(amount_buf: &Amount) -> Result<u64> {
98 if (amount_buf[0] >> 7) == 1 {
99 return Err(Error::InternalError);
100 }
101
102 Ok((((amount_buf[0] as u64) & 0xb00111111) << 56)
103 + ((amount_buf[1] as u64) << 48)
104 + ((amount_buf[2] as u64) << 40)
105 + ((amount_buf[3] as u64) << 32)
106 + ((amount_buf[4] as u64) << 24)
107 + ((amount_buf[5] as u64) << 16)
108 + ((amount_buf[6] as u64) << 8)
109 + (amount_buf[7] as u64))
110}
111
112#[inline(always)]
114pub fn prepare_payment_simple(
115 buf_out: &mut TxnPaymentSimple,
116 drops_amount: u64,
117 drops_fee: u64,
118 to_address: &AccountId,
119 dest_tag: u32,
120 src_tag: u32,
121) -> Result<()> {
122 const TT_RANGE: Range<usize> = Range { start: 0, end: 3 };
123 const FLAGS_RANGE: Range<usize> = Range { start: 3, end: 8 };
124 const TAG_SRC_RANGE: Range<usize> = Range { start: 8, end: 13 };
125 const SEQUENCE_RANGE: Range<usize> = Range { start: 13, end: 18 };
126 const TAG_DST_RANGE: Range<usize> = Range { start: 18, end: 23 };
127 const FLS_RANGE: Range<usize> = Range { start: 23, end: 29 };
128 const LLS_RANGE: Range<usize> = Range { start: 29, end: 35 };
129 const DROPS_RANGE: Range<usize> = Range { start: 35, end: 44 };
130 const DROPS_FEE_RANGE: Range<usize> = Range { start: 44, end: 53 };
131 const SIGNING_PUBKEY_RANGE: Range<usize> = Range { start: 53, end: 88 };
132 const ACCOUNT_SRC_RANGE: Range<usize> = Range {
133 start: 88,
134 end: 110,
135 };
136 const ACCOUNT_DST_RANGE: Range<usize> = Range {
137 start: 110,
138 end: 132,
139 };
140 const ETXN_DETAILS_RANGE: Range<usize> = Range {
141 start: 132,
142 end: 237,
143 };
144
145 let mut acc: AccountId = uninit_buf!();
146 match hook_account(&mut acc) {
147 Err(e) => return Err(e),
148 Ok(_) => {}
149 }
150
151 let cls = ledger_seq() as u32;
152
153 encode_tt(&mut buf_out[TT_RANGE], TxnType::Payment);
154 encode_flags(&mut buf_out[FLAGS_RANGE], TF_CANONICAL);
155 encode_tag_src(&mut buf_out[TAG_SRC_RANGE], src_tag);
156 encode_sequence(&mut buf_out[SEQUENCE_RANGE], 0);
157 encode_tag_dst(&mut buf_out[TAG_DST_RANGE], dest_tag);
158 encode_fls(&mut buf_out[FLS_RANGE], cls + 1);
159 encode_lls(&mut buf_out[LLS_RANGE], cls + 5);
160 encode_drops_amount(&mut buf_out[DROPS_RANGE], drops_amount);
161 encode_drops_fee(&mut buf_out[DROPS_FEE_RANGE], drops_fee);
162 encode_signing_pubkey_null(&mut buf_out[SIGNING_PUBKEY_RANGE]);
163 encode_account_src(&mut buf_out[ACCOUNT_SRC_RANGE], &acc);
164 encode_account_dst(&mut buf_out[ACCOUNT_DST_RANGE], to_address);
165 match etxn_details(&mut buf_out[ETXN_DETAILS_RANGE]) {
166 Err(e) => return Err(e),
167 Ok(_) => {}
168 }
169
170 Ok(())
171}
172
173#[inline(always)]
174fn encode_tt(buf_out: &mut [u8], tt: TxnType) {
175 buf_out[0] = 0x12;
176 buf_out[1] = ((tt as u16 >> 8) & 0xFF) as u8;
177 buf_out[2] = ((tt as u16 >> 0) & 0xFF) as u8;
178}
179
180#[inline(always)]
181fn encode_flags(buf_out: &mut [u8], flags: u32) {
182 encode_u32_common(buf_out, flags, 0x2)
183}
184
185#[inline(always)]
186fn encode_tag_src(buf_out: &mut [u8], tag: u32) {
187 encode_u32_common(buf_out, tag, 0x3)
188}
189
190#[inline(always)]
191fn encode_sequence(buf_out: &mut [u8], sequence: u32) {
192 encode_u32_common(buf_out, sequence, 0x4)
193}
194
195#[inline(always)]
196fn encode_tag_dst(buf_out: &mut [u8], tag: u32) {
197 encode_u32_common(buf_out, tag, 0xE)
198}
199
200#[inline(always)]
201fn encode_fls(buf_out: &mut [u8], fls: u32) {
202 encode_u32_uncommon(buf_out, fls, 0x1A)
203}
204
205#[inline(always)]
206fn encode_lls(buf_out: &mut [u8], lls: u32) {
207 encode_u32_uncommon(buf_out, lls, 0x1B)
208}
209
210#[inline(always)]
211fn encode_drops_amount(buf_out: &mut [u8], drops: u64) {
212 encode_drops(buf_out, drops, AmountType::Amount)
213}
214
215#[inline(always)]
216fn encode_drops_fee(buf_out: &mut [u8], drops: u64) {
217 encode_drops(buf_out, drops, AmountType::Fee)
218}
219
220#[inline(always)]
221fn encode_account_src(buf_out: &mut [u8], account_id: &Buffer<ACC_ID_LEN>) {
222 encode_account(buf_out, account_id, AccountType::Account)
223}
224
225#[inline(always)]
226fn encode_account_dst(buf_out: &mut [u8], account_id: &Buffer<ACC_ID_LEN>) {
227 encode_account(buf_out, account_id, AccountType::Destination)
228}
229
230#[inline(always)]
231fn encode_u32_common(buf_out: &mut [u8], i: u32, field: u8) {
232 buf_out[0] = 0x20 + (field & 0x0F);
233 buf_out[1] = ((i >> 24) & 0xFF) as u8;
234 buf_out[2] = ((i >> 16) & 0xFF) as u8;
235 buf_out[3] = ((i >> 8) & 0xFF) as u8;
236 buf_out[4] = ((i >> 0) & 0xFF) as u8;
237}
238
239#[inline(always)]
240fn encode_u32_uncommon(buf_out: &mut [u8], i: u32, field: u8) {
241 buf_out[0] = 0x20;
242 buf_out[1] = field;
243 buf_out[2] = ((i >> 24) & 0xFF) as u8;
244 buf_out[3] = ((i >> 16) & 0xFF) as u8;
245 buf_out[4] = ((i >> 8) & 0xFF) as u8;
246 buf_out[5] = ((i >> 0) & 0xFF) as u8;
247}
248
249#[inline(always)]
250fn encode_drops(buf_out: &mut [u8], drops: u64, amount_type: AmountType) {
251 buf_out[0] = 0x60 + (amount_type as u8 & 0x0F);
252 buf_out[1] = (0b01000000 + ((drops >> 56) & 0b00111111)) as u8;
253 buf_out[2] = ((drops >> 48) & 0xFF) as u8;
254 buf_out[3] = ((drops >> 40) & 0xFF) as u8;
255 buf_out[4] = ((drops >> 32) & 0xFF) as u8;
256 buf_out[5] = ((drops >> 24) & 0xFF) as u8;
257 buf_out[6] = ((drops >> 16) & 0xFF) as u8;
258 buf_out[7] = ((drops >> 8) & 0xFF) as u8;
259 buf_out[8] = ((drops >> 0) & 0xFF) as u8;
260}
261
262#[inline(always)]
263fn encode_signing_pubkey_null(buf_out: &mut [u8]) {
264 buf_out[0] = 0x73;
265 buf_out[1] = 0x21;
266 buf_out[2..35].clone_from_slice(&[0; 33]);
267}
268
269#[inline(always)]
270fn encode_account(buf_out: &mut [u8], account_id: &AccountId, account_type: AccountType) {
271 buf_out[0] = 0x80 + account_type as u8;
272 buf_out[1] = 0x14;
273 buf_out[2..22].clone_from_slice(&account_id[..]);
274}
275
276#[cfg(test)]
277mod tests {
278 use super::*;
279 use crate::_c;
280
281 const ACCOUNT_ID: AccountId = [
282 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
283 ];
284
285 #[test]
286 fn enc_account() {
287 let mut encoded: [u8; _c::ENCODE_ACCOUNT_SIZE as usize] = uninit_buf!();
288
289 encode_account(&mut encoded, &ACCOUNT_ID, AccountType::Account);
290
291 assert_eq!(
292 encoded,
293 [0x81, 0x14, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
294 );
295 }
296
297 #[test]
298 fn enc_signing_pubkey_null() {
299 let mut key: [u8; _c::ENCODE_SIGNING_PUBKEY_NULL_SIZE as usize] = [255; 35];
300
301 encode_signing_pubkey_null(&mut key);
302
303 assert_eq!(
304 key,
305 [
306 0x73, 0x21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
307 0, 0, 0, 0, 0, 0, 0, 0, 0
308 ]
309 )
310 }
311}