1use std::fmt::Write;
4
5mod print;
6pub use print::Print;
7
8pub trait Printer: Write {
11 fn current_pos(&self) -> usize;
13 fn inc_ident(&mut self);
15 fn dec_ident(&mut self);
17 fn get_indent(&self) -> usize;
19 fn print_indent(&mut self) -> std::fmt::Result {
21 write!(self, "{:indent$}", "", indent = self.get_indent())
22 }
23}
24
25pub struct PosTrackingWriter {
27 print_buf: String,
28 current_pos: usize,
29 current_indent: usize,
30}
31
32impl Write for PosTrackingWriter {
33 fn write_str(&mut self, s: &str) -> std::fmt::Result {
34 let len = s.len();
35 self.current_pos += len;
36 write!(self.print_buf, "{}", s)
37 }
38}
39
40impl Printer for PosTrackingWriter {
41 fn current_pos(&self) -> usize {
42 self.current_pos
43 }
44
45 fn inc_ident(&mut self) {
46 self.current_indent += Self::INDENT;
47 }
48
49 fn dec_ident(&mut self) {
50 self.current_indent -= Self::INDENT;
51 }
52
53 fn get_indent(&self) -> usize {
54 self.current_indent
55 }
56}
57
58impl PosTrackingWriter {
59 const INDENT: usize = 2;
60
61 pub fn new() -> Self {
63 Self {
64 print_buf: String::new(),
65 current_pos: 0,
66 current_indent: 0,
67 }
68 }
69
70 pub fn get_buf(&self) -> &str {
72 &self.print_buf
73 }
74
75 pub fn as_string(self) -> String {
77 self.print_buf
78 }
79}
80
81impl Default for PosTrackingWriter {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87#[allow(clippy::unwrap_used)]
88#[cfg(test)]
89mod tests {
90
91 use expect_test::expect;
92
93 use crate::chain::address::AddressEncoder;
94 use crate::chain::address::NetworkPrefix;
95 use crate::ergo_tree::ErgoTree;
96 use crate::mir::bin_op::ArithOp;
97 use crate::mir::bin_op::BinOp;
98 use crate::mir::block::BlockValue;
99 use crate::mir::expr::Expr;
100 use crate::mir::val_def::ValDef;
101 use crate::mir::val_use::ValUse;
102 use crate::serialization::SigmaSerializable;
103 use crate::types::stype::SType;
104
105 use super::*;
106
107 fn check_pretty(expr: Expr, expected_tree: expect_test::Expect) {
108 let print_buf = String::new();
109 let mut w = PosTrackingWriter {
110 print_buf,
111 current_pos: 0,
112 current_indent: 0,
113 };
114 let _ = expr.print(&mut w).unwrap();
115 expected_tree.assert_eq(w.get_buf());
116 }
117
118 fn check_spans(expr: Expr, expected_tree: expect_test::Expect) {
119 let print_buf = String::new();
120 let mut w = PosTrackingWriter {
121 print_buf,
122 current_pos: 0,
123 current_indent: 0,
124 };
125 let spanned_expr = expr.print(&mut w).unwrap();
126 expected_tree.assert_eq(format!("{:?}", spanned_expr).as_str());
127 }
128
129 #[test]
130 fn print_block() {
131 let val_id = 1.into();
132 let expr = Expr::BlockValue(
133 BlockValue {
134 items: vec![ValDef {
135 id: val_id,
136 rhs: Box::new(Expr::Const(1i32.into())),
137 }
138 .into()],
139 result: Box::new(
140 ValUse {
141 val_id,
142 tpe: SType::SInt,
143 }
144 .into(),
145 ),
146 }
147 .into(),
148 );
149 check_pretty(
150 expr,
151 expect![[r#"
152 {
153 val v1 = 1
154 v1
155 }
156 "#]],
157 );
158 }
159
160 #[test]
161 fn print_binop() {
162 let val_id = 1.into();
163 let expr = Expr::BlockValue(
164 BlockValue {
165 items: vec![ValDef {
166 id: val_id,
167 rhs: Box::new(
168 BinOp {
169 kind: ArithOp::Divide.into(),
170 left: Expr::Const(4i32.into()).into(),
171 right: Expr::Const(2i32.into()).into(),
172 }
173 .into(),
174 ),
175 }
176 .into()],
177 result: Box::new(
178 ValUse {
179 val_id,
180 tpe: SType::SInt,
181 }
182 .into(),
183 ),
184 }
185 .into(),
186 );
187 check_pretty(
188 expr.clone(),
189 expect![[r#"
190 {
191 val v1 = 4 / 2
192 v1
193 }
194 "#]],
195 );
196
197 check_spans(
198 expr,
199 expect![[
200 r#"BlockValue(Spanned { source_span: SourceSpan { offset: 0, length: 26 }, expr: BlockValue { items: [ValDef(Spanned { source_span: SourceSpan { offset: 4, length: 14 }, expr: ValDef { id: ValId(1), rhs: BinOp(Spanned { source_span: SourceSpan { offset: 13, length: 5 }, expr: BinOp { kind: Arith(Divide), left: Const("4: SInt"), right: Const("2: SInt") } }) } })], result: ValUse(ValUse { val_id: ValId(1), tpe: SInt }) } })"#
201 ]],
202 );
203 }
204
205 #[test]
206 fn eip23_refresh_contract() {
207 let ergo_tree_bytes = base16::decode("1016043c040004000e202a472d4a614e645267556b58703273357638792f423f4528482b4d625065536801000502010105000400040004020402040204080400040a05c8010e20472b4b6250655368566d597133743677397a24432646294a404d635166546a570400040404020408d80ed60199a37300d602b2a4730100d603b5a4d901036395e6c672030605eded928cc77203017201938cb2db6308720373020001730393e4c672030504e4c6720205047304d604b17203d605b0720386027305860273067307d901053c413d0563d803d607e4c68c7205020605d6088c720501d6098c720802860272078602ed8c720901908c72080172079a8c7209027207d6068c720502d6078c720501d608db63087202d609b27208730800d60ab2a5730900d60bdb6308720ad60cb2720b730a00d60db27208730b00d60eb2a5730c00ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02ea02cde4c6b27203e4e30004000407d18f8cc77202017201d1927204730dd18c720601d190997207e4c6b27203730e0006059d9c72077e730f057310d1938c7209017311d193b2720b7312007209d1938c720c018c720d01d1928c720c02998c720d027e9c7204731305d193b1720bb17208d193e4c6720a04059d8c7206027e720405d193e4c6720a05049ae4c6720205047314d193c2720ac27202d192c1720ac17202d1928cc7720a0199a37315d193db6308720edb6308a7d193c2720ec2a7d192c1720ec1a7").unwrap();
208 let ergo_tree = ErgoTree::sigma_parse_bytes(&ergo_tree_bytes).unwrap();
209 check_pretty(
210 ergo_tree.proposition().unwrap(),
211 expect![[r#"
212 {
213 val v1 = HEIGHT - 30
214 val v2 = INPUTS(0)
215 val v3 = INPUTS.filter({
216 (v3: Box) =>
217 if (v3.getReg(6).isDefined()) v3.creationInfo._1 >= v1 && v3.tokens(0)._1 == "2a472d4a614e645267556b58703273357638792f423f4528482b4d6250655368" && v3.getReg(5).get == v2.getReg(5).get else false
218 }
219 )
220 val v4 = v3.size
221 val v5 = v3.fold((, 1, (, true, 0)))({
222 (v5: ((Long, (Boolean, Long)), Box)) =>
223 {
224 val v7 = v5._2.getReg(6).get
225 val v8 = v5._1
226 val v9 = v8._2
227 (, v7, (, v9._1 && v8._1 <= v7, v9._2 + v7))
228 }
229
230 }
231 )
232 val v6 = v5._2
233 val v7 = v5._1
234 val v8 = v2.tokens
235 val v9 = v8(0)
236 val v10 = OUTPUTS(0)
237 val v11 = v10.tokens
238 val v12 = v11(1)
239 val v13 = v8(1)
240 val v14 = OUTPUTS(1)
241 allOf(
242 allOf(
243 allOf(
244 allOf(
245 allOf(
246 allOf(
247 allOf(
248 allOf(
249 allOf(
250 allOf(
251 allOf(
252 allOf(
253 allOf(
254 allOf(
255 allOf(
256 allOf(
257 allOf(
258 proveDlog(v3(getVar(0).get).getReg(4).get),
259 sigmaProp(v2.creationInfo._1 < v1),
260 ),
261 sigmaProp(v4 >= 4),
262 ),
263 sigmaProp(v6._1),
264 ),
265 sigmaProp(v7 - v3(0).getReg(6).get <= v7 * upcast(5) / 100),
266 ),
267 sigmaProp(v9._1 == "472b4b6250655368566d597133743677397a24432646294a404d635166546a57"),
268 ),
269 sigmaProp(v11(0) == v9),
270 ),
271 sigmaProp(v12._1 == v13._1),
272 ),
273 sigmaProp(v12._2 >= v13._2 - upcast(v4 * 2)),
274 ),
275 sigmaProp(v11.size == v8.size),
276 ),
277 sigmaProp(v10.getReg(4).get == v6._2 / upcast(v4)),
278 ),
279 sigmaProp(v10.getReg(5).get == v2.getReg(5).get + 1),
280 ),
281 sigmaProp(v10.propBytes == v2.propBytes),
282 ),
283 sigmaProp(v10.value >= v2.value),
284 ),
285 sigmaProp(v10.creationInfo._1 >= HEIGHT - 4),
286 ),
287 sigmaProp(v14.tokens == SELF.tokens),
288 ),
289 sigmaProp(v14.propBytes == SELF.propBytes),
290 ),
291 sigmaProp(v14.value >= SELF.value),
292 )
293 }
294 "#]],
295 )
296 }
297
298 #[test]
299 fn eip23_update_contract() {
300 let ergo_tree_bytes = base16::decode("100f0400040004000402040204020e20472b4b6250655368566d597133743677397a24432646294a404d635166546a570400040004000e203f4428472d4b6150645367566b5970337336763979244226452948404d625165010005000400040cd80ad601b2a4730000d602db63087201d603b27202730100d604b2a5730200d605db63087204d606b2a5730300d607b27205730400d6088c720701d6098c720702d60ab27202730500d1ededed938c7203017306edededed937203b2720573070093c17201c1720493c672010405c67204040593c672010504c672040504efe6c672040661edededed93db63087206db6308a793c27206c2a792c17206c1a7918cc77206018cc7a701efe6c67206046192b0b5a4d9010b63d801d60ddb6308720b9591b1720d7308d801d60ec6720b070eededed938cb2720d73090001730a93e4c6720b05048cc7a70193e4c6720b060ecbc2720495ede6720ee6c6720b0805ed93e4720e720893e4c6720b08057209ed938c720a017208938c720a027209730b730cd9010b41639a8c720b018cb2db63088c720b02730d00027e730e05").unwrap();
301 let ergo_tree = ErgoTree::sigma_parse_bytes(&ergo_tree_bytes).unwrap();
302 check_pretty(
303 ergo_tree.proposition().unwrap(),
304 expect![[r#"
305 {
306 val v1 = INPUTS(0)
307 val v2 = v1.tokens
308 val v3 = v2(0)
309 val v4 = OUTPUTS(0)
310 val v5 = v4.tokens
311 val v6 = OUTPUTS(1)
312 val v7 = v5(1)
313 val v8 = v7._1
314 val v9 = v7._2
315 val v10 = v2(1)
316 sigmaProp(v3._1 == "472b4b6250655368566d597133743677397a24432646294a404d635166546a57" && v3 == v5(0) && v1.value == v4.value && v1.getReg(4) == v4.getReg(4) && v1.getReg(5) == v4.getReg(5) && !v4.getReg(6).isDefined() && v6.tokens == SELF.tokens && v6.propBytes == SELF.propBytes && v6.value >= SELF.value && v6.creationInfo._1 > SELF.creationInfo._1 && !v6.getReg(4).isDefined() && INPUTS.filter({
317 (v11: Box) =>
318 {
319 val v13 = v11.tokens
320 if (v13.size > 0) {
321 val v14 = v11.getReg(7)
322 v13(0)._1 == "3f4428472d4b6150645367566b5970337336763979244226452948404d625165" && v11.getReg(5).get == SELF.creationInfo._1 && v11.getReg(6).get == blake2b256(v4.propBytes) && if (v14.isDefined() && v11.getReg(8).isDefined()) v14.get == v8 && v11.getReg(8).get == v9 else v10._1 == v8 && v10._2 == v9
323 }
324 else false
325 }
326
327 }
328 ).fold(0)({
329 (v11: (Long, Box)) =>
330 v11._1 + v11._2.tokens(0)._2
331 }
332 ) >= upcast(6))
333 }
334 "#]],
335 )
336 }
337
338 #[test]
339 fn eip23_ballot_contract() {
340 let ergo_tree_bytes = base16::decode("10070580dac409040204020400040204000e206251655468576d5a7134743777217a25432a462d4a404e635266556a586e3272d803d601e4c6a70407d602b2a5e4e3000400d603c672020407eb02cd7201d1edededede6720393c27202c2a793db63087202db6308a792c172027300ededededed91b1a4730191b1db6308b2a47302007303938cb2db6308b2a473040073050001730693e47203720192c17202c1a7efe6c672020561").unwrap();
341 let ergo_tree = ErgoTree::sigma_parse_bytes(&ergo_tree_bytes).unwrap();
342 check_pretty(
343 ergo_tree.proposition().unwrap(),
344 expect![[r#"
345 {
346 val v1 = SELF.getReg(4).get
347 val v2 = OUTPUTS(getVar(0).get)
348 val v3 = v2.getReg(4)
349 anyOf(
350 proveDlog(v1),
351 sigmaProp(v3.isDefined() && v2.propBytes == SELF.propBytes && v2.tokens == SELF.tokens && v2.value >= 10000000 && INPUTS.size > 1 && INPUTS(1).tokens.size > 0 && INPUTS(1).tokens(0)._1 == "6251655468576d5a7134743777217a25432a462d4a404e635266556a586e3272" && v3.get == v1 && v2.value >= SELF.value && !v2.getReg(5).isDefined()),
352 )
353 }
354 "#]],
355 )
356 }
357
358 #[test]
359 fn eip23_oracle_contract() {
360 let ergo_tree_bytes = base16::decode("100a040004000580dac409040004000e20472b4b6250655368566d597133743677397a24432646294a404d635166546a570402040204020402d804d601b2a5e4e3000400d602db63087201d603db6308a7d604e4c6a70407ea02d1ededed93b27202730000b2720373010093c27201c2a7e6c67201040792c172017302eb02cd7204d1ededededed938cb2db6308b2a4730300730400017305938cb27202730600018cb2720373070001918cb27202730800028cb272037309000293e4c672010407720492c17201c1a7efe6c672010561").unwrap();
361 let ergo_tree = ErgoTree::sigma_parse_bytes(&ergo_tree_bytes).unwrap();
362 check_pretty(
363 ergo_tree.proposition().unwrap(),
364 expect![[r#"
365 {
366 val v1 = OUTPUTS(getVar(0).get)
367 val v2 = v1.tokens
368 val v3 = SELF.tokens
369 val v4 = SELF.getReg(4).get
370 allOf(
371 sigmaProp(v2(0) == v3(0) && v1.propBytes == SELF.propBytes && v1.getReg(4).isDefined() && v1.value >= 10000000),
372 anyOf(
373 proveDlog(v4),
374 sigmaProp(INPUTS(0).tokens(0)._1 == "472b4b6250655368566d597133743677397a24432646294a404d635166546a57" && v2(1)._1 == v3(1)._1 && v2(1)._2 > v3(1)._2 && v1.getReg(4).get == v4 && v1.value >= SELF.value && !v1.getReg(5).isDefined()),
375 ),
376 )
377 }
378 "#]],
379 )
380 }
381
382 #[test]
383 fn ageusd_bank_full() {
384 let p2s_addr_str = "MUbV38YgqHy7XbsoXWF5z7EZm524Ybdwe5p9WDrbhruZRtehkRPT92imXer2eTkjwPDfboa1pR3zb3deVKVq3H7Xt98qcTqLuSBSbHb7izzo5jphEpcnqyKJ2xhmpNPVvmtbdJNdvdopPrHHDBbAGGeW7XYTQwEeoRfosXzcDtiGgw97b2aqjTsNFmZk7khBEQywjYfmoDc9nUCJMZ3vbSspnYo3LarLe55mh2Np8MNJqUN9APA6XkhZCrTTDRZb1B4krgFY1sVMswg2ceqguZRvC9pqt3tUUxmSnB24N6dowfVJKhLXwHPbrkHViBv1AKAJTmEaQW2DN1fRmD9ypXxZk8GXmYtxTtrj3BiunQ4qzUCu1eGzxSREjpkFSi2ATLSSDqUwxtRz639sHM6Lav4axoJNPCHbY8pvuBKUxgnGRex8LEGM8DeEJwaJCaoy8dBw9Lz49nq5mSsXLeoC4xpTUmp47Bh7GAZtwkaNreCu74m9rcZ8Di4w1cmdsiK1NWuDh9pJ2Bv7u3EfcurHFVqCkT3P86JUbKnXeNxCypfrWsFuYNKYqmjsix82g9vWcGMmAcu5nagxD4iET86iE2tMMfZZ5vqZNvntQswJyQqv2Wc6MTh4jQx1q2qJZCQe4QdEK63meTGbZNNKMctHQbp3gRkZYNrBtxQyVtNLR8xEY8zGp85GeQKbb37vqLXxRpGiigAdMe3XZA4hhYPmAAU5hpSMYaRAjtvvMT3bNiHRACGrfjvSsEG9G2zY5in2YWz5X9zXQLGTYRsQ4uNFkYoQRCBdjNxGv6R58Xq74zCgt19TxYZ87gPWxkXpWwTaHogG1eps8WXt8QzwJ9rVx6Vu9a5GjtcGsQxHovWmYixgBU8X9fPNJ9UQhYyAWbjtRSuVBtDAmoV1gCBEPwnYVP5GCGhCocbwoYhZkZjFZy6ws4uxVLid3FxuvhWvQrVEDYp7WRvGXbNdCbcSXnbeTrPMey1WPaXX";
386 let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
387 let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
388 let expr = addr.script().unwrap().proposition().unwrap();
389 check_pretty(
390 expr,
391 expect![[r#"
392 {
393 val v1 = CONTEXT.dataInputs
394 sigmaProp(if (v1.size > 0) {
395 val v2 = v1(0)
396 val v3 = v2.tokens(0)._1 == "011d3364de07e5a26f0c4eef0852cddb387039a921b7154ef3cab22c6eda887f"
397 val v4 = OUTPUTS(0)
398 val v5 = v4.value
399 val v6 = SELF.tokens
400 val v7 = v6(1)
401 val v8 = v7._2
402 val v9 = v4.tokens
403 val v10 = v9(1)
404 val v11 = v10._2
405 val v12 = v8 != v11
406 val v13 = v6(0)
407 val v14 = v13._2
408 val v15 = v9(0)
409 val v16 = v15._2
410 val v17 = v14 != v16
411 val v18 = SELF.getReg(5).get
412 val v19 = v4.getReg(5).get
413 val v20 = SELF.getReg(4).get
414 val v21 = v4.getReg(4).get
415 val v22 = OUTPUTS(1)
416 val v23 = v22.getReg(4).get
417 val v24 = if (v12) 0 else v23
418 val v25 = if (v12) v23 else 0
419 val v26 = SELF.value
420 val v27 = v22.getReg(5).get
421 val v28 = v2.getReg(4).get / 100
422 val v29 = v26 min v20 * v28 max 0
423 val v30 = if (v17) v28 min if (v20 == 0) 9223372036854775807 else v29 / v20 * v24 else {
424 val v30 = v26 - v29
425 if (v30 == 0) 1000000 else if (v18 == 0) 1000000 else v30 / v18 * v25
426 }
427
428 val v31 = v30 * upcast(2) / 100
429 val v32 = v21 * v28
430 val v33 = if (HEIGHT > 460000) 800 else 1000000000
431 val v34 = if (v32 == 0) v33 else v5 * 100 / v32
432 v3 && v5 >= 10000000 && v4.propBytes == SELF.propBytes && v12 || v17 && !v12 && v17 && v8 + v18 == v11 + v19 && v14 + v20 == v16 + v21 && v20 + v24 == v21 && v18 + v25 == v19 && v26 + v27 == v5 && v21 >= 0 && v19 >= 0 && v15._1 == v13._1 && v10._1 == v7._1 && v9(2)._1 == v6(2)._1 && v27 == v30 + if (v31 < 0) -v31 else v31 && if (v17) if (v24 > 0) v34 >= 400 else true else if (v25 > 0) v34 <= v33 else v34 >= 400 && v3
433 }
434 else false || INPUTS(0).tokens(0)._1 == "239c170b7e82f94e6b05416f14b8a2a57e0bfff0e3c93f4abbcd160b6a5b271a")
435 }
436 "#]],
437 )
438 }
439
440 #[test]
441 fn ageusd_update() {
442 let p2s_addr_str = "VLyjpv3dse3PbatT83GnDkBQasGqY52dAEdi9XpXhuSUn1FS1Tm7XxtAgmBiqY9pJXtEAsDKwX9ygSjrFu7vnUQZudhC2sSmxhxqgD3ZxJ2VsGwmPG77F6EiEZhcq71oqEq31y9XvCCXL5nqqszdENPAVhu7xT296qZ7w1x6hmwdh9ZE89bjfgbhfNYopoqsCaNLWYHJ12TDSY93kaGqCVKSu6gEF1gLpXBfRCnAPPxYswJPmK8oWDn8PKrUGs3MjVsj6bGXiW3VTGP4VsNH8YSSkjyj1FZ9azLsyfnNJ3zah2zUHdCCqY6PjH9JfHf9joCPf6TusvXgr71XWvh5e2HPEPQr4eJMD4S96cGTiSs3J5XcRd1tCDYoiis8nxv99zFFhHgpqXHgeqjhJ5sPot9eRYTsmm4cRTVLXYAiuKPS2qW5";
444 let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
445 let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
446 let expr = addr.script().unwrap().proposition().unwrap();
447 check_pretty(
448 expr,
449 expect![[r#"
450 {
451 val v1 = INPUTS(1)
452 val v2 = v1.tokens
453 val v3 = OUTPUTS(1)
454 val v4 = SELF.id
455 val v5 = OUTPUTS(0)
456 sigmaProp(v2.size == 3 && v2(2)._1 == "7d672d1def471720ca5782fd6473e47e796d9ac0c138d9911346f118b2f6d9d9" && v2 == v3.tokens && v1.value == v3.value && v1.getReg(4).get == v3.getReg(4).get && v1.getReg(5).get == v3.getReg(5).get && v4 == INPUTS(0).id && SELF.tokens == v5.tokens && SELF.propBytes == v5.propBytes && v5.value >= SELF.value && INPUTS.filter({
457 (v6: Box) =>
458 {
459 val v8 = v6.tokens
460 v8.size > 0 && v8(0)._1 == "f7995f212216fcf21854f56df7a9a0a9fc9b7ae4c0f1cc40f5b406371286a5e0" && v6.getReg(6).get == v4 && v6.getReg(7).get == blake2b256(v3.propBytes)
461 }
462
463 }
464 ).fold(0)({
465 (v6: (Long, Box)) =>
466 v6._1 + v6._2.tokens(0)._2
467 }
468 ) >= upcast(3))
469 }
470 "#]],
471 )
472 }
473
474 #[test]
475 fn ageusd_ballot() {
476 let p2s_addr_str = "22ELWBHzyWGjPRE48ZJDfFmD24myYdG3vHz8CipSS7rgE65ABmEj9QJiy3rG2PTJeCaZw9VX56GY6uoA3hQch7i5BfFU3AprUWTABi4X1VWtRdK9yrYJkmN6fq8hGfvmWTrsyh4fXZoGETpLuXQViYo194ajej2h7dr3oqNATdMskSXzxJi83bFdAvQ";
478 let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
479 let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
480 let expr = addr.script().unwrap().proposition().unwrap();
481 check_pretty(
482 expr,
483 expect![[r#"
484 {
485 val v1 = OUTPUTS(INPUTS.indexOf(SELF0))
486 val v2 = SELF.getReg(4).get
487 allOf(
488 sigmaProp(v1.getReg(4).get == v2 && v1.propBytes == SELF.propBytes && v1.tokens == SELF.tokens && v1.value >= SELF.value),
489 anyOf(
490 proveDlog(v2),
491 sigmaProp(INPUTS(0).tokens(0)._1 == "239c170b7e82f94e6b05416f14b8a2a57e0bfff0e3c93f4abbcd160b6a5b271a" && !v1.getReg(7).isDefined()),
492 ),
493 )
494 }
495 "#]],
496 )
497 }
498
499 #[test]
500 fn amm_simple_pool() {
501 let p2s_addr_str = "k6fD5ht5e1itDejPFV2VzAoHv478KQCbDnLAL6XUVeEu8KDaboCVZAoFz2AtMoLqM3CgQfr2TZhpwz7K96AgwTXDvBVeTchJ31jjD46Di1W67H8wwFcivnY62UB6L7HWzCkbYuiZaAq2qSJta5Twt4A2Aaoy7xViWcyLUVNAyQYDJXKhVBAGwp76i2too5yWUmEU4zt9XnjJAUt1FFfurNtTNHNPDbqmTRE4crz347q6rfbvkMmg9Jtk9rSiPCQpKjdbZVzUnP4CUw6AvQH6rZXxgNMktAtjQdHhCnrCmf78FwCKqYS54asKd1MFgYNT4NzPwmdZF6JtQt1vvkjZXqpGkjy33xxDNYy8JZS8eeqVgZErPeJ1aj4aaK8gvmApUgGStMDFeFYjuQqZiZxEAHNdAXDg7hyGnmfzA6Hj9zcB7p9nKCDNhEQEMPL1kMG5aXvt2HUPXqiCkLrv596DaGmRMN3gMJaj1T1AfMYNwZozcJ9uUSK4i6Xham28HWAekTtDPhobnmjvkubwLVTtvUumWHtDWFxYSJPF7vqzgZqg6Y5unMF";
503 let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
504 let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
505 let expr = addr.script().unwrap().proposition().unwrap();
506 check_pretty(
507 expr,
508 expect![[r#"
509 {
510 val v1 = OUTPUTS(0)
511 val v2 = v1.tokens
512 val v3 = SELF.tokens
513 val v4 = v2(0)
514 val v5 = v3(0)
515 val v6 = v2(2)
516 val v7 = v3(2)
517 val v8 = v2(3)
518 val v9 = v3(3)
519 val v10 = 1000000000000000000 - v5._2
520 val v11 = 1000000000000000000 - v4._2 - v10
521 val v12 = v7._2
522 val v13 = v6._2 - v12
523 val v14 = v13 > 0
524 val v15 = v9._2
525 val v16 = upcast(v15)
526 val v17 = upcast(v13)
527 val v18 = v8._2 - v15
528 val v19 = upcast(v12)
529 val v20 = upcast(v18)
530 val v21 = upcast(v10)
531 val v22 = upcast(v11) / v21
532 sigmaProp(v1.propBytes == SELF.propBytes && v1.value >= SELF.value && v2(1) == v3(1) && v4._1 == v5._1 && v6._1 == v7._1 && v8._1 == v9._1 && if (v11 == 0) if (v14) v16 * v17 * BigInt256(Int256(997)) >= upcast(-v18) * v19 * BigInt256(Int256(1000)) + upcast(v13 * 997) else v19 * v20 * BigInt256(Int256(997)) >= upcast(-v13) * v16 * BigInt256(Int256(1000)) + upcast(v18 * 997) else if (v14 && v18 > 0) upcast(-v11) <= v17 * v21 / v19 min v20 * v21 / v16 else v17 >= v22 * v19 && v20 >= v22 * v16)
533 }
534 "#]],
535 )
536 }
537
538 #[test]
539 fn amm_simple_swap() {
540 let p2s_addr_str = "cLPHJ3MHuKAHoCUwGhcEFw5sWJqvPwFyKxTRj1aUoMwgAz78Fg3zLXRhBup9Te1WLau1gZXNmXvUmeXGCd7QLeqB7ArrT3v5cg26piEtqymM6j2SkgYVCobgoAGKeTf6nMLxv1uVrLdjt1GnPxG1MuWj7Es7Dfumotbx9YEaxwqtTUC5SKsJc9LCpAmNWRAQbU6tVVEvmfwWivrGoZ3L5C4DMisxN3U";
542 let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
543 let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
544 let expr = addr.script().unwrap().proposition().unwrap();
545 check_pretty(
546 expr,
547 expect![[r#"
548 {
549 val v1 = INPUTS(0).tokens
550 val v2 = v1(2)
551 val v3 = SELF.tokens(0)
552 val v4 = v3._1
553 val v5 = v1(3)
554 val v6 = v3._2
555 sigmaProp(v2._1 == v4 || v5._1 == v4 && OUTPUTS.exists({
556 (v7: Box) =>
557 {
558 val v9 = v7.tokens(0)._2
559 v9 >= upcast(1000) && upcast(v5._2) * upcast(v6) * BigInt256(Int256(997)) <= upcast(v9) * upcast(v2._2) * BigInt256(Int256(1000)) + upcast(v6 * 997)
560 }
561
562 }
563 ))
564 }
565 "#]],
566 )
567 }
568
569 #[test]
570 fn amm_conc_pool_root() {
571 let p2s_addr_str = "3STRfQWC9Xb5wAxBiEQ74uTFSemk1oHn43mwj9tMCeu2a3A4kie1bY2qsCdRaEmdQoq3B4tXQuzq9nm84A8PmBgCzgGDEZf2pgYoAUc6krZxUY3rvKWW44ZpzN3u5bFRpKDo6rxKtxX2tw99xmfyfaVBejgDaTfsib2PSVsu9hrLQ3SouECWHQMjDA3Pi8ZuCvQeW8GDkZfHPr3SgwaxY1jpY2njsmf3JBASMoVZ6Mfpg63Q6mBno7mKUSCE7vNHHUZe2V7JEikwjPkaxSWxnwy3J17faGtiEHZLKiNQ9WNtsJLbdVp56dQGfC2zaiXjhx1XJK6m4Nh2M8yEvSuBzanRBAJqrNseGS97tk2iLqqfHrqqmmDsHY3mujCURky4SLr7YLk4B";
573 let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
574 let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
575 let expr = addr.script().unwrap().proposition().unwrap();
576 check_pretty(
577 expr,
578 expect![[r#"
579 {
580 val v1 = OUTPUTS(0)
581 val v2 = SELF.tokens(0)
582 val v3 = v2._1
583 val v4 = SELF.getReg(4).get
584 val v5 = SELF.getReg(5).get
585 val v6 = SELF.getReg(6).get
586 val v7 = OUTPUTS(1)
587 val v8 = v7.tokens
588 val v9 = v7.getReg(6).get
589 val v10 = v5._2
590 val v11 = v5._1
591 val v12 = v7.getReg(5).get
592 val v13 = v7.getReg(7).get
593 sigmaProp(v1.propBytes == SELF.propBytes && v1.value >= SELF.value && v1.tokens(0) == (, v3, v2._2 - 1) && v1.getReg(4).get == v4 && v1.getReg(5).get == v5 && v1.getReg(6).get == v6 && v7.getReg(4).get == v4 && v7.getReg(8).get == v6 && v8(1)._1 == v3 && v8(0) == (, SELF.id, 1000000000000000000) && v9._1 * v10 == v9._2 * v11 * v12 && v13._1 * v10 == v13._2 * v11 * v12 + 1)
594 }
595 "#]],
596 )
597 }
598
599 #[test]
600 fn amm_conc_pool_boot() {
601 let p2s_addr_str = "6Mv73vd1MnJp6AQg5vHGP9nujFc3Y1PL5gzeUt9PzCaUiQug7ueQGU1bDkmFkCspq4LU8j3T8yY6UyJQKSfah5qEDzjx8QCJF47NBG5jxgPxmBHkM6cUgnYa5ngzn9jrpAn379UC7o5nugTg3HYWZGk3APMcRftkrC3EgroiVMEmSkDcDwaebkNWKfKe3JXgewoTrgZ2YLMafr3JfX47C1zddoWDhS8TWryQYEprkP334eisuh1Fr2iNTW9ruV6m38cRkfRfzSBHYq45mvNLH7JQo6uQZ4NFPx4t27Q5A3mSqCpk7ATThFcQmc2w3Pp2F6xL87c94gxk83G8UEqkAhmaNfoj19zji9rxqRzq9gJeTLBraHR2DchKtahH8HhFPg5DZ4SjwJ4MHqTDF";
603 let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
604 let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
605 let expr = addr.script().unwrap().proposition().unwrap();
606 check_pretty(
607 expr,
608 expect![[r#"
609 {
610 val v1 = OUTPUTS(0)
611 val v2 = v1.tokens
612 val v3 = SELF.tokens
613 val v4 = v1.getReg(5).get
614 val v5 = v1.getReg(6).get
615 val v6 = v2(3)
616 val v7 = v6._2
617 val v8 = upcast(v7)
618 val v9 = v1.getReg(7).get
619 val v10 = upcast(v9)
620 val v11 = v2(2)
621 val v12 = v3(0)
622 sigmaProp(true && v1.value >= SELF.value && v2(0) == (, SELF.id, 1) && v2(1) == (, v3(1)._1, 1) && v1.getReg(4).get == SELF.getReg(4).get && v4 == SELF.getReg(6).get && v5 == SELF.getReg(7).get && (, v6._1, v2(4)._1) == SELF.getReg(8).get && v8 * v8 == v10 * v10 && if (v11._1 == v12._1) v11._2 else 0 >= v12._2 - v9 && v7 * upcast(v4._2) >= v7 * upcast(v4._1) && v7 * upcast(v5._2) < v7 * upcast(v5._1))
623 }
624 "#]],
625 )
626 }
627
628 #[test]
629 fn amm_conc_pool() {
630 let p2s_addr_str = "AhCu1UkNT4c9q3B2Lb7gNgvZWCdXL8iYgmNxTYiy4S3wgKWFFW6kz9v7pvY8NqC7g4wgXXwzJY1fQVn2xrLkiyiQWsorq5dR7d5KnDAY43H4GvSVjaDciadXCSHCb8jgk8mFSQCwoZHweLmMJ25312wT85AySJgYUuzdUxMz4EnQpiwZR2XVZq3M81gycuqP9gUryryjN4J1cAF3yL3kZR3rREubBvJ2CY5hF74Xaj2jwajivkESkqq22ieWWG2sK7dk1A7KHr1MmiXGcUBAMMGPAu3mVCeFW9SongxP9hodnJThLknjWRBBBC6wq5jNkSdHrMbdaQM3XesXqGTk9KwWpnSL92E96muU2k8FQbo5isps1r5ciYVrFptfEAC3tWbwcVmRKtrgxtCex6bP5aBZYjaH6L9QQbkYriDAcQ1iZcpf3hHCqURjRXL7i72C3aGBwzzspQvhLof6x4f4gPxTCtF1bNUxddUL6DJ1PbQWzVH8taivjhHohis6sRn3Akvv4xaZRJdKZ8rDuiounRKNXi8VoNgVEZbSFYtfweRSdsiXJCkhtehLWdtFTk1eg7djASdBGKaguvtEBcGaAALVDUoH479VskPUQ6hrfS7KcWrATBdb8sf4W5MFpx7UNitzq2fzSKC96mQRUzy5uELe7Y7vexm5ArNEyr6ARkypZypSzJ2CEifjVxxRBEWVtbdqHrwP4gWv6cMdbqFWwuXAw2BZQnWpZFtKAGQ9m";
632 let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
633 let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
634 let expr = addr.script().unwrap().proposition().unwrap();
635 check_pretty(
636 expr,
637 expect![[r#"
638 {
639 val v1 = OUTPUTS(0)
640 val v2 = v1.tokens
641 val v3 = SELF.tokens
642 val v4 = v2(2)
643 val v5 = v3(2)
644 val v6 = v2(3)
645 val v7 = v3(3)
646 val v8 = v2(4)
647 val v9 = v3(4)
648 val v10 = SELF.getReg(4).get
649 val v11 = SELF.getReg(5).get
650 val v12 = SELF.getReg(6).get
651 val v13 = 1000000000000000000 - v5._2
652 val v14 = 1000000000000000000 - v4._2 - v13
653 val v15 = v6._2
654 val v16 = upcast(v15)
655 val v17 = v8._2
656 val v18 = upcast(v17)
657 val v19 = v16 * upcast(v11._2) >= v18 * upcast(v11._1) && v16 * upcast(v12._2) < v18 * upcast(v12._1)
658 val v20 = v7._2
659 val v21 = v15 - v20
660 val v22 = v21 > 0
661 val v23 = v9._2
662 val v24 = upcast(v23)
663 val v25 = upcast(v21)
664 val v26 = v17 - v23
665 val v27 = upcast(v20)
666 val v28 = 1000
667 val v29 = upcast(v26)
668 val v30 = upcast(v13)
669 val v31 = upcast(v14) / v30
670 sigmaProp(v1.propBytes == SELF.propBytes && v1.value >= SELF.value && v2(0) == v3(0) && v2(1) == v3(1) && v4._1 == v5._1 && v6._1 == v7._1 && v8._1 == v9._1 && v1.getReg(4).get == v10 && v1.getReg(5).get == v11 && v1.getReg(6).get == v12 && if (v14 == 0) if (v22) v24 * v25 * upcast(v10) >= upcast(-v26) * v27 * upcast(v28) + upcast(v21 * upcast(v10)) else v27 * v29 * upcast(v10) >= upcast(-v21) * v24 * upcast(v28) + upcast(v26 * upcast(v10)) && v19 else if (v22 && v26 > 0) upcast(-v14) <= v25 * v30 / v27 min v29 * v30 / v24 && v19 else v25 >= v31 * v27 && v29 >= v31 * v24)
671 }
672 "#]],
673 )
674 }
675
676 #[test]
677 fn eip_22_auction() {
678 let p2s_addr_str = "GE68RH3VEgW6b4kN3GhYigrLxoXr9jMgMpmm3KnXJaYq1PzHieYhz7Uka86idxvBWLRLmpiA3HrxHPsX1jzQZEv5yaRDueiJqks1keM7iB1eYWMEVRUUq1MLFzdA1FHQwCfSakM3Uc8uBPqk2icxhoXvw1CVbUVtFCzcPrZzf8Jjf8gS5bCFpWQscHo14HTsdBxyV3dwL6wKu8LP8FuWJE7qCEgX9ToEiztH4ZLmFwBejnUFrCQqjLVLWpdgdnAXVyewiX9DxXKJKL4wNqhPUrYjmHEVvpZAezXjzfVMr7gKupTqAgx2AJYGh4winEDeYq9MVshX8xjJweGhbAm2RXN1euQpoepFaKqfrT2mQBTmr6edbbzYg6VJ7DoSCDzmcUupFAmZMjMiaUbgtyz2VEbPEKsmAFrZ6zdB5EUxhiYZMd6KdstsJwZCgKJSSCShTgpfqNLCdpR9JbZFQpA1uhUkuLMPvGi74V5EwijTEEtjmTVcWcVhJKv4GDr1Lqe2bMPq4jfEfqvemaY8FcrCsCSi2LZoQUeJ9VrBeotGTKccq8JhwnvNGhLUUrrm32v3bhU82jbtVBVFRD3FSv5hhS6pKHtTevjwuG7JWoR3LN7279A7zQGJWmkSWDoEhHjgxseqZ2G5bLB7ZVEzKM261QhwMwmXA1eWgq8zdBH1u9kFC9bMQ812q2DPZTuhzpBWJh74UGwaEgZLhnUrDKT58cEa4R3kfWyGCMoNw78q1E3a2eKDz8Va5wnixzT2SZFHU8DfHjPSz5rm8Mr3YxgRC6GzaasPDxTrZjuMJHU2exhqsoFvur7Q";
680 let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
681 let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
682 let expr = addr.script().unwrap().proposition().unwrap();
683 check_pretty(
684 expr,
685 expect![[r#"
686 {
687 val v1 = OUTPUTS(0)
688 val v2 = CONTEXT.preHeader.timestamp
689 val v3 = SELF.getReg(7).get
690 val v4 = SELF.tokens
691 val v5 = v4.size
692 val v6 = v5 == 1
693 val v7 = {
694 (v7: Box) =>
695 if (v6) v7.value else v7.tokens(1)._2
696 }
697
698 val v8 = v7(SELF)
699 val v9 = SELF.getReg(6).get
700 val v10 = SELF.getReg(8).get
701 val v11 = Coll[Coll[Byte]]()
702 val v12 = OUTPUTS(1)
703 val v13 = SELF.getReg(5).get
704 val v14 = SELF.getReg(4).get
705 val v15 = CONTEXT.dataInputs(0)
706 val v16 = v15.getReg(8).get
707 sigmaProp(v1.value >= SELF.value && v2 < v3 && v1.tokens(0) == v4(0) && {
708 val v17 = v7(v1)
709 v17 >= v8 + v9 || v10 != -1 && v17 >= v10
710 }
711 && v1.propBytes == SELF.propBytes && v5 == v1.tokens.size && {
712 (v17: Box) =>
713 if (v6) v11 else v17.tokens(1)._1
714 }
715 (SELF) == {
716 (v17: Box) =>
717 if (v6) v11 else v17.tokens(1)._1
718 }
719 (v1) && v12.propBytes == v13 && v7(v12) >= v8 && v1.getReg(4).get == v14 && v1.getReg(5).get.size > 0 && v1.getReg(6).get == v9 && v1.getReg(7).get == if (v3 - v2 <= v16(0)) v3 + v16(1) else v3 && v1.getReg(8).get == v10 && v1.getReg(9) == SELF.getReg(9) || if (OUTPUTS.size == 5) {
720 val v17 = OUTPUTS(2)
721 val v18 = v8 / upcast(v15.getReg(4).get)
722 val v19 = v4(0)
723 val v20 = v8 / upcast(v15.getReg(6).get)
724 val v21 = OUTPUTS(3)
725 val v22 = v21.getReg(4).get
726 v2 >= v3 || v8 >= v10 && v10 != -1 && v7(v17) >= v18 && v17.propBytes == v15.getReg(5).get && v1.tokens(0) == v19 && v1.propBytes == v13 && v7(v12) >= v8 - v18 - v20 - if (v6) v15.getReg(7).get * 2 else 0 && v12.propBytes == v14 && blake2b256(v22.bytes) == v19._1 && v7(v21) >= v20 && v21.propBytes == v22.propBytes
727 }
728 else false)
729 }
730 "#]],
731 )
732 }
733}