1+ #include <stdint.h>
2+ #include "hookapi.h"
3+
4+ #define SVAR (x ) &x, sizeof(x)
5+
6+ #define NOPE (x )\
7+ rollback(SBUF(x), __LINE__);
8+
9+ #define BUFFER_EQUAL_20 (buf1 , buf2 )\
10+ (\
11+ *(((uint64_t*)(buf1)) + 0) == *(((uint64_t*)(buf2)) + 0) &&\
12+ *(((uint64_t*)(buf1)) + 1) == *(((uint64_t*)(buf2)) + 1) &&\
13+ *(((uint32_t*)(buf1)) + 4) == *(((uint32_t*)(buf2)) + 4))
14+
15+ #define BUFFER_EQUAL_32 (buf1 , buf2 )\
16+ (\
17+ *(((uint64_t*)(buf1)) + 0) == *(((uint64_t*)(buf2)) + 0) &&\
18+ *(((uint64_t*)(buf1)) + 1) == *(((uint64_t*)(buf2)) + 1) &&\
19+ *(((uint64_t*)(buf1)) + 2) == *(((uint64_t*)(buf2)) + 2) &&\
20+ *(((uint64_t*)(buf1)) + 3) == *(((uint64_t*)(buf2)) + 3))
21+
22+ extern int64_t xpop_slot (uint32_t , uint32_t );
23+
24+ #define FLIP_ENDIAN (n ) ((uint32_t) (((n & 0xFFU) << 24U) | \
25+ ((n & 0xFF00U) << 8U) | \
26+ ((n & 0xFF0000U) >> 8U) | \
27+ ((n & 0xFF000000U) >> 24U)))
28+
29+ #define ttIMPORT 97
30+
31+ uint8_t txn [283 ] =
32+ {
33+ /* size,upto */
34+ /* 3, 0 */ 0x12U , 0x00U , 0x00U , /* tt = Payment */
35+ /* 5, 3*/ 0x22U , 0x80U , 0x00U , 0x00U , 0x00U , /* flags = tfCanonical */
36+ /* 5, 8 */ 0x24U , 0x00U , 0x00U , 0x00U , 0x00U , /* sequence = 0 */
37+ /* 5, 13 */ 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , /* dtag, flipped */
38+ /* 6, 18 */ 0x20U , 0x1AU , 0x00U , 0x00U , 0x00U , 0x00U , /* first ledger seq */
39+ /* 6, 24 */ 0x20U , 0x1BU , 0x00U , 0x00U , 0x00U , 0x00U , /* last ledger seq */
40+ /* 49, 30 */ 0x61U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , /* amount field 9 or 49 bytes */
41+ 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U ,
42+ 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U ,
43+ 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U ,
44+ 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U ,
45+ 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99U , 0x99 ,
46+ /* 9, 79 */ 0x68U , 0x40U , 0x00U , 0x00U , 0x00U , 0x00U , 0x00U , 0x00U , 0x00U , /* fee */
47+ /* 35, 88 */ 0x73U , 0x21U , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /* pubkey */
48+ /* 22,123 */ 0x81U , 0x14U , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /* src acc */
49+ /* 22,145 */ 0x83U , 0x14U , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /* dst acc */
50+ /* 116,167 */ /* emit details */
51+ /* 0,283 */
52+ };
53+
54+ // ACCOUNTS
55+ #define HOOK_ACC (txn + 125U)
56+ #define OTXN_ACC (txn + 147U)
57+
58+ // TXS
59+ #define FLS_OUT (txn + 20U)
60+ #define LLS_OUT (txn + 26U)
61+ #define DTAG_OUT (txn + 14U)
62+ #define AMOUNT_OUT (txn + 30U)
63+ #define EMIT_OUT (txn + 167U)
64+ #define FEE_OUT (txn + 80U)
65+
66+ #define CUR_N_SIZE 3
67+ uint8_t CUR_N [CUR_N_SIZE ] =
68+ {
69+ 0x43 , 0x55 , 0x52 };
70+
71+ int64_t hook (uint32_t r )
72+ {
73+ _g (1 , 1 );
74+
75+ // ACCOUNT: Hook
76+ hook_account (HOOK_ACC , 20 );
77+
78+ // ACCOUNT: Origin
79+ otxn_field (OTXN_ACC , 20 , sfAccount );
80+
81+ // outgoing
82+ if (BUFFER_EQUAL_20 (HOOK_ACC , OTXN_ACC ))
83+ accept (SBUF ("xpop_iou_iou.c: Passing outgoing txn." ), __LINE__ );
84+
85+ // TT: Import
86+ if (otxn_type () != ttIMPORT )
87+ accept (SBUF ("xpop_iou_iou.c: Passing non ttIMPORT txn." ), otxn_type ());
88+
89+ // UTIL: XPOP
90+ int64_t retval = xpop_slot (1 , 2 );
91+ if (retval <= 0 )
92+ NOPE ("xpop_iou_iou.c: Failed to slot xpop" );
93+
94+ #define tx_slot 1
95+ #define meta_slot 2
96+
97+ trace_num ("Slotted xpop" , 12 , retval );
98+ uint8_t dump1 [2048 ];
99+ uint8_t dump2 [2048 ];
100+ int64_t len1 = slot (dump1 , sizeof (dump1 ), tx_slot );
101+ int64_t len2 = slot (dump2 , sizeof (dump2 ), meta_slot );
102+
103+ trace ("tx" , 2 , dump1 , len1 , 1 );
104+ trace ("meta" , 4 , dump2 , len2 , 1 );
105+
106+ if (slot_subfield (meta_slot , sfTransactionResult , 3 ) != 3 )
107+ NOPE ("xpop_iou_iou.c: Failed to slot transaction result" );
108+
109+ uint8_t tr ;
110+ if (slot (SVAR (tr ), 3 ) != 1 )
111+ NOPE ("xpop_iou_iou.c: Failed to dump transaction result" );
112+
113+ trace_num (SBUF ("Inner Transaction Result:" ), tr );
114+ if (tr != 0 )
115+ NOPE ("xpop_iou_iou.c: Inner Transaction Result not tesSUCCESS (0)." );
116+
117+ // execution to here means tesSUCCESS on inner
118+
119+ if (slot_subfield (tx_slot , sfTransactionType , 4 ) != 4 )
120+ NOPE ("xpop_iou_iou.c: Could not slot transaction type" );
121+
122+ uint8_t tt_buf [2 ];
123+ if (slot (SBUF (tt_buf ), 4 ) != 2 )
124+ NOPE ("xpop_iou_iou.c: Could not dump transaction type" );
125+
126+ uint16_t tt = UINT16_FROM_BUF (tt_buf );
127+
128+ if (tt != ttPAYMENT )
129+ NOPE ("xpop_iou_iou.c: Only NFTokenBurn is accepted" );
130+
131+ // go track down the URI of the token (this is a huge pain, has to be done through metadata)
132+ //
133+ #define nodes 5
134+ if (slot_subfield (meta_slot , sfAffectedNodes , nodes ) != nodes )
135+ NOPE ("xpop_iou_iou.c: Could not slot sfAffectedNodes" );
136+
137+ uint8_t dump4 [1024 ];
138+ trace (SBUF ("slot nodes" ), dump4 , slot (SBUF (dump4 ), nodes ), 1 );
139+
140+ int64_t count = slot_count (nodes );
141+ if (count > 5 )
142+ count = 5 ;
143+
144+ int64_t found = 0 ;
145+
146+ for (int i = 0 ; GUARD (5 ), i < count ; ++ i )
147+ {
148+ if (slot_subarray (nodes , i , 6 ) != 6 )
149+ continue ;
150+
151+ if (slot_subfield (6 , sfLedgerEntryType , 8 ) != 8 )
152+ NOPE ("xpop_iou_iou.c: Could not slot LedgerEntryType" );
153+
154+ uint8_t buf [2 ];
155+ if (slot (SBUF (buf ), 8 ) != 2 )
156+ NOPE ("xpop_iou_iou.c: Could not dump LedgerEntryType" );
157+
158+ TRACEHEX (buf );
159+
160+ if (UINT16_FROM_BUF (buf ) == 0x0072U )
161+ {
162+ found = 1 ;
163+ break ;
164+ }
165+ }
166+
167+ if (!found )
168+ NOPE ("xpop_iou_iou.c: Could not find Payment in xpop metadata" );
169+
170+ // VALIDATION: PAYMENT XPOP
171+ if (slot_subfield (6 , sfPreviousFields , 9 ) != 9 || slot_subfield (6 , sfFinalFields , 10 ) != 10 )
172+ NOPE ("xpop_iou_iou.c: Could not slot sfPreviousFields or sfFinalFields" );
173+
174+ uint8_t prev_balance [48 ];
175+ uint8_t final_balance [48 ];
176+ if (slot_subfield (9 , sfBalance , 11 ) != 11 || slot_subfield (10 , sfBalance , 12 ) != 12 )
177+ NOPE ("xpop_iou_iou.c: Could not slot sfBalance" );
178+
179+ if (slot (SVAR (prev_balance ), 11 ) != 48 || slot (SVAR (final_balance ), 12 ) != 48 )
180+ NOPE ("xpop_iou_iou.c: Could not dump sfBalance" );
181+
182+ uint8_t high_limit [48 ];
183+ uint8_t low_limit [48 ];
184+ if (slot_subfield (10 , sfHighLimit , 13 ) != 13 || slot_subfield (10 , sfLowLimit , 14 ) != 14 )
185+ NOPE ("xpop_iou_iou.c: Could not slot sfHighLimit/sfLowLimit" );
186+
187+ if (slot (SVAR (high_limit ), 13 ) != 48 || slot (SVAR (low_limit ), 14 ) != 48 )
188+ NOPE ("xpop_iou_iou.c: Could not dump sfHighLimit/sfLowLimit" );
189+
190+ int is_high = BUFFER_EQUAL_20 (HOOK_ACC , low_limit + 28 );
191+ int is_low = BUFFER_EQUAL_20 (HOOK_ACC , high_limit + 28 );
192+
193+ int64_t amt_slot = slot_subfield (tx_slot , sfAmount , 15 );
194+ if (amt_slot < 0 )
195+ rollback (SBUF ("xpop_iou_iou.c: Could not slot otxn.sfAmount" ), 2 );
196+
197+ int64_t amount_token = slot_float (amt_slot );
198+ if (amount_token < 0 )
199+ rollback (SBUF ("xpop_iou_iou.c: Could not parse amount." ), 1 );
200+
201+ if (is_high )
202+ {
203+ // KEYLET: TrustLine
204+ uint8_t bal_kl [34 ];
205+ if (util_keylet (SBUF (bal_kl ), KEYLET_LINE , OTXN_ACC , 20 , low_limit + 28 , 20 , low_limit + 8 , 20 ) != 34 )
206+ {
207+ NOPE ("xpop_iou_iou.c: Missing trustline" );
208+ }
209+ // TXN PREPARE: Amount
210+ float_sto (AMOUNT_OUT , 49 , low_limit + 8 , 20 , low_limit + 28 , 20 , amount_token , sfAmount );
211+ }
212+ else
213+ {
214+ // KEYLET: TrustLine
215+ uint8_t bal_kl [34 ];
216+ if (util_keylet (SBUF (bal_kl ), KEYLET_LINE , OTXN_ACC , 20 , high_limit + 28 , 20 , high_limit + 8 , 20 ) != 34 )
217+ {
218+ NOPE ("xpop_iou_iou.c: Missing trustline" );
219+ }
220+ // TXN PREPARE: Amount
221+ float_sto (AMOUNT_OUT , 49 , high_limit + 8 , 20 , high_limit + 28 , 20 , amount_token , sfAmount );
222+ }
223+
224+ if (!is_high && !is_low )
225+ {
226+ NOPE ("xpop_iou_iou.c: Issuer does not match hook account" );
227+ }
228+
229+ // TXN: PREPARE: Init
230+ etxn_reserve (1 );
231+
232+ // TXN PREPARE: FirstLedgerSequence
233+ uint32_t fls = (uint32_t )ledger_seq () + 1 ;
234+ * ((uint32_t * )(FLS_OUT )) = FLIP_ENDIAN (fls );
235+
236+ // TXN PREPARE: LastLedgerSequense
237+ uint32_t lls = fls + 4 ;
238+ * ((uint32_t * )(LLS_OUT )) = FLIP_ENDIAN (lls );
239+
240+ // TXN PREPARE: Dest Tag <- Source Tag
241+ if (otxn_field (DTAG_OUT , 4 , sfSourceTag ) == 4 )
242+ * (DTAG_OUT - 1 ) = 0x2EU ;
243+
244+ // TXN PREPARE: Emit Metadata
245+ etxn_details (EMIT_OUT , 116U );
246+
247+ // TXN PREPARE: Fee
248+ {
249+ int64_t fee = etxn_fee_base (SBUF (txn ));
250+ uint8_t * b = FEE_OUT ;
251+ * b ++ = 0b01000000 + ((fee >> 56 ) & 0b00111111 );
252+ * b ++ = (fee >> 48 ) & 0xFFU ;
253+ * b ++ = (fee >> 40 ) & 0xFFU ;
254+ * b ++ = (fee >> 32 ) & 0xFFU ;
255+ * b ++ = (fee >> 24 ) & 0xFFU ;
256+ * b ++ = (fee >> 16 ) & 0xFFU ;
257+ * b ++ = (fee >> 8 ) & 0xFFU ;
258+ * b ++ = (fee >> 0 ) & 0xFFU ;
259+ }
260+
261+ // TXN: Emit/Send Txn
262+ uint8_t etxid [32 ];
263+ int64_t emit_result = emit (SBUF (etxid ), SBUF (txn ));
264+ if (emit_result < 0 )
265+ {
266+ NOPE ("xpop_iou_iou.c: Txn Emission Failed" );
267+ }
268+
269+ trace (SBUF ("xpop_iou_iou.c: Emission success" ), etxid , 32 , 1 );
270+ return accept (SBUF ("xpop_iou_iou.c: Finished" ), __LINE__ );
271+ }
0 commit comments