Skip to content

Commit ea58acb

Browse files
committed
Create xpop_iou_iou.c
1 parent e14ff23 commit ea58acb

1 file changed

Lines changed: 271 additions & 0 deletions

File tree

contracts-c/b2m/xpop_iou_iou.c

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
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

Comments
 (0)