From e02a25507c4156be5a7de3732d7110dd8c24a22f Mon Sep 17 00:00:00 2001 From: Vara Prasad Bandaru Date: Mon, 9 Jan 2023 14:54:00 +0530 Subject: [PATCH 1/4] Use intcblock,bytecblock information for intc*, bytec* instructions --- .github/workflows/pytest310.yml | 1 + tealer/teal/instructions/instructions.py | 134 +- tealer/teal/parse_teal.py | 39 +- tealer/teal/teal.py | 43 +- tealer/utils/analyses.py | 30 + tests/detectors/can_update.py | 44 + .../router_with_assembled_constants.py | 101 + tests/parsing/intcblock_1.teal | 1708 +++++++++++++++++ tests/parsing/intcblock_2.teal | 653 +++++++ tests/parsing/intcblock_3.teal | 1513 +++++++++++++++ tests/test_detectors_using_pyteal.py | 49 + tests/test_parsing.py | 121 ++ 12 files changed, 4386 insertions(+), 50 deletions(-) create mode 100644 tests/detectors/router_with_assembled_constants.py create mode 100644 tests/parsing/intcblock_1.teal create mode 100644 tests/parsing/intcblock_2.teal create mode 100644 tests/parsing/intcblock_3.teal create mode 100644 tests/test_detectors_using_pyteal.py diff --git a/.github/workflows/pytest310.yml b/.github/workflows/pytest310.yml index c5ef6c8..9be69fa 100644 --- a/.github/workflows/pytest310.yml +++ b/.github/workflows/pytest310.yml @@ -54,6 +54,7 @@ jobs: - name: Run detectors tests in 3.10 run: | pytest tests/test_detectors.py + pytest tests/test_detectors_using_pyteal.py - name: Run dataflow analysis tests in 3.10 run: | diff --git a/tealer/teal/instructions/instructions.py b/tealer/teal/instructions/instructions.py index 959c3fc..b9531c7 100644 --- a/tealer/teal/instructions/instructions.py +++ b/tealer/teal/instructions/instructions.py @@ -4003,8 +4003,28 @@ def __init__(self, int_list: List[int]): def __str__(self) -> str: return " ".join(["intcblock"] + list(map(str, self._constants))) + @property + def constants(self) -> List[int]: + return self._constants + + +class IntcInstruction(Instruction): + """Base class for Intc, Intc_0, Intc_1, Intc_2, Intc_3""" + + def __init__(self) -> None: + super().__init__() + self._idx: int = 0 -class Intc(Instruction): + @property + def index(self) -> int: + return self._idx + + @property + def stack_push_size(self) -> int: + return 1 + + +class Intc(IntcInstruction): """`intc i` push integer constant loaded from constant storage space. Immediates: @@ -4022,12 +4042,8 @@ def __init__(self, idx: int): def __str__(self) -> str: return f"intc {self._idx}" - @property - def stack_push_size(self) -> int: - return 1 - -class Intc0(Instruction): +class Intc0(IntcInstruction): """`intc_0` push integer constant 0 from constant storage space. Pushes: @@ -4035,15 +4051,15 @@ class Intc0(Instruction): """ + def __init__(self) -> None: + super().__init__() + self._idx = 0 + def __str__(self) -> str: return "intc_0" - @property - def stack_push_size(self) -> int: - return 1 - -class Intc1(Instruction): +class Intc1(IntcInstruction): """`intc_1` push integer constant 1 from constant storage space. Pushes: @@ -4051,15 +4067,15 @@ class Intc1(Instruction): """ + def __init__(self) -> None: + super().__init__() + self._idx = 1 + def __str__(self) -> str: return "intc_1" - @property - def stack_push_size(self) -> int: - return 1 - -class Intc2(Instruction): +class Intc2(IntcInstruction): """`intc_2` push integer constant 2 from constant storage space. Pushes: @@ -4067,15 +4083,15 @@ class Intc2(Instruction): """ + def __init__(self) -> None: + super().__init__() + self._idx = 2 + def __str__(self) -> str: return "intc_2" - @property - def stack_push_size(self) -> int: - return 1 - -class Intc3(Instruction): +class Intc3(IntcInstruction): """`intc_3` push integer constant 3 from constant storage space. Pushes: @@ -4083,15 +4099,31 @@ class Intc3(Instruction): """ - @property - def stack_push_size(self) -> int: - return 1 + def __init__(self) -> None: + super().__init__() + self._idx = 3 def __str__(self) -> str: return "intc_3" -class Bytec(Instruction): +class BytecInstruction(Instruction): + """Base class for Bytec, Bytec_0, Bytec_1, Bytec_2, Bytec_3""" + + def __init__(self) -> None: + super().__init__() + self._idx: int = 0 + + @property + def index(self) -> int: + return self._idx + + @property + def stack_push_size(self) -> int: + return 1 + + +class Bytec(BytecInstruction): """`bytec i` push byte constant loaded from constant storage space. Immediates: @@ -4106,15 +4138,11 @@ def __init__(self, idx: int): super().__init__() self._idx = idx - @property - def stack_push_size(self) -> int: - return 1 - def __str__(self) -> str: return f"bytec {self._idx}" -class Bytec0(Instruction): +class Bytec0(BytecInstruction): """`bytec_0` push byte constant 0 from constant storage space. Pushes: @@ -4122,6 +4150,10 @@ class Bytec0(Instruction): """ + def __init__(self) -> None: + super().__init__() + self._idx = 0 + def __str__(self) -> str: return "bytec_0" @@ -4130,7 +4162,7 @@ def stack_push_size(self) -> int: return 1 -class Bytec1(Instruction): +class Bytec1(BytecInstruction): """`bytec_1` push byte constant 1 from constant storage space. Pushes: @@ -4138,15 +4170,15 @@ class Bytec1(Instruction): """ + def __init__(self) -> None: + super().__init__() + self._idx = 1 + def __str__(self) -> str: return "bytec_1" - @property - def stack_push_size(self) -> int: - return 1 - -class Bytec2(Instruction): +class Bytec2(BytecInstruction): """`bytec_2` push byte constant 2 from constant storage space. Pushes: @@ -4154,15 +4186,15 @@ class Bytec2(Instruction): """ + def __init__(self) -> None: + super().__init__() + self._idx = 2 + def __str__(self) -> str: return "bytec_2" - @property - def stack_push_size(self) -> int: - return 1 - -class Bytec3(Instruction): +class Bytec3(BytecInstruction): """`bytec_3` push byte constant 3 from constant storage space. Pushes: @@ -4170,13 +4202,13 @@ class Bytec3(Instruction): """ + def __init__(self) -> None: + super().__init__() + self._idx = 3 + def __str__(self) -> str: return "bytec_3" - @property - def stack_push_size(self) -> int: - return 1 - class Arg(Instruction): """`arg n` pushes n LogicSig argument to stack. @@ -4307,6 +4339,10 @@ def __str__(self) -> str: def stack_push_size(self) -> int: return 1 + @property + def value(self) -> str: + return self._bytes + class PushBytes(Instruction): """`pushbytes x` instruction pushes immediate value to the top of the stack. @@ -4339,6 +4375,10 @@ def __str__(self) -> str: def stack_push_size(self) -> int: return 1 + @property + def value(self) -> str: + return self._bytes + class Len(Instruction): """`len` calculates the length of the given byte array. @@ -4373,6 +4413,10 @@ def __init__(self, bytes_list: List[str]): super().__init__() self._constants = bytes_list + @property + def constants(self) -> List[str]: + return self._constants + def __str__(self) -> str: return " ".join(["bytecblock"] + self._constants) diff --git a/tealer/teal/parse_teal.py b/tealer/teal/parse_teal.py index bd893d5..6acc747 100644 --- a/tealer/teal/parse_teal.py +++ b/tealer/teal/parse_teal.py @@ -27,7 +27,7 @@ import inspect import sys -from typing import Optional, Dict, List +from typing import Optional, Dict, List, Tuple from tealer.teal.basic_blocks import BasicBlock from tealer.teal.instructions.instructions import ( @@ -43,6 +43,8 @@ Pragma, Switch, Match, + Intcblock, + Bytecblock, ) from tealer.teal.instructions.instructions import ContractType from tealer.teal.instructions.parse_instruction import parse_line, ParseError @@ -155,7 +157,7 @@ def _first_pass( labels: Dict[str, Label], rets: Dict[str, List[Instruction]], instructions: List[Instruction], -) -> None: +) -> Tuple[List[Intcblock], List[Bytecblock]]: """Parse instructions and add sequential instruction links. This function is the first pass of the teal parser. Source code @@ -196,6 +198,8 @@ def _first_pass( idx = 0 prev: Optional[Instruction] = None # Flag: last instruction was an unconditional jump call: Optional[Callsub] = None # Flag: last instruction was a callsub + intcblock_ins: List[Intcblock] = [] # List of intcblock instructions present in the contract + bytecblock_ins: List[Bytecblock] = [] # List of bytecblock instructions present in the contract for line in lines: try: @@ -206,6 +210,12 @@ def _first_pass( idx = idx + 1 if not ins: continue + + if isinstance(ins, Intcblock): + intcblock_ins.append(ins) + elif isinstance(ins, Bytecblock): + bytecblock_ins.append(ins) + ins.line = idx # A label? Add it to the global label list @@ -239,6 +249,7 @@ def _first_pass( # Finally, add the instruction to the instruction list instructions.append(ins) + return intcblock_ins, bytecblock_ins def _second_pass( # pylint: disable=too-many-branches @@ -508,6 +519,27 @@ def _apply_transaction_context_analysis(teal: "Teal") -> None: cl(teal).run_analysis() +def _fill_intc_bytec_info( + intcblock_ins: List[Intcblock], + bytecblock_ins: List[Bytecblock], + entry_block: BasicBlock, + teal: Teal, +) -> None: + """Find intcblock, bytecblock instructions and fill that information in Teal class + + Tealer determines intc_*/bytec_* instruction values if and only if intcblock, bytecblock + instructions are used only once and that too in the entry block itself. + + This is the case for most of the contracts as intcblock/bytecblock instructions are generated + internally by the assembler or PyTeal compiler. + """ + if len(intcblock_ins) == 1 and intcblock_ins[0].bb == entry_block: + teal.set_int_constants(intcblock_ins[0].constants) + + if len(bytecblock_ins) == 1 and bytecblock_ins[0].bb == entry_block: + teal.set_byte_constants(bytecblock_ins[0].constants) + + def parse_teal(source_code: str) -> Teal: """Parse algorand smart contracts written in teal. @@ -538,7 +570,7 @@ def parse_teal(source_code: str) -> Teal: lines = source_code.splitlines() - _first_pass(lines, labels, rets, instructions) + intcblock_ins, bytecblock_ins = _first_pass(lines, labels, rets, instructions) _second_pass(instructions, labels, rets) # Third pass over the instructions list: Construct the basic blocks and sequential links @@ -568,6 +600,7 @@ def parse_teal(source_code: str) -> Teal: for bb in teal.bbs: bb.teal = teal + _fill_intc_bytec_info(intcblock_ins, bytecblock_ins, all_bbs[0], teal) _apply_transaction_context_analysis(teal) return teal diff --git a/tealer/teal/teal.py b/tealer/teal/teal.py index e036167..a57316c 100644 --- a/tealer/teal/teal.py +++ b/tealer/teal/teal.py @@ -10,7 +10,7 @@ """ from pathlib import Path -from typing import List, Any, Optional, Type, TYPE_CHECKING +from typing import List, Any, Optional, Type, TYPE_CHECKING, Tuple from tealer.detectors.abstract_detector import AbstractDetector, DetectorClassification from tealer.printers.abstract_printer import AbstractPrinter @@ -55,7 +55,7 @@ def _check_common_things( raise TealerException(f"You can't register {cls.__name__} twice.") -class Teal: +class Teal: # pylint: disable=too-many-instance-attributes """Class to represent a teal contract. This class stores CFG, subroutines and other information of the @@ -87,6 +87,8 @@ def __init__( # pylint: disable=too-many-arguments self._version = version self._mode = mode self._subroutines = subroutines + self._int_constants: List[int] = [] + self._byte_constants: List[str] = [] self._detectors: List[AbstractDetector] = [] self._printers: List[AbstractPrinter] = [] @@ -143,6 +145,43 @@ def mode(self) -> ContractType: def mode(self, m: ContractType) -> None: self._mode = m + def get_int_constant(self, index: int) -> Tuple[bool, int]: + """Return int value stored by intcblock instruction + + Returns boolean and an int. Boolean indicates whether there's a value at that index + and whether Tealer was able to identify that information. + + Cases: + intcblock is only present in the entry block; Tealer is able to identify the confirmed and + correct constants. As a result, Tealer can know the values of `intc_*` instructions. + + intcblock instruction occurs multiple times. Tealer cannot determine the exact value a `intc_` + instruction refers to. This method returns `False` in this case. + + A `intc_*` instruction refers to a value that is not declared in the intcblock instruction. For example, + intcblock only stores 3 values in the constant space and a intc instruction refers to 5th value. Execution + will fail at runtime in this case. Return value will be `False` in this case as well. + + Returns: + bool: True if Tealer was able to determine the value referred by that instruction or else False + int: value referred by intc instruction at that index. + """ + if len(self._int_constants) <= index: + return False, 0 + return True, self._int_constants[index] + + def get_byte_constant(self, index: int) -> Tuple[bool, str]: + """Return []byte value stored by bytecblock instruction""" + if len(self._byte_constants) <= index: + return False, "" + return True, self._byte_constants[index] + + def set_int_constants(self, int_constants: List[int]) -> None: + self._int_constants = int_constants + + def set_byte_constants(self, byte_constants: List[str]) -> None: + self._byte_constants = byte_constants + # from slither: Slither Class in slither/slither.py @property def detectors(self) -> List[AbstractDetector]: diff --git a/tealer/utils/analyses.py b/tealer/utils/analyses.py index 62043aa..f0d06b5 100644 --- a/tealer/utils/analyses.py +++ b/tealer/utils/analyses.py @@ -15,15 +15,45 @@ BZ, BNZ, Assert, + Byte, + PushBytes, + IntcInstruction, + BytecInstruction, ) from tealer.teal.instructions.transaction_field import TransactionField, OnCompletion, ApplicationID +from tealer.exceptions import TealerException + def is_int_push_ins(ins: Instruction) -> Tuple[bool, Optional[Union[int, str]]]: + """Return true if :ins: pushes a int literal on to the stack""" if isinstance(ins, Int) or isinstance( # pylint: disable=consider-merging-isinstance ins, PushInt ): return True, ins.value + if isinstance(ins, IntcInstruction): + if not ins.bb or not ins.bb.teal: + # TODO: move the check to respective class property + raise TealerException("Block or teal property is not set") + teal = ins.bb.teal + is_known, value = teal.get_int_constant(ins.index) + if is_known: + return True, value + return False, None + + +def is_byte_push_ins(ins: Instruction) -> Tuple[bool, Optional[str]]: + """Return true if :ins: pushes a byte literal on to the stack.""" + if isinstance(ins, (Byte, PushBytes)): + return True, ins.value + if isinstance(ins, BytecInstruction): + if not ins.bb or not ins.bb.teal: + # TODO: move the check to respective class property + raise TealerException("Block or teal property is not set") + teal = ins.bb.teal + is_known, value = teal.get_byte_constant(ins.index) + if is_known: + return True, value return False, None diff --git a/tests/detectors/can_update.py b/tests/detectors/can_update.py index 925cfe9..2073e90 100644 --- a/tests/detectors/can_update.py +++ b/tests/detectors/can_update.py @@ -390,8 +390,52 @@ [0, 2, 7, 8, 9], ] +CAN_UPDATE_GROUP_INDEX_INTC_0 = """ +#pragma version 6 +intcblock 0 1 0x2 0x9301 0x3 0x4 0x5 +txn GroupIndex +int 0 +== +assert +int 0 +gtxn 0 ApplicationID +== +bz not_creation +int 1 +return +not_creation: + gtxn 0 OnCompletion + intc_0 + == + bnz handle_noop + gtxn 0 OnCompletion + intc_1 + == + bnz handle_optin + gtxn 0 OnCompletion + intc_2 + == + bnz handle_closeout + gtxn 0 OnCompletion + intc 5 + == + bnz handle_updateapp + int 1 + return +handle_noop: +handle_optin: +handle_closeout: +int 1 +return +handle_updateapp: +err +""" + +CAN_UPDATE_GROUP_INDEX_INTC_0_VULNERABLE_PATHS: List[List[int]] = [] + new_can_update_tests = [ (CAN_UPDATE_GROUP_INDEX_0, CanUpdate, CAN_UPDATE_GROUP_INDEX_0_VULNERABLE_PATHS), (CAN_UPDATE_GROUP_INDEX_1, CanUpdate, CAN_UPDATE_GROUP_INDEX_1_VULNERABLE_PATHS), (CAN_UPDATE_GROUP_INDEX_2, CanUpdate, CAN_UPDATE_GROUP_INDEX_2_VULNERABLE_PATHS), + (CAN_UPDATE_GROUP_INDEX_INTC_0, CanUpdate, CAN_UPDATE_GROUP_INDEX_INTC_0_VULNERABLE_PATHS), ] diff --git a/tests/detectors/router_with_assembled_constants.py b/tests/detectors/router_with_assembled_constants.py new file mode 100644 index 0000000..f46d5fe --- /dev/null +++ b/tests/detectors/router_with_assembled_constants.py @@ -0,0 +1,101 @@ +# pylint: skip-file +# mypy: ignore-errors +from pyteal import * # pylint: disable=wildcard-import, unused-wildcard-import + +from pyteal import * +from typing import Literal + +from tealer.detectors.all_detectors import CanUpdate, CanDelete + +router = Router( + name="Example", + bare_calls=BareCallActions(), +) + +""" +Pattern for method config having CallConfig.CALL: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + +Pattern for method config having CallConfig.CREATE: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + == + && + assert + +Pattern for method config having CallConfig.ALL: + txn OnCompletion + int NoOp + == + assert + +Tealer cannot calculate the information from first two patterns. For that reason, all of the +methods have CallConfig.ALL. +""" + + +@router.method(no_op=CallConfig.ALL) +def echo(input: abi.Uint64, *, output: abi.Uint64) -> Expr: + """ + Method config validations Teal pattern: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert // Assert(NoOp, CALL) + """ + return output.set(input.get()) + + +@router.method(opt_in=CallConfig.ALL) +def deposit() -> Expr: + return Return() + + +@router.method(close_out=CallConfig.ALL) +def getBalance() -> Expr: + return Return() + + +@router.method(update_application=CallConfig.ALL) +def update() -> Expr: + return Err() + + +@router.method(delete_application=CallConfig.ALL) +def delete() -> Expr: + return Err() + + +# does not matter even if multiple actions are allowed as it fails for all calls. +@router.method(no_op=CallConfig.CALL, opt_in=CallConfig.CREATE, close_out=CallConfig.ALL) +def some(input: abi.Uint64) -> Expr: + return Err() + + +# PyTeal creates intcblock, bytecblock if assemble_constants = True +# int NoOp, OptIn, ... are all replaced by intc_* instructions. +pragma(compiler_version="0.20.1") +approval_program, clear_state_program, contract = router.compile_program( + version=7, + assemble_constants=True, # use intcblock, bytecblock + # optimize=OptimizeOptions(scratch_slots=True), +) + +router_with_assembled_constants = [ + (approval_program, CanUpdate, []), + (approval_program, CanDelete, []), +] diff --git a/tests/parsing/intcblock_1.teal b/tests/parsing/intcblock_1.teal new file mode 100644 index 0000000..14a5b1f --- /dev/null +++ b/tests/parsing/intcblock_1.teal @@ -0,0 +1,1708 @@ +// reference: https://algoexplorer.io/application/900932886 +#pragma version 6 + intcblock 0 1 400 1000 600 1000000000000000 4 1000000000000000000 64 6 + bytecblock 0x757473 0x737473 0x75737473 0x7575725f 0x6c6d 0x7473 0x72635f 0x727063 0x76656169 0x7270635f 0x726561 0x7572635f 0x757270635f 0x7270735f 0x72695f 0x726d6169 0x6c74 0x637574 0x656461 0x7261695f 0x72705f 0x637564 0x6461 0x6169 0x63756168 0x63756368 0x757662 0x626d 0x75727073 + txn ApplicationID // id=0 + intc_0 // 0 + == + bnz label1 + txn OnCompletion + intc 6 // 4 + == + bnz label2 + txn OnCompletion + intc_1 // 1 + == + bnz label3 + txn Sender // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 22 // "da" + app_global_get + == + txn Sender // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 18 // "eda" + app_global_get + == + || + bnz label4 + bytec 15 // "rmai" + app_global_get + intc_0 // 0 + != + bytec 15 // "rmai" + app_global_get + global CallerApplicationID + == + && + txn OnCompletion + intc_0 // 0 + == + && + bnz label5 + txn OnCompletion + intc_0 // 0 + == + bnz label6 + txn OnCompletion + pushint 2 + == + bnz label7 + txn OnCompletion + pushint 5 + == + bnz label8 + err +label8: + intc_0 // 0 + return +label7: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + intc_0 // 0 + == + assert + txna ApplicationArgs 1 + btoi + intc_0 // 0 + == + bnz label9 +label10: + intc_1 // 1 + return +label9: + intc_0 // 0 + store 0 +label11: + load 0 + bytec 7 // "rpc" + app_global_get + < + bz label10 + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + app_local_get + intc_0 // 0 + == + assert + load 0 + intc_1 // 1 + + + store 0 + b label11 +label6: + txna ApplicationArgs 0 + pushbytes 0x666f // "fo" + == + bnz label12 + txna ApplicationArgs 0 + pushbytes 0x757475 // "utu" + == + bnz label13 + intc_1 // 1 + bnz label14 + err +label14: + intc_0 // 0 + store 0 +label35: + load 0 + bytec 7 // "rpc" + app_global_get + < + bnz label15 + bytec 16 // "lt" + global LatestTimestamp // Tue, 11 Oct 2022 22:36:03 UTC + app_global_put + bytec_1 // "sts" + bytec_1 // "sts" + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + - + app_global_put + bytec 8 // "veai" + app_global_get + intc_0 // 0 + != + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 8 // "veai" + app_global_get + app_opted_in + && + bnz label16 + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + intc_0 // 0 + app_local_put +label32: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + intc_2 // 400 + mulw + intc_0 // 0 + intc_3 // 1000 + divmodw + pop + pop + swap + ! + assert + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + app_local_get + bytec 5 // "ts" + app_global_get + mulw + intc 4 // 600 + uncover 2 + dig 1 + * + cover 2 + mulw + cover 2 + + + swap + intc_0 // 0 + intc 5 // 1000000000000000 + divmodw + pop + pop + swap + ! + assert + + + < + bnz label17 + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + intc_2 // 400 + mulw + intc_0 // 0 + intc_3 // 1000 + divmodw + pop + pop + swap + ! + assert + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + app_local_get + bytec 5 // "ts" + app_global_get + mulw + intc 4 // 600 + uncover 2 + dig 1 + * + cover 2 + mulw + cover 2 + + + swap + intc_0 // 0 + intc 5 // 1000000000000000 + divmodw + pop + pop + swap + ! + assert + + +label31: + app_local_put + bytec_1 // "sts" + bytec_1 // "sts" + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + + + app_global_put + txna ApplicationArgs 0 + pushbytes 0x73 // "s" + == + bnz label18 + txna ApplicationArgs 0 + pushbytes 0x75 // "u" + == + bnz label19 + txna ApplicationArgs 0 + pushbytes 0x6372 // "cr" + == + bnz label20 + err +label20: + txna ApplicationArgs 1 + btoi + bytec 7 // "rpc" + app_global_get + < + assert + txna ApplicationArgs 1 + btoi + store 0 + bytec 19 // "rai_" + load 0 + itob + concat + app_global_get + intc_1 // 1 + == + bnz label21 + bytec 10 // "rea" + app_global_get + bytec 19 // "rai_" + load 0 + itob + concat + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + app_local_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + callsub label22 +label24: + bytec 20 // "rp_" + load 0 + itob + concat + bytec 20 // "rp_" + load 0 + itob + concat + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + app_local_get + + + app_global_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + intc_0 // 0 + app_local_put + intc_1 // 1 + return +label21: + bytec 10 // "rea" + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + app_local_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + callsub label23 + b label24 +label19: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + txna ApplicationArgs 1 + btoi + >= + assert + bytec 23 // "ai" + app_global_get + txna ApplicationArgs 1 + btoi + txn Sender // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + callsub label25 + bytec_1 // "sts" + bytec_1 // "sts" + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + - + app_global_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + txna ApplicationArgs 1 + btoi + - + app_local_put + bytec 5 // "ts" + bytec 5 // "ts" + app_global_get + txna ApplicationArgs 1 + btoi + - + app_global_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + intc_2 // 400 + mulw + intc_0 // 0 + intc_3 // 1000 + divmodw + pop + pop + swap + ! + assert + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + app_local_get + bytec 5 // "ts" + app_global_get + mulw + intc 4 // 600 + uncover 2 + dig 1 + * + cover 2 + mulw + cover 2 + + + swap + intc_0 // 0 + intc 5 // 1000000000000000 + divmodw + pop + pop + swap + ! + assert + + + < + bnz label26 + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + intc_2 // 400 + mulw + intc_0 // 0 + intc_3 // 1000 + divmodw + pop + pop + swap + ! + assert + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + app_local_get + bytec 5 // "ts" + app_global_get + mulw + intc 4 // 600 + uncover 2 + dig 1 + * + cover 2 + mulw + cover 2 + + + swap + intc_0 // 0 + intc 5 // 1000000000000000 + divmodw + pop + pop + swap + ! + assert + + +label27: + app_local_put + bytec_1 // "sts" + bytec_1 // "sts" + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + + + app_global_put + intc_1 // 1 + return +label26: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + b label27 +label18: + txn GroupIndex // index=1 + intc_1 // 1 + - + global CurrentApplicationAddress + bytec 23 // "ai" + app_global_get + callsub label28 + txn GroupIndex // index=1 + intc_1 // 1 + - + gtxns AssetAmount + store 1 + bytec_1 // "sts" + bytec_1 // "sts" + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + - + app_global_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + load 1 + + + app_local_put + bytec 5 // "ts" + bytec 5 // "ts" + app_global_get + load 1 + + + app_global_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + intc_2 // 400 + mulw + intc_0 // 0 + intc_3 // 1000 + divmodw + pop + pop + swap + ! + assert + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + app_local_get + bytec 5 // "ts" + app_global_get + mulw + intc 4 // 600 + uncover 2 + dig 1 + * + cover 2 + mulw + cover 2 + + + swap + intc_0 // 0 + intc 5 // 1000000000000000 + divmodw + pop + pop + swap + ! + assert + + + < + bnz label29 + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + intc_2 // 400 + mulw + intc_0 // 0 + intc_3 // 1000 + divmodw + pop + pop + swap + ! + assert + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + app_local_get + bytec 5 // "ts" + app_global_get + mulw + intc 4 // 600 + uncover 2 + dig 1 + * + cover 2 + mulw + cover 2 + + + swap + intc_0 // 0 + intc 5 // 1000000000000000 + divmodw + pop + pop + swap + ! + assert + + +label30: + app_local_put + bytec_1 // "sts" + bytec_1 // "sts" + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + + + app_global_put + intc_1 // 1 + return +label29: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + b label30 +label17: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + b label31 +label16: + itxn_begin + intc 9 // 6 + itxn_field TypeEnum + bytec 8 // "veai" + app_global_get + itxn_field ApplicationID + bytec 26 // "uvb" + itxn_field ApplicationArgs + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + itxn_field Accounts + intc_0 // 0 + itxn_field Fee + itxn_submit + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 8 // "veai" + app_global_get + bytec 27 // "bm" + app_local_get_ex + store 3 + store 2 + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + load 2 + app_local_put + b label32 +label15: + bytec_1 // "sts" + app_global_get + intc_0 // 0 + > + bnz label33 +label37: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 12 // "urpc_" + load 0 + itob + concat + app_local_get + bytec 9 // "rpc_" + load 0 + itob + concat + app_global_get + != + bnz label34 +label36: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + app_local_get + bytec 6 // "rc_" + load 0 + itob + concat + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 11 // "urc_" + load 0 + itob + concat + app_local_get + b- + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + itob + b* + intc 7 // 1000000000000000000 + itob + b/ + btoi + + + app_local_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 11 // "urc_" + load 0 + itob + concat + bytec 6 // "rc_" + load 0 + itob + concat + app_global_get + app_local_put + load 0 + intc_1 // 1 + + + store 0 + b label35 +label34: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + intc_0 // 0 + app_local_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 11 // "urc_" + load 0 + itob + concat + intc 8 // 64 + bzero + app_local_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 12 // "urpc_" + load 0 + itob + concat + bytec 9 // "rpc_" + load 0 + itob + concat + app_global_get + app_local_put + b label36 +label33: + global LatestTimestamp // Tue, 11 Oct 2022 22:36:03 UTC + bytec 16 // "lt" + app_global_get + - + bytec 13 // "rps_" + load 0 + itob + concat + app_global_get + * + store 10 + bytec 6 // "rc_" + load 0 + itob + concat + bytec 6 // "rc_" + load 0 + itob + concat + app_global_get + intc 7 // 1000000000000000000 + itob + load 10 + itob + b* + bytec_1 // "sts" + app_global_get + itob + b/ + b+ + app_global_put + bytec 14 // "ri_" + load 0 + itob + concat + bytec 14 // "ri_" + load 0 + itob + concat + app_global_get + load 10 + + + app_global_put + b label37 +label13: + intc_0 // 0 + store 0 +label45: + load 0 + bytec 7 // "rpc" + app_global_get + < + bnz label38 + bytec 16 // "lt" + global LatestTimestamp // Tue, 11 Oct 2022 22:36:03 UTC + app_global_put + bytec_1 // "sts" + bytec_1 // "sts" + app_global_get + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + - + app_global_put + bytec 8 // "veai" + app_global_get + intc_0 // 0 + != + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 8 // "veai" + app_global_get + app_opted_in + && + bnz label39 + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + intc_0 // 0 + app_local_put +label42: + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + intc_2 // 400 + mulw + intc_0 // 0 + intc_3 // 1000 + divmodw + pop + pop + swap + ! + assert + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + app_local_get + bytec 5 // "ts" + app_global_get + mulw + intc 4 // 600 + uncover 2 + dig 1 + * + cover 2 + mulw + cover 2 + + + swap + intc_0 // 0 + intc 5 // 1000000000000000 + divmodw + pop + pop + swap + ! + assert + + + < + bnz label40 + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + intc_2 // 400 + mulw + intc_0 // 0 + intc_3 // 1000 + divmodw + pop + pop + swap + ! + assert + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + app_local_get + bytec 5 // "ts" + app_global_get + mulw + intc 4 // 600 + uncover 2 + dig 1 + * + cover 2 + mulw + cover 2 + + + swap + intc_0 // 0 + intc 5 // 1000000000000000 + divmodw + pop + pop + swap + ! + assert + + +label41: + app_local_put + bytec_1 // "sts" + bytec_1 // "sts" + app_global_get + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + + + app_global_put + intc_1 // 1 + return +label40: + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + app_local_get + b label41 +label39: + itxn_begin + intc 9 // 6 + itxn_field TypeEnum + bytec 8 // "veai" + app_global_get + itxn_field ApplicationID + bytec 26 // "uvb" + itxn_field ApplicationArgs + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + itxn_field Accounts + intc_0 // 0 + itxn_field Fee + itxn_submit + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 8 // "veai" + app_global_get + bytec 27 // "bm" + app_local_get_ex + store 5 + store 4 + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + load 4 + app_local_put + b label42 +label38: + bytec_1 // "sts" + app_global_get + intc_0 // 0 + > + bnz label43 +label47: + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 12 // "urpc_" + load 0 + itob + concat + app_local_get + bytec 9 // "rpc_" + load 0 + itob + concat + app_global_get + != + bnz label44 +label46: + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + app_local_get + bytec 6 // "rc_" + load 0 + itob + concat + app_global_get + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 11 // "urc_" + load 0 + itob + concat + app_local_get + b- + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + itob + b* + intc 7 // 1000000000000000000 + itob + b/ + btoi + + + app_local_put + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 11 // "urc_" + load 0 + itob + concat + bytec 6 // "rc_" + load 0 + itob + concat + app_global_get + app_local_put + load 0 + intc_1 // 1 + + + store 0 + b label45 +label44: + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + intc_0 // 0 + app_local_put + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 11 // "urc_" + load 0 + itob + concat + intc 8 // 64 + bzero + app_local_put + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 12 // "urpc_" + load 0 + itob + concat + bytec 9 // "rpc_" + load 0 + itob + concat + app_global_get + app_local_put + b label46 +label43: + global LatestTimestamp // Tue, 11 Oct 2022 22:36:03 UTC + bytec 16 // "lt" + app_global_get + - + bytec 13 // "rps_" + load 0 + itob + concat + app_global_get + * + store 10 + bytec 6 // "rc_" + load 0 + itob + concat + bytec 6 // "rc_" + load 0 + itob + concat + app_global_get + intc 7 // 1000000000000000000 + itob + load 10 + itob + b* + bytec_1 // "sts" + app_global_get + itob + b/ + b+ + app_global_put + bytec 14 // "ri_" + load 0 + itob + concat + bytec 14 // "ri_" + load 0 + itob + concat + app_global_get + load 10 + + + app_global_put + b label47 +label12: + intc_1 // 1 + return +label5: + txna ApplicationArgs 0 + bytec 28 // "urps" + == + bnz label48 + err +label48: + txna ApplicationArgs 1 + btoi + bytec 7 // "rpc" + app_global_get + < + assert + txna ApplicationArgs 1 + btoi + store 0 + bytec 13 // "rps_" + load 0 + itob + concat + txna ApplicationArgs 2 + btoi + app_global_put + intc_1 // 1 + return +label4: + txn OnCompletion + intc_0 // 0 + == + bnz label49 + err +label49: + txna ApplicationArgs 0 + pushbytes 0x756461 // "uda" + == + bnz label50 + txna ApplicationArgs 0 + pushbytes 0x75656461 // "ueda" + == + bnz label51 + txna ApplicationArgs 0 + pushbytes 0x69726561 // "irea" + == + bnz label52 + txna ApplicationArgs 0 + pushbytes 0x736375 // "scu" + == + bnz label53 + txna ApplicationArgs 0 + pushbytes 0x69637564 // "icud" + == + bnz label54 + txna ApplicationArgs 0 + pushbytes 0x73726d6169 // "srmai" + == + bnz label55 + txna ApplicationArgs 0 + pushbytes 0x7376656169 // "sveai" + == + bnz label56 + txna ApplicationArgs 0 + pushbytes 0x737270 // "srp" + == + bnz label57 + txna ApplicationArgs 0 + bytec 28 // "urps" + == + bnz label58 + txna ApplicationArgs 0 + pushbytes 0x6f6961 // "oia" + == + bnz label59 + txna ApplicationArgs 0 + pushbytes 0x6f69726d // "oirm" + == + bnz label60 + txna ApplicationArgs 0 + pushbytes 0x727261 // "rra" + == + bnz label61 + err +label61: + txna ApplicationArgs 1 + btoi + intc_1 // 1 + == + bnz label62 + bytec 10 // "rea" + app_global_get + txna ApplicationArgs 1 + btoi + txna ApplicationArgs 2 + btoi + txn Sender // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + callsub label22 +label63: + intc_1 // 1 + return +label62: + bytec 10 // "rea" + app_global_get + txna ApplicationArgs 2 + btoi + txn Sender // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + callsub label23 + b label63 +label60: + itxn_begin + intc 9 // 6 + itxn_field TypeEnum + intc_1 // 1 + itxn_field OnCompletion + bytec 15 // "rmai" + app_global_get + itxn_field ApplicationID + pushbytes 0x636f69 // "coi" + itxn_field ApplicationArgs + global CurrentApplicationID // id=900932886 + itxn_field Applications + intc_0 // 0 + itxn_field Fee + itxn_submit + intc_1 // 1 + return +label59: + txna Assets 0 + intc_0 // 0 + global CurrentApplicationAddress + callsub label25 + intc_1 // 1 + return +label58: + txna ApplicationArgs 1 + btoi + bytec 7 // "rpc" + app_global_get + < + assert + txna ApplicationArgs 1 + btoi + store 0 + bytec 13 // "rps_" + load 0 + itob + concat + txna ApplicationArgs 2 + btoi + app_global_put + intc_1 // 1 + return +label57: + txna ApplicationArgs 1 + btoi + bytec 7 // "rpc" + app_global_get + < + assert + txna ApplicationArgs 1 + btoi + store 0 + bytec 9 // "rpc_" + load 0 + itob + concat + bytec 9 // "rpc_" + load 0 + itob + concat + app_global_get + intc_1 // 1 + + + app_global_put + bytec 19 // "rai_" + load 0 + itob + concat + txna Assets 0 + app_global_put + bytec 13 // "rps_" + load 0 + itob + concat + txna ApplicationArgs 2 + btoi + app_global_put + bytec 6 // "rc_" + load 0 + itob + concat + intc 8 // 64 + bzero + app_global_put + bytec 14 // "ri_" + load 0 + itob + concat + intc_0 // 0 + app_global_put + bytec 20 // "rp_" + load 0 + itob + concat + intc_0 // 0 + app_global_put + txna Assets 0 + intc_1 // 1 + != + bnz label64 +label65: + intc_1 // 1 + return +label64: + bytec 10 // "rea" + app_global_get + txna Assets 0 + intc_0 // 0 + bytec 10 // "rea" + app_global_get + callsub label22 + b label65 +label56: + bytec 8 // "veai" + txna Applications 1 + app_global_put + intc_1 // 1 + return +label55: + bytec 15 // "rmai" + txna Applications 1 + app_global_put + intc_1 // 1 + return +label54: + bytec 21 // "cud" + app_global_get + txna ApplicationArgs 1 + btoi + < + assert + bytec 21 // "cud" + txna ApplicationArgs 1 + btoi + app_global_put + intc_1 // 1 + return +label53: + txna ApplicationArgs 1 + btoi + global LatestTimestamp // Tue, 11 Oct 2022 22:36:03 UTC + bytec 21 // "cud" + app_global_get + + + >= + assert + bytec 24 // "cuah" + txna ApplicationArgs 2 + app_global_put + bytec 25 // "cuch" + txna ApplicationArgs 3 + app_global_put + bytec 17 // "cut" + txna ApplicationArgs 1 + btoi + app_global_put + intc_1 // 1 + return +label52: + bytec 10 // "rea" + app_global_get + global ZeroAddress + == + assert + txn GroupIndex // index=1 + intc_1 // 1 + - + gtxns Sender + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + == + assert + txn GroupIndex // index=1 + intc_1 // 1 + - + gtxns CloseRemainderTo + global ZeroAddress + == + assert + txn GroupIndex // index=1 + intc_1 // 1 + - + gtxns RekeyTo + global CurrentApplicationAddress + == + assert + bytec 10 // "rea" + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + app_global_put + intc_1 // 1 + return +label51: + txn Sender // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 18 // "eda" + app_global_get + == + assert + bytec 18 // "eda" + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + app_global_put + intc_1 // 1 + return +label50: + bytec 22 // "da" + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + app_global_put + intc_1 // 1 + return +label3: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_0 // "uts" + intc_0 // 0 + app_local_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + intc_0 // 0 + app_local_put + intc_0 // 0 + store 0 +label68: + load 0 + bytec 7 // "rpc" + app_global_get + < + bnz label66 + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 4 // "lm" + intc_0 // 0 + app_local_put + intc_1 // 1 + return +label66: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 12 // "urpc_" + load 0 + itob + concat + app_local_get + bytec 9 // "rpc_" + load 0 + itob + concat + app_global_get + != + bnz label67 +label69: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + app_local_get + bytec 6 // "rc_" + load 0 + itob + concat + app_global_get + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 11 // "urc_" + load 0 + itob + concat + app_local_get + b- + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_2 // "usts" + app_local_get + itob + b* + intc 7 // 1000000000000000000 + itob + b/ + btoi + + + app_local_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 11 // "urc_" + load 0 + itob + concat + bytec 6 // "rc_" + load 0 + itob + concat + app_global_get + app_local_put + load 0 + intc_1 // 1 + + + store 0 + b label68 +label67: + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec_3 // "uur_" + load 0 + itob + concat + intc_0 // 0 + app_local_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 11 // "urc_" + load 0 + itob + concat + intc 8 // 64 + bzero + app_local_put + txna Accounts 0 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + bytec 12 // "urpc_" + load 0 + itob + concat + bytec 9 // "rpc_" + load 0 + itob + concat + app_global_get + app_local_put + b label69 +label2: + bytec 17 // "cut" + app_global_get + intc_0 // 0 + != + assert + bytec 17 // "cut" + app_global_get + global LatestTimestamp // Tue, 11 Oct 2022 22:36:03 UTC + <= + assert + txn ApprovalProgram + sha256 + bytec 24 // "cuah" + app_global_get + == + assert + txn ClearStateProgram + sha256 + bytec 25 // "cuch" + app_global_get + == + assert + bytec 24 // "cuah" + intc_0 // 0 + app_global_put + bytec 25 // "cuch" + intc_0 // 0 + app_global_put + bytec 17 // "cut" + intc_0 // 0 + app_global_put + intc_1 // 1 + return +label1: + bytec 22 // "da" + txna Accounts 1 // EJAB2PODJFHEPXGR3XZ3JVSZ53DPYBMRHJO7GEDIEYABYA7XT6YLVJ3S4U + app_global_put + bytec 18 // "eda" + txna Accounts 2 + app_global_put + bytec 10 // "rea" + global ZeroAddress + app_global_put + bytec 21 // "cud" + intc_0 // 0 + app_global_put + bytec 17 // "cut" + intc_0 // 0 + app_global_put + bytec 15 // "rmai" + txna Applications 1 + app_global_put + bytec 8 // "veai" + txna Applications 2 + app_global_put + bytec 5 // "ts" + intc_0 // 0 + app_global_put + bytec_1 // "sts" + intc_0 // 0 + app_global_put + bytec 23 // "ai" + txna Assets 0 + app_global_put + bytec 7 // "rpc" + intc 6 // 4 + app_global_put + intc_0 // 0 + store 0 +label71: + load 0 + bytec 7 // "rpc" + app_global_get + < + bnz label70 + bytec 16 // "lt" + global LatestTimestamp // Tue, 11 Oct 2022 22:36:03 UTC + app_global_put + intc_1 // 1 + return +label70: + bytec 9 // "rpc_" + load 0 + itob + concat + bytec 9 // "rpc_" + load 0 + itob + concat + app_global_get + intc_1 // 1 + + + app_global_put + bytec 19 // "rai_" + load 0 + itob + concat + intc_1 // 1 + app_global_put + bytec 13 // "rps_" + load 0 + itob + concat + intc_0 // 0 + app_global_put + bytec 6 // "rc_" + load 0 + itob + concat + intc 8 // 64 + bzero + app_global_put + bytec 14 // "ri_" + load 0 + itob + concat + intc_0 // 0 + app_global_put + bytec 20 // "rp_" + load 0 + itob + concat + intc_0 // 0 + app_global_put + load 0 + intc_1 // 1 + + + store 0 + b label71 +label28: + store 8 + store 7 + store 6 + load 6 + gtxns TypeEnum + intc 6 // 4 + == + assert + load 6 + gtxns AssetReceiver + load 7 + == + assert + load 6 + gtxns XferAsset + load 8 + == + assert + load 6 + gtxns AssetAmount + intc_0 // 0 + > + assert + retsub +label25: + store 12 + store 11 + store 9 + itxn_begin + intc 6 // 4 + itxn_field TypeEnum + load 9 + itxn_field XferAsset + load 11 + itxn_field AssetAmount + load 12 + itxn_field AssetReceiver + intc_0 // 0 + itxn_field Fee + itxn_submit + retsub +label22: + store 16 + store 15 + store 14 + store 13 + itxn_begin + load 13 + itxn_field Sender + intc 6 // 4 + itxn_field TypeEnum + load 14 + itxn_field XferAsset + load 15 + itxn_field AssetAmount + load 16 + itxn_field AssetReceiver + intc_0 // 0 + itxn_field Fee + itxn_submit + retsub +label23: + store 19 + store 18 + store 17 + itxn_begin + load 17 + itxn_field Sender + intc_1 // 1 + itxn_field TypeEnum + load 18 + itxn_field Amount + load 19 + itxn_field Receiver + intc_0 // 0 + itxn_field Fee + itxn_submit + retsub + \ No newline at end of file diff --git a/tests/parsing/intcblock_2.teal b/tests/parsing/intcblock_2.teal new file mode 100644 index 0000000..2fc1690 --- /dev/null +++ b/tests/parsing/intcblock_2.teal @@ -0,0 +1,653 @@ +// reference: https://algoexplorer.io/application/843061415 +#pragma version 5 + intcblock 1 0 2 4 8 16 + bytecblock 0x706f6f6c5f73697a65 0x746f6b656e5f6964 0x656e645f74696d657374616d70 0x746f74616c5f7374616b65 0x6d61785f706f6f6c5f73697a65 0x6d61785f7368617265 0x61646d696e5f61646472657373 0x6d696e5f6c6f636b7570 0x6d61785f6c6f636b7570 0x6d696e5f617079 0x6d61785f617079 + txn OnCompletion + pushint 5 + == + txn OnCompletion + intc_2 // 2 + == + || + txn OnCompletion + intc_3 // 4 + == + || + bnz label1 + txn ApplicationID // id=0 + intc_1 // 0 + == + bnz label2 + txn OnCompletion + intc_1 // 0 + == + bnz label3 + txn OnCompletion + intc_0 // 1 + == + bnz label4 + err +label2: + global GroupSize // size=1 + intc_0 // 1 + == + assert + txn NumAppArgs // index=7 + pushint 7 + == + assert + bytec 4 // "max_pool_size" + txna ApplicationArgs 0 // arg=4563918244f40000 + btoi + app_global_put + bytec 5 // "max_share" + txna ApplicationArgs 1 // arg=4563918244f40000 + btoi + app_global_put + bytec 7 // "min_lockup" + txna ApplicationArgs 2 // arg=000000000013c680 + btoi + app_global_put + bytec 8 // "max_lockup" + txna ApplicationArgs 3 // arg=00000000004f1a00 + btoi + app_global_put + bytec 9 // "min_apy" + txna ApplicationArgs 4 // arg=00000000000001f4 + btoi + app_global_put + bytec 10 // "max_apy" + txna ApplicationArgs 5 // arg=00000000000007d0 + btoi + app_global_put + bytec_2 // "end_timestamp" + txna ApplicationArgs 6 // arg=00000000637abf7f + btoi + app_global_put + bytec_0 // "pool_size" + intc_1 // 0 + app_global_put + bytec 6 // "admin_address" + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + app_global_put + b label4 +label3: + txna ApplicationArgs 0 // arg=4563918244f40000 + pushbytes 0x7365747570 // "setup" + == + bnz label5 + txna ApplicationArgs 0 // arg=4563918244f40000 + pushbytes 0x636c6f7365 // "close" + == + bnz label6 + txna ApplicationArgs 0 // arg=4563918244f40000 + pushbytes 0x7365745f61646d696e5f61646472657373 // "set_admin_address" + == + bnz label7 + txna ApplicationArgs 0 // arg=4563918244f40000 + pushbytes 0x7365745f6d61785f706f6f6c5f73697a65 // "set_max_pool_size" + == + bnz label8 + txna ApplicationArgs 0 // arg=4563918244f40000 + pushbytes 0x7365745f6d61785f7368617265 // "set_max_share" + == + bnz label9 + txna ApplicationArgs 0 // arg=4563918244f40000 + pushbytes 0x7365745f656e645f74696d657374616d70 // "set_end_timestamp" + == + bnz label10 + txna ApplicationArgs 0 // arg=4563918244f40000 + pushbytes 0x7374616b65 // "stake" + == + bnz label11 + txna ApplicationArgs 0 // arg=4563918244f40000 + pushbytes 0x7769746864726177 // "withdraw" + == + bnz label12 + txna ApplicationArgs 0 // arg=4563918244f40000 + pushbytes 0x77697468647261775f6e6f5f72657761726473 // "withdraw_no_rewards" + == + bnz label13 + txna ApplicationArgs 0 // arg=4563918244f40000 + pushbytes 0x646566756e64 // "defund" + == + bnz label14 + err +label5: + callsub label15 + bytec_1 // "token_id" + app_global_get + intc_1 // 0 + == + assert + global GroupSize // size=1 + intc_2 // 2 + == + assert + gtxn 0 TypeEnum + intc_0 // 1 + == + assert + gtxn 0 Receiver // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ + global CurrentApplicationAddress + == + assert + gtxn 0 CloseRemainderTo // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ + global ZeroAddress + == + assert + txn NumAssets + intc_0 // 1 + == + assert + itxn_begin + intc_3 // 4 + itxn_field TypeEnum + txna Assets 0 + itxn_field XferAsset + global CurrentApplicationAddress + itxn_field AssetReceiver + intc_1 // 0 + itxn_field Fee + itxn_submit + bytec_1 // "token_id" + txna Assets 0 + app_global_put + b label4 +label6: + callsub label15 + global GroupSize // size=1 + intc_0 // 1 + == + assert + txn NumAccounts // index=0 + intc_2 // 2 + == + assert + txn NumAssets + intc_0 // 1 + == + assert + bytec_1 // "token_id" + app_global_get + txna Assets 0 + == + assert + bytec_0 // "pool_size" + app_global_get + intc_1 // 0 + == + assert + itxn_begin + intc_3 // 4 + itxn_field TypeEnum + txna Assets 0 + itxn_field XferAsset + txna Accounts 1 + itxn_field AssetCloseTo + intc_1 // 0 + itxn_field Fee + itxn_submit + itxn_begin + intc_0 // 1 + itxn_field TypeEnum + txna Accounts 2 + itxn_field CloseRemainderTo + intc_1 // 0 + itxn_field Fee + itxn_submit + bytec_1 // "token_id" + intc_1 // 0 + app_global_put + b label4 +label7: + callsub label15 + global GroupSize // size=1 + intc_0 // 1 + == + assert + txn NumAppArgs // index=7 + intc_0 // 1 + == + assert + txn NumAccounts // index=0 + intc_0 // 1 + == + assert + bytec 6 // "admin_address" + txna Accounts 1 + app_global_put + b label4 +label8: + callsub label15 + global GroupSize // size=1 + intc_0 // 1 + == + assert + txn NumAppArgs // index=7 + intc_2 // 2 + == + assert + bytec 4 // "max_pool_size" + txna ApplicationArgs 1 // arg=4563918244f40000 + btoi + app_global_put + b label4 +label9: + callsub label15 + global GroupSize // size=1 + intc_0 // 1 + == + assert + txn NumAppArgs // index=7 + intc_2 // 2 + == + assert + bytec 5 // "max_share" + txna ApplicationArgs 1 // arg=4563918244f40000 + btoi + app_global_put + b label4 +label10: + callsub label15 + global GroupSize // size=1 + intc_0 // 1 + == + assert + txn NumAppArgs // index=7 + intc_2 // 2 + == + assert + bytec_2 // "end_timestamp" + app_global_get + txna ApplicationArgs 1 // arg=4563918244f40000 + btoi + < + assert + bytec_2 // "end_timestamp" + txna ApplicationArgs 1 // arg=4563918244f40000 + btoi + app_global_put + b label4 +label11: + global GroupSize // size=1 + intc_2 // 2 + == + assert + gtxn 1 TypeEnum + intc_3 // 4 + == + assert + gtxn 1 Sender // ZW3ISEHZUHPO7OZGMKLKIIMKVICOUDRCERI454I3DB2BH52HGLSO67W754 + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + == + assert + gtxn 1 AssetCloseTo // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ + global ZeroAddress + == + assert + gtxn 1 AssetReceiver // XJJZYVOLPSNLK3UMCZM4N2YSJMLPOIUISZJRP6RWT6FJRET23RJEMDTA5Q + global CurrentApplicationAddress + == + assert + gtxn 1 XferAsset // id=27165954 + bytec_1 // "token_id" + app_global_get + == + assert + txn NumAppArgs // index=7 + pushint 3 + == + assert + callsub label16 + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + global CurrentApplicationID // id=843061415 + load 0 + app_local_get_ex + bnz label1 + pop + txna ApplicationArgs 2 // arg=000000000013c680 + btoi + callsub label17 + >= + assert + txna ApplicationArgs 2 // arg=000000000013c680 + btoi + callsub label18 + <= + assert + global LatestTimestamp // Thu, 18 Aug 2022 12:52:33 UTC + txna ApplicationArgs 2 // arg=000000000013c680 + btoi + + + bytec_2 // "end_timestamp" + app_global_get + <= + assert + gtxn 1 AssetAmount // 0.000000 + intc_1 // 0 + > + assert + bytec_0 // "pool_size" + app_global_get + gtxn 1 AssetAmount // 0.000000 + + + bytec 4 // "max_pool_size" + app_global_get + <= + assert + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + bytec_3 // "total_stake" + app_local_get + dup + store 1 + gtxn 1 AssetAmount // 0.000000 + + + bytec 5 // "max_share" + app_global_get + <= + assert + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + load 0 + gtxn 1 AssetAmount // 0.000000 + itob + global LatestTimestamp // Thu, 18 Aug 2022 12:52:33 UTC + itob + concat + txna ApplicationArgs 2 // arg=000000000013c680 + concat + app_local_put + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + bytec_3 // "total_stake" + load 1 + gtxn 1 AssetAmount // 0.000000 + + + app_local_put + bytec_0 // "pool_size" + bytec_0 // "pool_size" + app_global_get + gtxn 1 AssetAmount // 0.000000 + + + app_global_put + b label4 +label12: + global GroupSize // size=1 + intc_0 // 1 + == + assert + txn NumAppArgs // index=7 + intc_2 // 2 + == + assert + callsub label16 + callsub label19 + callsub label20 + callsub label21 + callsub label22 + callsub label23 + - + load 4 + * + store 10 + callsub label23 + callsub label18 + * + store 11 + callsub label22 + callsub label17 + * + store 12 + callsub label18 + callsub label17 + - + store 13 + load 10 + load 11 + + + load 12 + - + load 13 + / + store 5 + load 5 + callsub label24 + load 3 + - + * + load 2 + mulw + pushint 31536000 + pushint 10000 + mulw + callsub label25 + store 7 + callsub label26 + load 6 + load 7 + - + bytec_0 // "pool_size" + app_global_get + >= + assert + itxn_begin + intc_3 // 4 + itxn_field TypeEnum + bytec_1 // "token_id" + app_global_get + itxn_field XferAsset + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + itxn_field AssetReceiver + load 2 + load 7 + + + itxn_field AssetAmount + intc_1 // 0 + itxn_field Fee + itxn_submit + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + load 0 + app_local_del + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + bytec_3 // "total_stake" + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + bytec_3 // "total_stake" + app_local_get + load 2 + - + app_local_put + bytec_0 // "pool_size" + bytec_0 // "pool_size" + app_global_get + load 2 + - + app_global_put + b label4 +label13: + global GroupSize // size=1 + intc_0 // 1 + == + assert + txn NumAppArgs // index=7 + intc_2 // 2 + == + assert + callsub label16 + callsub label19 + callsub label20 + callsub label21 + itxn_begin + intc_3 // 4 + itxn_field TypeEnum + bytec_1 // "token_id" + app_global_get + itxn_field XferAsset + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + itxn_field AssetReceiver + load 2 + itxn_field AssetAmount + intc_1 // 0 + itxn_field Fee + itxn_submit + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + load 0 + app_local_del + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + bytec_3 // "total_stake" + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + bytec_3 // "total_stake" + app_local_get + load 2 + - + app_local_put + bytec_0 // "pool_size" + bytec_0 // "pool_size" + app_global_get + load 2 + - + app_global_put + b label4 +label14: + callsub label15 + global GroupSize // size=1 + intc_0 // 1 + == + assert + txn NumAppArgs // index=7 + intc_2 // 2 + == + assert + txn NumAccounts // index=0 + intc_0 // 1 + == + assert + callsub label26 + load 6 + txna ApplicationArgs 1 // arg=4563918244f40000 + btoi + - + bytec_0 // "pool_size" + app_global_get + >= + assert + itxn_begin + intc_3 // 4 + itxn_field TypeEnum + bytec_1 // "token_id" + app_global_get + itxn_field XferAsset + txna Accounts 1 + itxn_field AssetReceiver + txna ApplicationArgs 1 // arg=4563918244f40000 + btoi + itxn_field AssetAmount + intc_1 // 0 + itxn_field Fee + itxn_submit + b label4 +label4: + intc_0 // 1 + return +label1: + intc_1 // 0 + return +label15: + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + bytec 6 // "admin_address" + app_global_get + == + assert + retsub +label19: + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + global CurrentApplicationID // id=843061415 + load 0 + app_local_get_ex + bz label1 + pop + retsub +label20: + global LatestTimestamp // Thu, 18 Aug 2022 12:52:33 UTC + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + load 0 + app_local_get + intc 4 // 8 + extract_uint64 + - + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + load 0 + app_local_get + intc 5 // 16 + extract_uint64 + >= + assert + retsub +label23: + bytec 9 // "min_apy" + app_global_get + retsub +label22: + bytec 10 // "max_apy" + app_global_get + retsub +label17: + bytec 7 // "min_lockup" + app_global_get + retsub +label18: + bytec 8 // "max_lockup" + app_global_get + retsub +label16: + txna ApplicationArgs 1 // arg=4563918244f40000 + btoi + pushint 10 + < + assert + pushbytes 0x7374616b655f // "stake_" + txna ApplicationArgs 1 // arg=4563918244f40000 + concat + store 0 + retsub +label26: + global CurrentApplicationAddress + bytec_1 // "token_id" + app_global_get + asset_holding_get AssetBalance + assert + store 6 + retsub +label24: + global LatestTimestamp // Thu, 18 Aug 2022 12:52:33 UTC + bytec_2 // "end_timestamp" + app_global_get + > + bnz label27 + global LatestTimestamp // Thu, 18 Aug 2022 12:52:33 UTC + retsub +label27: + bytec_2 // "end_timestamp" + app_global_get + retsub +label21: + txn Sender // YZP4OCGJJRLHAITQBKUZ47XK4PVZ6MX3XEXJVVYK36GMOTRFWVYWOQ2VZQ + load 0 + app_local_get + dup + dup + intc_1 // 0 + extract_uint64 + store 2 + intc 4 // 8 + extract_uint64 + store 3 + intc 5 // 16 + extract_uint64 + store 4 + retsub +label25: + divmodw + pop + pop + swap + pop + retsub diff --git a/tests/parsing/intcblock_3.teal b/tests/parsing/intcblock_3.teal new file mode 100644 index 0000000..2303f3d --- /dev/null +++ b/tests/parsing/intcblock_3.teal @@ -0,0 +1,1513 @@ +// reference: https://algoexplorer.io/application/842125965 +#pragma version 6 + intcblock 1 0 127 2 1000 86400 128 255 + bytecblock 0x 0x0008 0x677561726469616e 0x63757272656e74477561726469616e536574496e646578 0x6e6f70 0x76657269667953696773 0x4d657373616765466565 0x76616c6964557064617465417070726f766548617368 0x767068617368 0x766572696679564141 0x7075626c6973684d657373616765 0x0001 0x0000000000000000000000000000000000000000000000000000000000000004 0x00000000000000000000000000000000000000000000000000000000436f7265 0x0000 0x626f6f746564 0x50726f6772616d 0x6d657461 + txn ApplicationID // id=842125965 + intc_1 // 0 + == + bnz label1 + txn OnCompletion + pushint 4 + == + bnz label2 + txn OnCompletion + pushint 5 + == + bnz label3 + txn OnCompletion + intc_0 // 1 + == + bnz label4 + txn OnCompletion + intc_1 // 0 + == + bnz label5 + err +label5: + txna ApplicationArgs 0 + bytec 10 // "publishMessage" + == + bnz label6 + txna ApplicationArgs 0 + bytec 4 // "nop" + == + bnz label7 + txna ApplicationArgs 0 + pushbytes 0x696e6974 // "init" + == + bnz label8 + txna ApplicationArgs 0 + bytec 5 // "verifySigs" + == + bnz label9 + txna ApplicationArgs 0 + bytec 9 // "verifyVAA" + == + bnz label10 + txna ApplicationArgs 0 + pushbytes 0x676f7665726e616e6365 // "governance" + == + bnz label11 + err +label11: + callsub label12 + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxns TypeEnum + pushint 6 + == + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxns ApplicationID + txn ApplicationID // id=842125965 + == + && + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxnsa ApplicationArgs 0 + bytec 9 // "verifyVAA" + == + && + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxns Sender + txn Sender // QLSKYBVKSJRZUUDKGN7LET7X3NOAFZ3EI2N7UDZMQLQJOU6DCHXZP6KXCE + == + && + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxns RekeyTo + global ZeroAddress + == + && + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxns OnCompletion + intc_1 // 0 + == + && + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxnsa ApplicationArgs 1 + txna ApplicationArgs 1 + == + && + txn GroupIndex // index=1 + gtxns RekeyTo + global ZeroAddress + == + && + txn GroupIndex // index=1 + gtxns Sender + txn Sender // QLSKYBVKSJRZUUDKGN7LET7X3NOAFZ3EI2N7UDZMQLQJOU6DCHXZP6KXCE + == + && + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxnsa Accounts 0 + txna Accounts 0 + == + && + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxnsa Accounts 1 + txna Accounts 1 + == + && + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxnsa Accounts 2 + txna Accounts 2 + == + && + assert + bytec_3 // "currentGuardianSetIndex" + app_global_get + store 26 + load 26 + intc_1 // 0 + != + bnz label13 +label26: + txna ApplicationArgs 1 + extract 5 1 + btoi + pushint 66 + * + pushint 14 + + + store 21 + txna ApplicationArgs 1 + load 21 + intc_3 // 2 + extract3 + bytec 11 // 0x0001 + == + assert + txna ApplicationArgs 1 + load 21 + intc_3 // 2 + + + pushint 32 + extract3 + bytec 12 // addr AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDTIDK3E + == + assert + load 21 + pushint 43 + + + store 21 + txna ApplicationArgs 1 + load 21 + pushint 32 + extract3 + bytec 13 // addr AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ3POJSZIA5PEA + == + assert + load 21 + pushint 32 + + + store 21 + txna ApplicationArgs 1 + load 21 + intc_0 // 1 + + + intc_3 // 2 + extract3 + store 28 + txna ApplicationArgs 1 + load 21 + intc_0 // 1 + extract3 + btoi + store 22 + load 22 + intc_0 // 1 + == + bnz label14 + load 22 + intc_3 // 2 + == + bnz label15 + load 22 + pushint 3 + == + bnz label16 + load 22 + pushint 4 + == + bnz label17 + err +label17: + load 21 + intc_0 // 1 + + + store 21 + load 28 + bytec_1 // 0x0008 + == + assert + load 21 + pushint 26 + + + store 21 + txna ApplicationArgs 1 + load 21 + pushint 8 + extract3 + btoi + store 24 + load 21 + pushint 8 + + + store 21 + txna ApplicationArgs 1 + load 21 + pushint 32 + extract3 + store 23 + itxn_begin + intc_0 // 1 + itxn_field TypeEnum + load 23 + itxn_field Receiver + load 24 + itxn_field Amount + intc_1 // 0 + itxn_field Fee + itxn_submit +label18: + intc_0 // 1 + return + intc_0 // 1 + return +label16: + load 21 + intc_0 // 1 + + + store 21 + load 28 + bytec_1 // 0x0008 + == + assert + load 21 + intc_3 // 2 + + + pushint 24 + + + store 21 + txna ApplicationArgs 1 + load 21 + pushint 8 + extract3 + btoi + store 24 + bytec 6 // "MessageFee" + load 24 + app_global_put + b label18 +label15: + load 28 + bytec_1 // 0x0008 + == + load 28 + bytec 14 // 0x0000 + == + || + assert + load 21 + pushint 3 + + + store 21 + txna ApplicationArgs 1 + load 21 + pushint 4 + extract3 + btoi + store 25 + txna Accounts 3 + load 25 + bytec_2 // "guardian" + callsub label19 + == + assert + intc_1 // 0 + intc_1 // 0 + == + bnz label20 +label25: + bytec_3 // "currentGuardianSetIndex" + load 25 + app_global_put + load 21 + pushint 4 + + + store 21 + txna ApplicationArgs 1 + load 21 + intc_0 // 1 + extract3 + btoi + store 27 + load 27 + intc_1 // 0 + > + assert + pushint 3 + intc_1 // 0 + txna ApplicationArgs 1 + load 21 + intc_0 // 1 + pushint 20 + load 27 + * + + + extract3 + callsub label21 + pop + txna Accounts 3 + txna Accounts 2 + != + bnz label22 +label24: + pushint 3 + bytec_2 // "guardian" + callsub label23 + b label18 +label22: + intc_3 // 2 + intc 4 // 1000 + global LatestTimestamp // Wed, 28 Sep 2022 14:05:30 UTC + intc 5 // 86400 + + + itob + callsub label21 + pop + b label24 +label20: + txna Accounts 3 + txna Accounts 2 + != + assert + load 25 + load 26 + intc_0 // 1 + + + == + assert + b label25 +label14: + load 28 + bytec_1 // 0x0008 + == + assert + load 21 + pushint 3 + + + store 21 + bytec 7 // "validUpdateApproveHash" + txna ApplicationArgs 1 + load 21 + pushint 32 + extract3 + app_global_put + b label18 +label13: + txna ApplicationArgs 1 + extract 1 4 + store 25 + load 25 + btoi + load 26 + == + assert + b label26 +label10: + txna Accounts 2 + txna ApplicationArgs 1 + extract 1 4 + btoi + bytec_2 // "guardian" + callsub label19 + == + assert + intc_3 // 2 + bytec_2 // "guardian" + callsub label27 + intc_3 // 2 + intc_1 // 0 + callsub label28 + store 12 + load 12 + intc_1 // 0 + > + assert + intc_3 // 2 + intc_0 // 1 + intc_0 // 1 + pushint 20 + load 12 + * + + + callsub label29 + store 13 + intc_3 // 2 + intc 4 // 1000 + pushint 1008 + callsub label29 + btoi + store 18 + load 18 + intc_1 // 0 + != + bnz label30 +label43: + pushbytes 0x00000000 // 0x00000000 + store 17 + txna ApplicationArgs 1 + extract 5 1 + btoi + store 14 + pushint 6 + load 14 + pushint 66 + * + + + store 15 + txna ApplicationArgs 1 + load 15 + txna ApplicationArgs 1 + len + load 15 + - + extract3 + keccak256 + keccak256 + store 16 + load 12 + intc_1 // 0 + > + load 14 + load 12 + <= + && + load 14 + load 12 + intc_3 // 2 + * + pushint 3 + / + > + && + assert + pushint 6 + store 15 + txn GroupIndex // index=1 + intc_1 // 0 + > + assert + txn GroupIndex // index=1 + intc_0 // 1 + - + store 10 + load 10 + gtxns NumAppArgs + intc_1 // 0 + > + assert + load 10 + gtxnsa ApplicationArgs 0 + store 11 +label42: + load 10 + intc_1 // 0 + > + load 11 + bytec 5 // "verifySigs" + == + load 11 + bytec 4 // "nop" + == + || + && + bnz label31 +label41: + load 11 + bytec 5 // "verifySigs" + != + load 11 + bytec 4 // "nop" + != + && + bnz label32 +label37: + load 10 + txn GroupIndex // index=1 + <= + bnz label33 + load 15 + pushint 6 + load 14 + pushint 66 + * + + + == + assert + intc_0 // 1 + return +label33: + load 10 + gtxns TypeEnum + pushint 6 + == + load 10 + gtxns RekeyTo + global ZeroAddress + == + && + load 10 + gtxns ApplicationID + txn ApplicationID // id=842125965 + == + && + load 10 + gtxnsa Accounts 1 + txna Accounts 1 + == + && + load 10 + gtxnsa Accounts 2 + txna Accounts 2 + == + && + assert + load 10 + gtxnsa ApplicationArgs 0 + store 11 + load 11 + bytec 5 // "verifySigs" + == + bnz label34 + load 11 + bytec 4 // "nop" + == + bnz label35 + load 11 + bytec 9 // "verifyVAA" + == + bnz label35 + intc_0 // 1 + intc_0 // 1 + == + bnz label36 + err +label36: + intc_1 // 0 + return +label35: + load 10 + intc_0 // 1 + + + store 10 + b label37 +label34: + load 10 + gtxnsa ApplicationArgs 1 + store 18 + load 18 + len + intc_1 // 0 + > + assert + txna ApplicationArgs 1 + load 15 + load 18 + len + extract3 + load 18 + == + assert + load 15 + load 18 + len + + + store 19 + bytec_0 // "" + store 18 +label39: + load 15 + load 19 + < + bnz label38 + load 10 + gtxnsa ApplicationArgs 2 + load 18 + == + load 10 + gtxns Sender + bytec 8 // "vphash" + app_global_get + == + && + load 10 + gtxnsa ApplicationArgs 3 + load 16 + == + && + assert + b label35 +label38: + txna ApplicationArgs 1 + load 15 + intc_0 // 1 + extract3 + btoi + store 20 + load 17 + load 20 + getbit + intc_1 // 0 + == + assert + load 17 + load 20 + intc_0 // 1 + setbit + store 17 + load 18 + load 13 + load 20 + pushint 20 + * + pushint 20 + extract3 + concat + store 18 + load 15 + pushint 66 + + + store 15 + b label39 +label32: + load 10 + intc_0 // 1 + + + store 10 + b label37 +label31: + load 10 + intc_0 // 1 + - + store 10 + load 10 + gtxns NumAppArgs + intc_1 // 0 + > + bnz label40 + bytec_0 // "" + store 11 + b label41 +label40: + load 10 + gtxnsa ApplicationArgs 0 + store 11 + b label42 +label30: + global LatestTimestamp // Wed, 28 Sep 2022 14:05:30 UTC + load 18 + < + assert + b label43 +label9: + txn Sender // QLSKYBVKSJRZUUDKGN7LET7X3NOAFZ3EI2N7UDZMQLQJOU6DCHXZP6KXCE + bytec 8 // "vphash" + app_global_get + == + return +label8: + bytec 8 // "vphash" + txna ApplicationArgs 2 + app_global_put + txn Sender // QLSKYBVKSJRZUUDKGN7LET7X3NOAFZ3EI2N7UDZMQLQJOU6DCHXZP6KXCE + global CreatorAddress + == + assert + bytec 15 // "booted" + app_global_get + intc_1 // 0 + == + assert + bytec 15 // "booted" + pushbytes 0x74727565 // "true" + app_global_put + callsub label12 + bytec_3 // "currentGuardianSetIndex" + app_global_get + store 7 + load 7 + intc_1 // 0 + != + bnz label44 +label54: + txna ApplicationArgs 1 + extract 5 1 + btoi + pushint 66 + * + pushint 14 + + + store 2 + txna ApplicationArgs 1 + load 2 + intc_3 // 2 + extract3 + bytec 11 // 0x0001 + == + assert + txna ApplicationArgs 1 + load 2 + intc_3 // 2 + + + pushint 32 + extract3 + bytec 12 // addr AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDTIDK3E + == + assert + load 2 + pushint 43 + + + store 2 + txna ApplicationArgs 1 + load 2 + pushint 32 + extract3 + bytec 13 // addr AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ3POJSZIA5PEA + == + assert + load 2 + pushint 32 + + + store 2 + txna ApplicationArgs 1 + load 2 + intc_0 // 1 + + + intc_3 // 2 + extract3 + store 9 + txna ApplicationArgs 1 + load 2 + intc_0 // 1 + extract3 + btoi + store 3 + load 3 + intc_0 // 1 + == + bnz label45 + load 3 + intc_3 // 2 + == + bnz label46 + load 3 + pushint 3 + == + bnz label47 + load 3 + pushint 4 + == + bnz label48 + err +label48: + load 2 + intc_0 // 1 + + + store 2 + load 9 + bytec_1 // 0x0008 + == + assert + load 2 + pushint 26 + + + store 2 + txna ApplicationArgs 1 + load 2 + pushint 8 + extract3 + btoi + store 5 + load 2 + pushint 8 + + + store 2 + txna ApplicationArgs 1 + load 2 + pushint 32 + extract3 + store 4 + itxn_begin + intc_0 // 1 + itxn_field TypeEnum + load 4 + itxn_field Receiver + load 5 + itxn_field Amount + intc_1 // 0 + itxn_field Fee + itxn_submit +label49: + intc_0 // 1 + return +label47: + load 2 + intc_0 // 1 + + + store 2 + load 9 + bytec_1 // 0x0008 + == + assert + load 2 + intc_3 // 2 + + + pushint 24 + + + store 2 + txna ApplicationArgs 1 + load 2 + pushint 8 + extract3 + btoi + store 5 + bytec 6 // "MessageFee" + load 5 + app_global_put + b label49 +label46: + load 9 + bytec_1 // 0x0008 + == + load 9 + bytec 14 // 0x0000 + == + || + assert + load 2 + pushint 3 + + + store 2 + txna ApplicationArgs 1 + load 2 + pushint 4 + extract3 + btoi + store 6 + txna Accounts 3 + load 6 + bytec_2 // "guardian" + callsub label19 + == + assert + intc_0 // 1 + intc_1 // 0 + == + bnz label50 +label53: + bytec_3 // "currentGuardianSetIndex" + load 6 + app_global_put + load 2 + pushint 4 + + + store 2 + txna ApplicationArgs 1 + load 2 + intc_0 // 1 + extract3 + btoi + store 8 + load 8 + intc_1 // 0 + > + assert + pushint 3 + intc_1 // 0 + txna ApplicationArgs 1 + load 2 + intc_0 // 1 + pushint 20 + load 8 + * + + + extract3 + callsub label21 + pop + txna Accounts 3 + txna Accounts 2 + != + bnz label51 +label52: + pushint 3 + bytec_2 // "guardian" + callsub label23 + b label49 +label51: + intc_3 // 2 + intc 4 // 1000 + global LatestTimestamp // Wed, 28 Sep 2022 14:05:30 UTC + intc 5 // 86400 + + + itob + callsub label21 + pop + b label52 +label50: + txna Accounts 3 + txna Accounts 2 + != + assert + load 6 + load 7 + intc_0 // 1 + + + == + assert + b label53 +label45: + load 9 + bytec_1 // 0x0008 + == + assert + load 2 + pushint 3 + + + store 2 + bytec 7 // "validUpdateApproveHash" + txna ApplicationArgs 1 + load 2 + pushint 32 + extract3 + app_global_put + b label49 +label44: + txna ApplicationArgs 1 + extract 1 4 + store 6 + load 6 + btoi + load 7 + == + assert + b label54 +label7: + intc_0 // 1 + return +label6: + txna Accounts 1 + intc_1 // 0 + txn Sender // QLSKYBVKSJRZUUDKGN7LET7X3NOAFZ3EI2N7UDZMQLQJOU6DCHXZP6KXCE + callsub label19 + == + assert + bytec 6 // "MessageFee" + app_global_get + store 1 + load 1 + intc_1 // 0 + > + bnz label55 +label56: + intc_0 // 1 + intc_1 // 0 + pushint 8 + callsub label29 + btoi + intc_0 // 1 + + + itob + store 0 + intc_0 // 1 + intc_1 // 0 + load 0 + callsub label21 + pop + load 0 + log + intc_0 // 1 + bytec 10 // "publishMessage" + callsub label23 + intc_0 // 1 + return +label55: + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxns TypeEnum + intc_0 // 1 + == + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxns Amount + load 1 + >= + && + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxns Receiver + global CurrentApplicationAddress + == + && + txn GroupIndex // index=1 + intc_0 // 1 + - + gtxns RekeyTo + global ZeroAddress + == + && + assert + b label56 +label4: + callsub label57 + return +label3: + intc_1 // 0 + return +label2: + bytec 16 // "Program" + txn ApprovalProgram + concat + sha512_256 + bytec 7 // "validUpdateApproveHash" + app_global_get + == + assert + txn ClearStateProgram + len + pushint 4 + == + txn ClearStateProgram + extract 1 3 + pushbytes 0x810143 // 0x810143 + == + && + assert + intc_0 // 1 + return +label1: + bytec 6 // "MessageFee" + intc_1 // 0 + app_global_put + bytec 8 // "vphash" + bytec_0 // "" + app_global_put + bytec_3 // "currentGuardianSetIndex" + intc_1 // 0 + app_global_put + bytec 7 // "validUpdateApproveHash" + bytec_0 // "" + app_global_put + intc_0 // 1 + return +label59: + itob + extract 7 1 + retsub +label78: + store 51 + intc_1 // 0 + store 52 +label60: + load 52 + pushint 15 + < + bz label58 + load 51 + load 52 + callsub label59 + intc_2 // 127 + bzero + app_local_put + load 52 + intc_0 // 1 + + + store 52 + b label60 +label58: + retsub +label28: + store 29 + load 29 + intc_2 // 127 + / + callsub label59 + app_local_get + load 29 + intc_2 // 127 + % + getbyte + retsub +label79: + store 60 + store 59 + store 58 + load 58 + load 59 + intc_2 // 127 + / + callsub label59 + load 58 + load 59 + intc_2 // 127 + / + callsub label59 + app_local_get + load 59 + intc_2 // 127 + % + load 60 + setbyte + app_local_put + retsub +label29: + store 32 + store 31 + store 30 + bytec_0 // "" + store 34 + load 31 + intc_2 // 127 + / + store 33 +label64: + load 33 + load 32 + intc_2 // 127 + / + <= + bz label61 + load 33 + load 31 + intc_2 // 127 + / + == + bnz label62 + intc_1 // 0 +label66: + store 35 + load 33 + load 32 + intc_2 // 127 + / + == + bnz label63 + intc_2 // 127 +label65: + store 36 + load 34 + load 30 + load 33 + callsub label59 + app_local_get + load 35 + load 36 + substring3 + concat + store 34 + load 33 + intc_0 // 1 + + + store 33 + b label64 +label63: + load 32 + intc_2 // 127 + % + b label65 +label62: + load 31 + intc_2 // 127 + % + b label66 +label61: + load 34 + retsub +label23: + store 37 + bytec 17 // "meta" + load 37 + app_local_put + retsub +label27: + store 38 + bytec 17 // "meta" + app_local_get + load 38 + == + pushint 145 + && + assert + retsub +label21: + store 41 + store 40 + store 39 + intc_1 // 0 + store 45 + load 40 + intc_2 // 127 + / + store 42 +label71: + load 42 + load 40 + load 41 + len + + + intc_2 // 127 + / + <= + bz label67 + load 42 + load 40 + intc_2 // 127 + / + == + bnz label68 + intc_1 // 0 +label74: + store 43 + load 42 + load 40 + load 41 + len + + + intc_2 // 127 + / + == + bnz label69 + intc_2 // 127 +label73: + store 44 + load 39 + load 42 + callsub label59 + load 44 + intc_2 // 127 + != + load 43 + intc_1 // 0 + != + || + bnz label70 + intc_2 // 127 + store 46 + load 41 + load 45 + intc_2 // 127 + extract3 +label72: + app_local_put + load 45 + load 46 + + + store 45 + load 42 + intc_0 // 1 + + + store 42 + b label71 +label70: + load 44 + load 43 + - + store 46 + load 39 + load 42 + callsub label59 + app_local_get + intc_1 // 0 + load 43 + substring3 + load 41 + load 45 + load 46 + extract3 + concat + load 39 + load 42 + callsub label59 + app_local_get + load 44 + intc_2 // 127 + substring3 + concat + b label72 +label69: + load 40 + load 41 + len + + + intc_2 // 127 + % + b label73 +label68: + load 40 + intc_2 // 127 + % + b label74 +label67: + load 45 + retsub +label77: + store 50 + store 49 + load 50 + load 49 + intc 6 // 128 + >= + bnz label75 + load 49 + intc 7 // 255 + & + itob + extract 7 1 + b label76 +label75: + load 49 + pushint 7 + shr + load 49 + intc 7 // 255 + & + intc 6 // 128 + | + itob + extract 7 1 + load 49 + load 50 + uncover 3 + uncover 3 + callsub label77 + cover 2 + store 50 + store 49 +label76: + concat + retsub +label19: + store 48 + store 47 + bytec 16 // "Program" + pushbytes 0x0620010181 // 0x0620010181 + concat + load 47 + bytec_0 // "" + callsub label77 + concat + pushbytes 0x4880 // 0x4880 + concat + load 48 + len + bytec_0 // "" + callsub label77 + concat + load 48 + concat + pushbytes 0x483110810612443119221244311881 // 0x483110810612443119221244311881 + concat + global CurrentApplicationID // id=842125965 + bytec_0 // "" + callsub label77 + concat + pushbytes 0x1244312080 // 0x1244312080 + concat + global CurrentApplicationAddress + len + bytec_0 // "" + callsub label77 + concat + global CurrentApplicationAddress + concat + pushbytes 0x124431018100124431093203124431153203124422 // 0x124431018100124431093203124431153203124422 + concat + sha512_256 + retsub +label57: + gtxn 0 TypeEnum + intc_0 // 1 + == + gtxn 0 Amount // 0.716149 + pushint 1002000 + == + && + gtxn 0 Receiver // UPVQHHD22VRIPYG4VY4URS6CKJJ27BYFMUQQBMN6W6SOB7MELNDGQQ6HCM + gtxn 1 Sender // QLSKYBVKSJRZUUDKGN7LET7X3NOAFZ3EI2N7UDZMQLQJOU6DCHXZP6KXCE + == + && + gtxn 1 TypeEnum + pushint 6 + == + && + gtxn 1 OnCompletion + intc_0 // 1 + == + && + gtxn 1 ApplicationID // id=842125965 + global CurrentApplicationID // id=842125965 + == + && + gtxn 1 RekeyTo // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ + global CurrentApplicationAddress + == + && + gtxn 1 NumAppArgs // index=0 + intc_1 // 0 + == + && + assert + intc_1 // 0 + callsub label78 + intc_0 // 1 + retsub +label12: + txna ApplicationArgs 1 + extract 0 1 + btoi + intc_0 // 1 + == + assert + txna ApplicationArgs 1 + extract 5 1 + btoi + pushint 66 + * + pushint 14 + + + store 53 + txna ApplicationArgs 1 + load 53 + pushint 34 + extract3 + store 54 + txna ApplicationArgs 1 + load 53 + pushint 34 + + + pushint 8 + extract3 + btoi + store 55 + load 55 + pushint 15240 + / + store 57 + txna Accounts 1 + load 57 + load 54 + callsub label19 + == + assert + load 55 + pushint 8 + / + pushint 1905 + % + store 57 + intc_0 // 1 + load 57 + callsub label28 + store 56 + load 56 + load 55 + pushint 8 + % + getbit + intc_1 // 0 + == + assert + intc_0 // 1 + load 57 + load 56 + load 55 + pushint 8 + % + intc_0 // 1 + setbit + callsub label79 + intc_0 // 1 + pushbytes 0x6475706c6963617465 // "duplicate" + callsub label23 + retsub diff --git a/tests/test_detectors_using_pyteal.py b/tests/test_detectors_using_pyteal.py new file mode 100644 index 0000000..03040c9 --- /dev/null +++ b/tests/test_detectors_using_pyteal.py @@ -0,0 +1,49 @@ +# type: ignore[unreachable] +import sys +from typing import Tuple, List, Type + +import pytest + +from tealer.detectors.abstract_detector import AbstractDetector +from tealer.teal.parse_teal import parse_teal + +if not sys.version_info >= (3, 10): + pytest.skip(reason="PyTeal based tests require python >= 3.10", allow_module_level=True) + +# Place import statements after the version check +from tests.detectors.router_with_assembled_constants import ( # pylint: disable=wrong-import-position + router_with_assembled_constants, +) + +TESTS: List[Tuple[str, Type[AbstractDetector], List[List[int]]]] = [ + *router_with_assembled_constants, +] + + +@pytest.mark.parametrize("test", TESTS) # type: ignore +def test_detectors_using_pyteal(test: Tuple[str, Type[AbstractDetector], List[List[int]]]) -> None: + code, detector, expected_paths = test + teal = parse_teal(code.strip()) + teal.register_detector(detector) + result = teal.run_detectors()[0] + for bi in teal.bbs: + print( + bi, + bi.idx, + bi.transaction_context.transaction_types, + bi.transaction_context.group_indices, + ) + print( + bi.transaction_context.gtxn_context(0).transaction_types, + bi.transaction_context.group_indices, + ) + print( + bi.transaction_context.gtxn_context(1).transaction_types, + bi.transaction_context.group_indices, + ) + + assert len(result.paths) == len(expected_paths) + for path, expected_path in zip(result.paths, expected_paths): + assert len(path) == len(expected_path) + for bi, expected_idx in zip(path, expected_path): + assert bi.idx == expected_idx diff --git a/tests/test_parsing.py b/tests/test_parsing.py index 8760b65..ebe96e5 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -1,11 +1,18 @@ from typing import Type, Tuple +import base64 import pytest from tealer.teal.instructions import instructions +from tealer.teal.instructions.instructions import ( + IntcInstruction, + BytecInstruction, +) from tealer.teal.instructions import transaction_field from tealer.teal.instructions.parse_instruction import parse_line, ParseError from tealer.teal.parse_teal import parse_teal +from tealer.utils.analyses import is_int_push_ins, is_byte_push_ins + TARGETS = [ "tests/parsing/teal1-instructions.teal", @@ -314,3 +321,117 @@ def test_cost_values() -> None: for ins in teal.instructions: print("DSDF", ins, ins.cost) assert ins.cost == 0 + + +INTCBLOCK_TESTS = [ + "tests/parsing/intcblock_1.teal", + "tests/parsing/intcblock_2.teal", + "tests/parsing/intcblock_3.teal", +] + + +@pytest.mark.parametrize("test", INTCBLOCK_TESTS) +def test_intc_bytec(test: str) -> None: + with open(test, encoding="utf-8") as f: + teal = parse_teal(f.read()) + + for ins in teal.instructions: + if isinstance(ins, IntcInstruction): + is_known, value = is_int_push_ins(ins) + assert is_known + assert value == int(ins.comment[2:].strip()) + + if isinstance(ins, BytecInstruction): + is_known, value = is_byte_push_ins(ins) + assert is_known + expected_value = ins.comment[2:].strip() + if expected_value.startswith('"'): + expected_value = "0x" + expected_value[1:-1].encode().hex() + elif expected_value.startswith("addr"): + s = expected_value.strip("addr ").strip() + expected_value = ( + "0x" + base64.b32decode(s + "=" * (-len(s) % 8))[:-4].hex() + ) # 4-byte checksum + assert value == expected_value + + +INTCBLOCK_FALSE_TEST_1 = """ +#pragma version 7 +intcblock 0x00 0x01 0x02 0x03 0x04 0x05 0x06 +intcblock 0x07 0x08 0x09 0x10 0x11 0x12 0x13 +intc0 +intc1 +intc2 +intc3 +intc 4 +return +""" + +INTCBLOCK_FALSE_TEST_2 = """ +#pragma version 7 +int 0 +int 1 ++ +b next +next: +intcblock 0x00 0x01 0x02 0x03 0x04 0x05 0x06 +intc0 +intc1 +intc2 +intc3 +intc 4 +return +""" + +INTCBLOCK_FALSE_TEST_3 = """ +#pragma version 7 +intc0 +intc1 +return +""" + +# Tealer can determine that this is invalid code in this case. But currently does +# not do that to be uniform for all cases. +INTCBLOCK_FALSE_TEST_4 = """ +#pragma version 7 +intcblock 0x00 0x01 0x02 0x03 +intc 7 // Invalid index +""" + +# Tealer cannot determing in this case. +INTCBLOCK_FALSE_TEST_5 = """ +#pragma version 7 +intcblock 0x00 0x01 0x02 0x03 +txn RekeyTo +global ZeroAddress +== +bnz branch +b sub +branch: + intcblock 0x04 0x05 0x06 0x07 0x08 0x09 0xa +sub: + intc 9 // Invalid index +""" + +INTCBLOCK_FALSE_TESTS = [ + INTCBLOCK_FALSE_TEST_1, + INTCBLOCK_FALSE_TEST_2, + INTCBLOCK_FALSE_TEST_3, + INTCBLOCK_FALSE_TEST_4, + INTCBLOCK_FALSE_TEST_5, +] + + +@pytest.mark.parametrize("test", INTCBLOCK_FALSE_TESTS) +def test_intc_bytec_false(test: str) -> None: + teal = parse_teal(test) + for ins in teal.instructions: + if isinstance(ins, IntcInstruction): + is_known, _ = is_int_push_ins(ins) + assert not is_known + + teal = parse_teal(test.replace("intc", "bytec")) + for ins in teal.instructions: + if isinstance(ins, BytecInstruction): + is_known, _ = is_byte_push_ins(ins) + assert not is_known From fc9731986fde65e6070fb7f52f084d0b94233c22 Mon Sep 17 00:00:00 2001 From: Vara Prasad Bandaru Date: Tue, 10 Jan 2023 10:22:01 +0530 Subject: [PATCH 2/4] Fix Mypy errors --- tests/test_parsing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_parsing.py b/tests/test_parsing.py index ebe96e5..f8c9772 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -330,7 +330,7 @@ def test_cost_values() -> None: ] -@pytest.mark.parametrize("test", INTCBLOCK_TESTS) +@pytest.mark.parametrize("test", INTCBLOCK_TESTS) # type: ignore def test_intc_bytec(test: str) -> None: with open(test, encoding="utf-8") as f: teal = parse_teal(f.read()) @@ -422,7 +422,7 @@ def test_intc_bytec(test: str) -> None: ] -@pytest.mark.parametrize("test", INTCBLOCK_FALSE_TESTS) +@pytest.mark.parametrize("test", INTCBLOCK_FALSE_TESTS) # type: ignore def test_intc_bytec_false(test: str) -> None: teal = parse_teal(test) for ins in teal.instructions: From 21bc3473615f92c5bbdb7ffd1093996ced7a0dac Mon Sep 17 00:00:00 2001 From: Vara Prasad Bandaru Date: Tue, 10 Jan 2023 10:31:02 +0530 Subject: [PATCH 3/4] Use txn type information for CanCloseAccount and CanCloseAsset detectors --- tealer/detectors/can_close_account.py | 8 +- tealer/detectors/can_close_asset.py | 7 +- tests/detectors/can_delete.py | 17 ++- tests/detectors/can_update.py | 23 +++- tests/detectors/pyteal_can_close.py | 165 ++++++++++++++++++++++++++ tests/test_detectors_using_pyteal.py | 5 + 6 files changed, 216 insertions(+), 9 deletions(-) create mode 100644 tests/detectors/pyteal_can_close.py diff --git a/tealer/detectors/can_close_account.py b/tealer/detectors/can_close_account.py index 1e65d72..cc5c04a 100644 --- a/tealer/detectors/can_close_account.py +++ b/tealer/detectors/can_close_account.py @@ -9,7 +9,7 @@ ) from tealer.teal.basic_blocks import BasicBlock from tealer.detectors.utils import detect_missing_tx_field_validations - +from tealer.utils.teal_enums import TealerTransactionType if TYPE_CHECKING: from tealer.utils.output import SupportedOutput @@ -74,7 +74,11 @@ def detect(self) -> "SupportedOutput": def checks_field(block_ctx: "BlockTransactionContext") -> bool: # return False if CloseRemainderTo field can have any address. # return True if CloseRemainderTo should have some address or zero address - return not block_ctx.closeto.any_addr + # CloseRemainderTo field can only be set for Payment type transactions. + return not ( + block_ctx.closeto.any_addr + and TealerTransactionType.Pay in block_ctx.transaction_types + ) paths_without_check: List[List[BasicBlock]] = detect_missing_tx_field_validations( self.teal.bbs[0], checks_field diff --git a/tealer/detectors/can_close_asset.py b/tealer/detectors/can_close_asset.py index 248a10f..46b14d6 100644 --- a/tealer/detectors/can_close_asset.py +++ b/tealer/detectors/can_close_asset.py @@ -9,6 +9,7 @@ ) from tealer.teal.basic_blocks import BasicBlock from tealer.detectors.utils import detect_missing_tx_field_validations +from tealer.utils.teal_enums import TealerTransactionType if TYPE_CHECKING: from tealer.utils.output import SupportedOutput @@ -69,7 +70,11 @@ def detect(self) -> "SupportedOutput": def checks_field(block_ctx: "BlockTransactionContext") -> bool: # return False if AssetCloseTo field can have any address. # return True if AssetCloseTo should have some address or zero address - return not block_ctx.assetcloseto.any_addr + # AssetCloseTo field can only be set for Asset Transafer type transactions. + return not ( + block_ctx.assetcloseto.any_addr + and TealerTransactionType.Axfer in block_ctx.transaction_types + ) paths_without_check: List[List[BasicBlock]] = detect_missing_tx_field_validations( self.teal.bbs[0], checks_field diff --git a/tests/detectors/can_delete.py b/tests/detectors/can_delete.py index 00147f0..769a1c0 100644 --- a/tests/detectors/can_delete.py +++ b/tests/detectors/can_delete.py @@ -1,8 +1,9 @@ -from typing import List +from typing import List, Tuple, Type from tealer.teal.instructions import instructions from tealer.teal.instructions import transaction_field -from tealer.detectors.all_detectors import CanDelete +from tealer.detectors.abstract_detector import AbstractDetector +from tealer.detectors.all_detectors import CanDelete, CanCloseAccount, CanCloseAsset from tests.utils import construct_cfg @@ -390,8 +391,18 @@ [0, 2, 7, 8, 9], ] -new_can_delete_tests = [ +new_can_delete_tests: List[Tuple[str, Type[AbstractDetector], List[List[int]]]] = [ (CAN_DELETE_GROUP_INDEX_0, CanDelete, CAN_DELETE_GROUP_INDEX_0_VULNERABLE_PATHS), (CAN_DELETE_GROUP_INDEX_1, CanDelete, CAN_DELETE_GROUP_INDEX_1_VULNERABLE_PATHS), (CAN_DELETE_GROUP_INDEX_2, CanDelete, CAN_DELETE_GROUP_INDEX_2_VULNERABLE_PATHS), + (CAN_DELETE, CanCloseAccount, []), + (CAN_DELETE_LOOP, CanCloseAccount, []), + (CAN_DELETE_GROUP_INDEX_0, CanCloseAccount, []), + (CAN_DELETE_GROUP_INDEX_1, CanCloseAccount, []), + (CAN_DELETE_GROUP_INDEX_2, CanCloseAccount, []), + (CAN_DELETE, CanCloseAsset, []), + (CAN_DELETE_LOOP, CanCloseAsset, []), + (CAN_DELETE_GROUP_INDEX_0, CanCloseAsset, []), + (CAN_DELETE_GROUP_INDEX_1, CanCloseAsset, []), + (CAN_DELETE_GROUP_INDEX_2, CanCloseAsset, []), ] diff --git a/tests/detectors/can_update.py b/tests/detectors/can_update.py index 2073e90..ff3c488 100644 --- a/tests/detectors/can_update.py +++ b/tests/detectors/can_update.py @@ -1,8 +1,9 @@ -from typing import List +from typing import List, Tuple, Type from tealer.teal.instructions import instructions from tealer.teal.instructions import transaction_field -from tealer.detectors.all_detectors import CanUpdate +from tealer.detectors.abstract_detector import AbstractDetector +from tealer.detectors.all_detectors import CanUpdate, CanCloseAccount, CanCloseAsset from tests.utils import construct_cfg @@ -433,9 +434,25 @@ CAN_UPDATE_GROUP_INDEX_INTC_0_VULNERABLE_PATHS: List[List[int]] = [] -new_can_update_tests = [ +new_can_update_tests: List[Tuple[str, Type[AbstractDetector], List[List[int]]]] = [ (CAN_UPDATE_GROUP_INDEX_0, CanUpdate, CAN_UPDATE_GROUP_INDEX_0_VULNERABLE_PATHS), (CAN_UPDATE_GROUP_INDEX_1, CanUpdate, CAN_UPDATE_GROUP_INDEX_1_VULNERABLE_PATHS), (CAN_UPDATE_GROUP_INDEX_2, CanUpdate, CAN_UPDATE_GROUP_INDEX_2_VULNERABLE_PATHS), (CAN_UPDATE_GROUP_INDEX_INTC_0, CanUpdate, CAN_UPDATE_GROUP_INDEX_INTC_0_VULNERABLE_PATHS), + ( + CAN_UPDATE, + CanCloseAccount, + [], + ), # Applications are not vulnerable to CanCloseAccount and CanCloseAsset + (CAN_UPDATE_LOOP, CanCloseAccount, []), + (CAN_UPDATE_GROUP_INDEX_0, CanCloseAccount, []), + (CAN_UPDATE_GROUP_INDEX_1, CanCloseAccount, []), + (CAN_UPDATE_GROUP_INDEX_2, CanCloseAccount, []), + (CAN_UPDATE_GROUP_INDEX_INTC_0, CanCloseAccount, []), + (CAN_UPDATE, CanCloseAsset, []), + (CAN_UPDATE_LOOP, CanCloseAsset, []), + (CAN_UPDATE_GROUP_INDEX_0, CanCloseAsset, []), + (CAN_UPDATE_GROUP_INDEX_1, CanCloseAsset, []), + (CAN_UPDATE_GROUP_INDEX_2, CanCloseAsset, []), + (CAN_UPDATE_GROUP_INDEX_INTC_0, CanCloseAsset, []), ] diff --git a/tests/detectors/pyteal_can_close.py b/tests/detectors/pyteal_can_close.py new file mode 100644 index 0000000..def1a2c --- /dev/null +++ b/tests/detectors/pyteal_can_close.py @@ -0,0 +1,165 @@ +# pylint: skip-file +# mypy: ignore-errors +from pyteal import * # pylint: disable=wildcard-import, unused-wildcard-import + +from pyteal import * +from typing import Literal + +from tealer.detectors.all_detectors import CanUpdate, CanDelete, CanCloseAsset, CanCloseAccount + +router = Router( + name="Example", + bare_calls=BareCallActions(), +) + + +@router.method(no_op=CallConfig.ALL) +def echo(input: abi.Uint64, *, output: abi.Uint64) -> Expr: + """ + Method config validations Teal pattern: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert // Assert(NoOp, CALL) + """ + return output.set(input.get()) + + +pragma(compiler_version="0.20.1") +application_approval_program, _, _ = router.compile_program( + version=7, + assemble_constants=True, # use intcblock, bytecblock + # optimize=OptimizeOptions(scratch_slots=True), +) + + +@Subroutine(TealType.none) +def process_txn() -> Expr: + return Pop(Bytes("ExecuteTransaction")) + + +def axfer_approval_program(): + @Subroutine(TealType.none) + def validate_txn() -> Expr: + return Seq( + [ + Assert(Global.group_size() == Int(1)), + Assert(Txn.fee() <= Global.min_txn_fee()), + Assert(Txn.type_enum() == TxnType.AssetTransfer), + Assert(Txn.asset_close_to() == Global.zero_address()), + ] + ) + + return Seq( + [ + validate_txn(), + process_txn(), + Return(Int(1)), + ] + ) + + +axfer_approval_program_teal = compileTeal(axfer_approval_program(), mode=Mode.Signature, version=7) + + +def payment_approval_program(): + @Subroutine(TealType.none) + def validate_txn() -> Expr: + return Seq( + [ + Assert(Global.group_size() == Int(1)), + Assert(Txn.fee() <= Global.min_txn_fee()), + Assert(Txn.type_enum() == TxnType.Payment), + Assert(Txn.close_remainder_to() == Global.zero_address()), + ] + ) + + return Seq( + [ + validate_txn(), + process_txn(), + Return(Int(1)), + ] + ) + + +payment_approval_program_teal = compileTeal( + payment_approval_program(), mode=Mode.Signature, version=7 +) + + +def axfer_payment_approval_program(): + return ( + If(Arg(Int(0)) == Bytes("Payment In Algo")) + .Then( + payment_approval_program(), + ) + .Else( + axfer_approval_program(), + ) + ) + + +axfer_payment_approval_program_teal = compileTeal( + axfer_payment_approval_program(), mode=Mode.Signature, version=7 +) + + +def different_group_sizes_approval_program(): + group_size_3 = Seq( + [ + Assert(Global.group_size() == Int(3)), + Assert(Gtxn[0].fee() <= Global.min_txn_fee()), + Assert(Gtxn[0].type_enum() == TxnType.Payment), + Assert(Gtxn[0].close_remainder_to() == Global.zero_address()), + Assert(Gtxn[1].fee() <= Global.min_txn_fee()), + Assert(Gtxn[1].type_enum() == TxnType.KeyRegistration), + Assert(Gtxn[2].fee() <= Global.min_txn_fee()), + Assert(Gtxn[2].type_enum() == TxnType.AssetConfig), + Assert(Gtxn[2].close_remainder_to() == Global.zero_address()), + Return(Int(1)), + ] + ) + + group_size_2 = Seq( + [ + Assert(Global.group_size() == Int(2)), + Assert(Gtxn[0].fee() <= Global.min_txn_fee()), + Assert(Gtxn[0].type_enum() == TxnType.AssetTransfer), + Assert(Gtxn[0].asset_close_to() == Txn.sender()), + Assert(Gtxn[1].fee() <= Global.min_txn_fee()), + Assert(Gtxn[1].type_enum() == TxnType.AssetFreeze), + Return(Int(1)), + ] + ) + + return ( + If(Arg(Int(0)) == Bytes("First Operation")) + .Then( + group_size_2, + ) + .Else(group_size_3) + ) + + +different_group_sizes_approval_program_teal = compileTeal( + different_group_sizes_approval_program(), mode=Mode.Signature, version=7 +) + + +txn_type_based_tests = [ + (application_approval_program, CanCloseAccount, []), + (application_approval_program, CanCloseAsset, []), + (axfer_approval_program_teal, CanCloseAccount, []), + (axfer_approval_program_teal, CanCloseAsset, []), + (payment_approval_program_teal, CanCloseAccount, []), + (payment_approval_program_teal, CanCloseAsset, []), + (axfer_payment_approval_program_teal, CanCloseAccount, []), + (axfer_payment_approval_program_teal, CanCloseAsset, []), + (different_group_sizes_approval_program_teal, CanCloseAccount, []), + (different_group_sizes_approval_program_teal, CanCloseAsset, []), +] diff --git a/tests/test_detectors_using_pyteal.py b/tests/test_detectors_using_pyteal.py index 03040c9..bdd5fee 100644 --- a/tests/test_detectors_using_pyteal.py +++ b/tests/test_detectors_using_pyteal.py @@ -14,9 +14,14 @@ from tests.detectors.router_with_assembled_constants import ( # pylint: disable=wrong-import-position router_with_assembled_constants, ) +from tests.detectors.pyteal_can_close import ( # pylint: disable=wrong-import-position + txn_type_based_tests, +) + TESTS: List[Tuple[str, Type[AbstractDetector], List[List[int]]]] = [ *router_with_assembled_constants, + *txn_type_based_tests, ] From 0e08150f0712060170a37641f548fba4e5900e36 Mon Sep 17 00:00:00 2001 From: Vara Prasad Bandaru Date: Thu, 26 Jan 2023 16:55:29 +0530 Subject: [PATCH 4/4] Remove pyteal pragma from detector tests --- .gitignore | 1 + tests/detectors/pyteal_can_close.py | 2 +- tests/detectors/router_with_assembled_constants.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f3a663e..fed0f9d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build/ dist/ tealer.egg-info/ +__pycache__ diff --git a/tests/detectors/pyteal_can_close.py b/tests/detectors/pyteal_can_close.py index def1a2c..164d334 100644 --- a/tests/detectors/pyteal_can_close.py +++ b/tests/detectors/pyteal_can_close.py @@ -29,7 +29,7 @@ def echo(input: abi.Uint64, *, output: abi.Uint64) -> Expr: return output.set(input.get()) -pragma(compiler_version="0.20.1") +# pragma(compiler_version="0.22.0") application_approval_program, _, _ = router.compile_program( version=7, assemble_constants=True, # use intcblock, bytecblock diff --git a/tests/detectors/router_with_assembled_constants.py b/tests/detectors/router_with_assembled_constants.py index f46d5fe..c000aa9 100644 --- a/tests/detectors/router_with_assembled_constants.py +++ b/tests/detectors/router_with_assembled_constants.py @@ -88,7 +88,7 @@ def some(input: abi.Uint64) -> Expr: # PyTeal creates intcblock, bytecblock if assemble_constants = True # int NoOp, OptIn, ... are all replaced by intc_* instructions. -pragma(compiler_version="0.20.1") +# pragma(compiler_version="0.22.0") approval_program, clear_state_program, contract = router.compile_program( version=7, assemble_constants=True, # use intcblock, bytecblock