Пример #1
0
def uint_decode(
    size: int,
    uint_var: ScratchVar,
    encoded: Expr,
    start_index: Optional[Expr],
    end_index: Optional[Expr],
    length: Optional[Expr],
) -> Expr:
    if size > 64:
        raise NotImplementedError(
            "Uint operations have not yet been implemented for bit sizes larger than 64"
        )

    if size == 64:
        if start_index is None:
            if end_index is None and length is None:
                return uint_var.store(Btoi(encoded))
            start_index = Int(0)
        return uint_var.store(ExtractUint64(encoded, start_index))

    if start_index is None:
        start_index = Int(0)

    if size == 8:
        return uint_var.store(GetByte(encoded, start_index))
    if size == 16:
        return uint_var.store(ExtractUint16(encoded, start_index))
    if size == 32:
        return uint_var.store(ExtractUint32(encoded, start_index))

    raise ValueError("Unsupported uint size: {}".format(size))
Пример #2
0
def substring_for_decoding(
    encoded: Expr,
    *,
    start_index: Expr = None,
    end_index: Expr = None,
    length: Expr = None,
) -> Expr:
    """A helper function for getting the substring to decode according to the rules of BaseType.decode."""
    if length is not None and end_index is not None:
        raise TealInputError("length and end_index are mutually exclusive arguments")

    if start_index is not None:
        if length is not None:
            # substring from start_index to start_index + length
            return Extract(encoded, start_index, length)

        if end_index is not None:
            # substring from start_index to end_index
            return Substring(encoded, start_index, end_index)

        # substring from start_index to end of string
        return Suffix(encoded, start_index)

    if length is not None:
        # substring from 0 to length
        return Extract(encoded, Int(0), length)

    if end_index is not None:
        # substring from 0 to end_index
        return Substring(encoded, Int(0), end_index)

    # the entire string
    return encoded
Пример #3
0
 def decode(self,
            encoded: Expr,
            *,
            start_index: Expr = None,
            end_index: Expr = None,
            length: Expr = None) -> Expr:
     if start_index is None:
         start_index = Int(0)
     return self.decode_bit(encoded, start_index * Int(NUM_BITS_IN_BYTE))
Пример #4
0
    def SetField(cls, field: TxnField, value: Expr | list[Expr]) -> Expr:
        """Set a field of the current inner transaction.

        :any:`InnerTxnBuilder.Begin` must be called before setting any fields on an inner
        transaction.

        Note: For non-array field (e.g., note), setting it twice will overwrite the original value.
              While for array field (e.g., accounts), setting it multiple times will append the values.
              It is also possible to pass the entire array field if desired (e.g., Txn.accounts) to pass all the references.

        Requires program version 5 or higher. This operation is only permitted in application mode.

        Args:
            field: The field to set on the inner transaction.
            value: The value to that the field should take. This must evaluate to a type that is
                compatible with the field being set.
        """
        if not field.is_array:
            if type(value) is list or isinstance(value, TxnArray):
                raise TealInputError(
                    "inner transaction set field {} does not support array value".format(
                        field
                    )
                )
            return InnerTxnFieldExpr(field, cast(Expr, value))
        else:
            if type(value) is not list and not isinstance(value, TxnArray):
                raise TealInputError(
                    "inner transaction set array field {} with non-array value".format(
                        field
                    )
                )

            if type(value) is list:
                for valueIter in value:
                    if not isinstance(valueIter, Expr):
                        raise TealInputError(
                            "inner transaction set array field {} with non PyTeal expression array element {}".format(
                                field, valueIter
                            )
                        )

                return Seq(
                    *[
                        InnerTxnFieldExpr(field, cast(Expr, valueIter))
                        for valueIter in value
                    ]
                )
            else:
                arr = cast(TxnArray, value)
                return For(
                    (i := ScratchVar()).store(Int(0)),
                    i.load() < arr.length(),
                    i.store(i.load() + Int(1)),
                ).Do(InnerTxnFieldExpr(field, arr[i.load()]))
Пример #5
0
 def approval_condition_under_config(self) -> Expr | int:
     match self:
         case CallConfig.NEVER:
             return 0
         case CallConfig.CALL:
             return Txn.application_id() != Int(0)
         case CallConfig.CREATE:
             return Txn.application_id() == Int(0)
         case CallConfig.ALL:
             return 1
         case _:
             raise TealInternalError(f"unexpected CallConfig {self}")
Пример #6
0
    def maximize_budget(self, fee: Expr) -> Expr:
        """Maximize the available opcode budget without spending more than the given fee.

        Note: the available budget just prior to calling maximize_budget() must be
        high enough to execute the budget increase code. The exact budget required
        depends on the provided fee expression, but a budget of ~25 should be
        sufficient for most use cases. If lack of budget is an issue then consider
        moving the call to maximize_budget() earlier in the pyteal program."""
        require_type(fee, TealType.uint64)

        i = ScratchVar(TealType.uint64)
        n = fee / Global.min_txn_fee()
        return For(i.store(Int(0)),
                   i.load() < n,
                   i.store(i.load() + Int(1))).Do(self._construct_itxn())
Пример #7
0
    def length(self) -> Expr:
        """Get the element number of this ABI static array.

        Returns:
            A PyTeal expression that represents the static array length.
        """
        return Int(self.type_spec().length_static())
Пример #8
0
def _store_encoded_expr_byte_string_into_var(value: Expr, location: ScratchVar) -> Expr:
    return Seq(
        location.store(value),
        location.store(
            Concat(Suffix(Itob(Len(location.load())), Int(6)), location.load())
        ),
    )
Пример #9
0
    def get(self) -> Expr:
        """Return the value held by this String as a PyTeal expression.

        The expression will have the type TealType.bytes.
        """
        return Suffix(
            self.stored_value.load(), Int(Uint16TypeSpec().byte_length_static())
        )
Пример #10
0
    def get(self) -> Expr:
        """Get the byte encoding of this DynamicBytes.

        Dropping the uint16 encoding prefix for dynamic array length.

        Returns:
            A Pyteal expression that loads byte encoding of this DynamicBytes, and drop the first uint16 DynamicArray length encoding.
        """
        return Suffix(self.stored_value.load(), Int(2))
Пример #11
0
def uint_encode(size: int, uint_var: Expr | ScratchVar) -> Expr:

    if isinstance(uint_var, ScratchVar):
        uint_var = uint_var.load()

    if size > 64:
        raise NotImplementedError(
            "Uint operations have not yet been implemented for bit sizes larger than 64"
        )

    if size == 8:
        return SetByte(Bytes(b"\x00"), Int(0), uint_var)
    if size == 16:
        return Suffix(Itob(uint_var), Int(6))
    if size == 32:
        return Suffix(Itob(uint_var), Int(4))
    if size == 64:
        return Itob(uint_var)

    raise ValueError("Unsupported uint size: {}".format(size))
Пример #12
0
    def __init__(
        self,
        name: str,
        bare_calls: BareCallActions = None,
        descr: str = None,
    ) -> None:
        """
        Args:
            name: the name of the smart contract, used in the JSON object.
            bare_calls: the bare app call registered for each on_completion.
            descr: a description of the smart contract, used in the JSON object.
        """

        self.name: str = name
        self.descr = descr

        self.approval_ast = ASTBuilder()
        self.clear_state_ast = ASTBuilder()

        self.methods: list[sdk_abi.Method] = []
        self.method_sig_to_selector: dict[str, bytes] = dict()
        self.method_selector_to_sig: dict[bytes, str] = dict()

        if bare_calls and not bare_calls.is_empty():
            bare_call_approval = bare_calls.approval_construction()
            if bare_call_approval:
                self.approval_ast.conditions_n_branches.append(
                    CondNode(
                        Txn.application_args.length() == Int(0),
                        cast(Expr, bare_call_approval),
                    )
                )
            bare_call_clear = bare_calls.clear_state_construction()
            if bare_call_clear:
                self.clear_state_ast.conditions_n_branches.append(
                    CondNode(
                        Txn.application_args.length() == Int(0),
                        cast(Expr, bare_call_clear),
                    )
                )
Пример #13
0
 def _set_index(
     self, value: Union[int, Expr, "Transaction", ComputedValue["Transaction"]]
 ) -> Expr:
     match value:
         case ComputedValue():
             return self._set_with_computed_type(value)
         case BaseType():
             return self.stored_value.store(self.stored_value.load())
         case int():
             return self.stored_value.store(Int(value))
         case Expr():
             return self.stored_value.store(value)
         case _:
             raise TealInputError(f"Cant store a {type(value)} in a Transaction")
Пример #14
0
    def __teal__(self, options: "CompileOptions"):
        if not isinstance(self.startArg, Int) or not isinstance(
                self.endArg, Int):
            return TernaryExpr(
                Op.substring3,
                (TealType.bytes, TealType.uint64, TealType.uint64),
                TealType.bytes,
                self.stringArg,
                self.startArg,
                self.endArg,
            ).__teal__(options)

        op = self.__get_op(options)

        verifyProgramVersion(
            op.min_version,
            options.version,
            "Program version too low to use op {}".format(op),
        )

        start, end = cast(Int, self.startArg).value, cast(Int,
                                                          self.endArg).value
        if op == Op.extract:
            length = end - start
            return TealBlock.FromOp(
                options,
                TealOp(self, op, self.startArg.value, length),
                self.stringArg,
            )
        elif op == Op.extract3:
            length = end - start
            return TealBlock.FromOp(
                options,
                TealOp(self, op),
                self.stringArg,
                self.startArg,
                Int(length),
            )
        elif op == Op.substring:
            return TealBlock.FromOp(options, TealOp(self, op, start, end),
                                    self.stringArg)
        elif op == Op.substring3:
            return TealBlock.FromOp(
                options,
                TealOp(self, op),
                self.stringArg,
                self.startArg,
                self.endArg,
            )
Пример #15
0
def uint_set(size: int, uint_var: ScratchVar, value: Union[int, Expr, "Uint"]) -> Expr:
    if size > 64:
        raise NotImplementedError(
            "Uint operations have not yet been implemented for bit sizes larger than 64"
        )

    checked = False
    if type(value) is int:
        if value >= 2**size:
            raise TealInputError("Value exceeds uint{} maximum: {}".format(size, value))
        value = Int(value)
        checked = True

    if isinstance(value, Uint):
        value = value.get()
        checked = True

    if checked or size == 64:
        return uint_var.store(cast(Expr, value))

    return Seq(
        uint_var.store(cast(Expr, value)),
        Assert(uint_var.load() < Int(2**size)),
    )
Пример #16
0
def _encode_bool_sequence(values: Sequence[Bool]) -> Expr:
    """Encoding a sequences of boolean values into a byte string.

    Args:
        values: The values to encode. Each must be an instance of Bool.

    Returns:
        An expression which creates an encoded byte string with the input boolean values.
    """
    length = _bool_sequence_length(len(values))
    expr: Expr = Bytes(b"\x00" * length)

    for i, value in enumerate(values):
        expr = SetBit(expr, Int(i), value.get())

    return expr
Пример #17
0
    def ensure_budget(self, required_budget: Expr) -> Expr:
        """Ensure that the budget will be at least the required_budget.

        Note: the available budget just prior to calling ensure_budget() must be
        high enough to execute the budget increase code. The exact budget required
        depends on the provided required_budget expression, but a budget of ~20
        should be sufficient for most use cases. If lack of budget is an issue then
        consider moving the call to ensure_budget() earlier in the pyteal program."""
        require_type(required_budget, TealType.uint64)

        # A budget buffer is necessary to deal with an edge case of ensure_budget():
        #   if the current budget is equal to or only slightly higher than the
        #   required budget then it's possible for ensure_budget() to return with a
        #   current budget less than the required budget. The buffer prevents this
        #   from being the case.
        buffer = Int(10)
        buffered_budget = ScratchVar(TealType.uint64)
        return Seq(
            buffered_budget.store(required_budget + buffer),
            While(buffered_budget.load() > Global.opcode_budget()).Do(
                self._construct_itxn()),
        )
Пример #18
0
    def set(self, value: Union[bool, Expr, "Bool",
                               ComputedValue["Bool"]]) -> Expr:
        """Set the value of this Bool to the input value.

        The behavior of this method depends on the input argument type:

            * :code:`bool`: set the value to a Python boolean value.
            * :code:`Expr`: set the value to the result of a PyTeal expression, which must evaluate to a TealType.uint64. All values greater than 0 are considered true, while 0 is considered false.
            * :code:`Bool`: copy the value from another Bool.
            * :code:`ComputedValue[Bool]`: copy the value from a Bool produced by a ComputedValue.

        Args:
            value: The new value this Bool should take. This must follow the above constraints.

        Returns:
            An expression which stores the given value into this Bool.
        """
        if isinstance(value, ComputedValue):
            return self._set_with_computed_type(value)

        checked = False
        if type(value) is bool:
            value = Int(1 if value else 0)
            checked = True

        if isinstance(value, BaseType):
            if value.type_spec() != self.type_spec():
                raise TealInputError("Cannot set type bool to {}".format(
                    value.type_spec()))
            value = value.get()
            checked = True

        if checked:
            return self.stored_value.store(value)

        # Not(Not(value)) coerces all values greater than 0 to 1
        return self.stored_value.store(Not(Not(value)))
Пример #19
0
def _index_tuple(
    value_types: Sequence[TypeSpec], encoded: Expr, index: int, output: BaseType
) -> Expr:
    if not (0 <= index < len(value_types)):
        raise ValueError("Index outside of range")

    offset = 0
    ignoreNext = 0
    lastBoolStart = 0
    lastBoolLength = 0
    for i, typeBefore in enumerate(value_types[:index]):
        if ignoreNext > 0:
            ignoreNext -= 1
            continue

        if typeBefore == BoolTypeSpec():
            lastBoolStart = offset
            lastBoolLength = _consecutive_bool_type_spec_num(value_types, i)
            offset += _bool_sequence_length(lastBoolLength)
            ignoreNext = lastBoolLength - 1
            continue

        if typeBefore.is_dynamic():
            offset += 2
            continue

        offset += typeBefore.byte_length_static()

    valueType = value_types[index]
    if output.type_spec() != valueType:
        raise TypeError("Output type does not match value type")

    if type(output) is Bool:
        if ignoreNext > 0:
            # value is in the middle of a bool sequence
            bitOffsetInBoolSeq = lastBoolLength - ignoreNext
            bitOffsetInEncoded = lastBoolStart * NUM_BITS_IN_BYTE + bitOffsetInBoolSeq
        else:
            # value is the beginning of a bool sequence (or a single bool)
            bitOffsetInEncoded = offset * NUM_BITS_IN_BYTE
        return output.decode_bit(encoded, Int(bitOffsetInEncoded))

    if valueType.is_dynamic():
        hasNextDynamicValue = False
        nextDynamicValueOffset = offset + 2
        ignoreNext = 0
        for i, typeAfter in enumerate(value_types[index + 1 :], start=index + 1):
            if ignoreNext > 0:
                ignoreNext -= 1
                continue

            if type(typeAfter) is BoolTypeSpec:
                boolLength = _consecutive_bool_type_spec_num(value_types, i)
                nextDynamicValueOffset += _bool_sequence_length(boolLength)
                ignoreNext = boolLength - 1
                continue

            if typeAfter.is_dynamic():
                hasNextDynamicValue = True
                break

            nextDynamicValueOffset += typeAfter.byte_length_static()

        start_index = ExtractUint16(encoded, Int(offset))
        if not hasNextDynamicValue:
            # This is the final dynamic value, so decode the substring from start_index to the end of
            # encoded
            return output.decode(encoded, start_index=start_index)

        # There is a dynamic value after this one, and end_index is where its tail starts, so decode
        # the substring from start_index to end_index
        end_index = ExtractUint16(encoded, Int(nextDynamicValueOffset))
        return output.decode(encoded, start_index=start_index, end_index=end_index)

    start_index = Int(offset)
    length = Int(valueType.byte_length_static())

    if index + 1 == len(value_types):
        if offset == 0:
            # This is the first and only value in the tuple, so decode all of encoded
            return output.decode(encoded)
        # This is the last value in the tuple, so decode the substring from start_index to the end of
        # encoded
        return output.decode(encoded, start_index=start_index)

    if offset == 0:
        # This is the first value in the tuple, so decode the substring from 0 with length length
        return output.decode(encoded, length=length)

    # This is not the first or last value, so decode the substring from start_index with length length
    return output.decode(encoded, start_index=start_index, length=length)
Пример #20
0
    def wrap_handler(
        is_method_call: bool, handler: ABIReturnSubroutine | SubroutineFnWrapper | Expr
    ) -> Expr:
        """This is a helper function that handles transaction arguments passing in bare-app-call/abi-method handlers.

        If `is_method_call` is True, then it can only be `ABIReturnSubroutine`,
        otherwise:
            - both `ABIReturnSubroutine` and `Subroutine` takes 0 argument on the stack.
            - all three cases have none (or void) type.

        On ABI method case, if the ABI method has more than 15 args, this function manages to de-tuple
        the last (16-th) Txn app-arg into a list of ABI method arguments, and pass in to the ABI method.

        Args:
            is_method_call: a boolean value that specify if the handler is an ABI method.
            handler: an `ABIReturnSubroutine`, or `SubroutineFnWrapper` (for `Subroutine` case), or an `Expr`.
        Returns:
            Expr:
                - for bare-appcall it returns an expression that the handler takes no txn arg and Approve
                - for abi-method it returns the txn args correctly decomposed into ABI variables,
                  passed in ABIReturnSubroutine and logged, then approve.
        """
        if not is_method_call:
            match handler:
                case Expr():
                    if handler.type_of() != TealType.none:
                        raise TealInputError(
                            f"bare appcall handler should be TealType.none not {handler.type_of()}."
                        )
                    return handler if handler.has_return() else Seq(handler, Approve())
                case SubroutineFnWrapper():
                    if handler.type_of() != TealType.none:
                        raise TealInputError(
                            f"subroutine call should be returning TealType.none not {handler.type_of()}."
                        )
                    if handler.subroutine.argument_count() != 0:
                        raise TealInputError(
                            f"subroutine call should take 0 arg for bare-app call. "
                            f"this subroutine takes {handler.subroutine.argument_count()}."
                        )
                    return Seq(handler(), Approve())
                case ABIReturnSubroutine():
                    if handler.type_of() != "void":
                        raise TealInputError(
                            f"abi-returning subroutine call should be returning void not {handler.type_of()}."
                        )
                    if handler.subroutine.argument_count() != 0:
                        raise TealInputError(
                            f"abi-returning subroutine call should take 0 arg for bare-app call. "
                            f"this abi-returning subroutine takes {handler.subroutine.argument_count()}."
                        )
                    return Seq(cast(Expr, handler()), Approve())
                case _:
                    raise TealInputError(
                        "bare appcall can only accept: none type Expr, or Subroutine/ABIReturnSubroutine with none return and no arg"
                    )
        else:
            if not isinstance(handler, ABIReturnSubroutine):
                raise TealInputError(
                    f"method call should be only registering ABIReturnSubroutine, got {type(handler)}."
                )
            if not handler.is_abi_routable():
                raise TealInputError(
                    f"method call ABIReturnSubroutine is not routable "
                    f"got {handler.subroutine.argument_count()} args with {len(handler.subroutine.abi_args)} ABI args."
                )

            # All subroutine args types
            arg_type_specs = cast(
                list[abi.TypeSpec], handler.subroutine.expected_arg_types
            )

            # All subroutine arg values, initialize here and use below instead of
            # creating new instances on the fly so we dont have to think about splicing
            # back in the transaction types
            arg_vals = [typespec.new_instance() for typespec in arg_type_specs]

            # Only args that appear in app args
            app_arg_vals: list[abi.BaseType] = [
                ats for ats in arg_vals if not isinstance(ats, abi.Transaction)
            ]

            for aav in app_arg_vals:
                # If we're here we know the top level isnt a Transaction but a transaction may
                # be included in some collection type like a Tuple or Array, raise error
                # as these are not supported
                if abi.contains_type_spec(aav.type_spec(), abi.TransactionTypeSpecs):
                    raise TealInputError(
                        "A Transaction type may not be included in Tuples or Arrays"
                    )

            # assign to a var here since we modify app_arg_vals later
            tuplify = len(app_arg_vals) > METHOD_ARG_NUM_CUTOFF

            # only transaction args (these are omitted from app args)
            txn_arg_vals: list[abi.Transaction] = [
                ats for ats in arg_vals if isinstance(ats, abi.Transaction)
            ]

            # Tuple-ify any app args after the limit
            if tuplify:
                last_arg_specs_grouped: list[abi.TypeSpec] = [
                    t.type_spec() for t in app_arg_vals[METHOD_ARG_NUM_CUTOFF - 1 :]
                ]
                app_arg_vals = app_arg_vals[: METHOD_ARG_NUM_CUTOFF - 1]
                app_arg_vals.append(
                    abi.TupleTypeSpec(*last_arg_specs_grouped).new_instance()
                )

            # decode app args
            decode_instructions: list[Expr] = [
                app_arg.decode(Txn.application_args[idx + 1])
                for idx, app_arg in enumerate(app_arg_vals)
            ]

            # "decode" transaction types by setting the relative index
            if len(txn_arg_vals) > 0:
                txn_arg_len = len(txn_arg_vals)
                # The transactions should appear in the group in the order they're specified in the method signature
                # and should be relative to the current transaction.

                # ex:
                # doit(axfer,pay,appl)
                # would be 4 transactions
                #      current_idx-3 = axfer
                #      current_idx-2 = pay
                #      current_idx-1 = appl
                #      current_idx-0 = the txn that triggered the current eval (not specified but here for completeness)

                # since we're iterating in order of the txns appearance in the args we
                # subtract the current index from the total length to get the offset.
                # and subtract that from the current index to get the absolute position
                # in the group

                txn_decode_instructions: list[Expr] = []

                for idx, arg_val in enumerate(txn_arg_vals):
                    txn_decode_instructions.append(
                        arg_val._set_index(Txn.group_index() - Int(txn_arg_len - idx))
                    )
                    spec = arg_val.type_spec()
                    if type(spec) is not abi.TransactionTypeSpec:
                        # this is a specific transaction type
                        txn_decode_instructions.append(
                            Assert(arg_val.get().type_enum() == spec.txn_type_enum())
                        )

                decode_instructions += txn_decode_instructions

            # de-tuple into specific values using `store_into` on
            # each element of the tuple'd arguments
            if tuplify:
                tupled_abi_vals: list[abi.BaseType] = arg_vals[
                    METHOD_ARG_NUM_CUTOFF - 1 :
                ]
                tupled_arg: abi.Tuple = cast(abi.Tuple, app_arg_vals[-1])
                de_tuple_instructions: list[Expr] = [
                    tupled_arg[idx].store_into(arg_val)
                    for idx, arg_val in enumerate(tupled_abi_vals)
                ]
                decode_instructions += de_tuple_instructions

            # NOTE: does not have to have return, can be void method
            if handler.type_of() == "void":
                return Seq(
                    *decode_instructions,
                    cast(Expr, handler(*arg_vals)),
                    Approve(),
                )
            else:
                output_temp: abi.BaseType = cast(
                    OutputKwArgInfo, handler.output_kwarg_info
                ).abi_type.new_instance()
                subroutine_call: abi.ReturnedValue = cast(
                    abi.ReturnedValue, handler(*arg_vals)
                )
                return Seq(
                    *decode_instructions,
                    subroutine_call.store_into(output_temp),
                    abi.MethodReturn(output_temp),
                    Approve(),
                )
Пример #21
0
    def set(
        self,
        value: Union[
            str,
            bytes,
            Expr,
            Sequence[Byte],
            StaticArray[Byte, Literal[AddressLength.Bytes]],
            ComputedValue[StaticArray[Byte, Literal[AddressLength.Bytes]]],
            "Address",
            ComputedValue["Address"],
        ],
    ):
        """Set the value of this Address to the input value.

        The behavior of this method depends on the input argument type:

            * :code:`str`: set the value to the address from the encoded address string. This string must be a valid 58-character base-32 Algorand address with checksum.
            * :code:`bytes`: set the value to the raw address bytes. This byte string must have length 32.
            * :code:`Expr`: set the value to the result of a PyTeal expression, which must evaluate to a TealType.bytes. The program will fail if the evaluated byte string length is not 32.
            * :code:`Sequence[Byte]`: set the bytes of this Address to those contained in this Python sequence (e.g. a list or tuple). A compiler error will occur if the sequence length is not 32.
            * :code:`StaticArray[Byte, 32]`: copy the bytes from a StaticArray of 32 bytes.
            * :code:`ComputedValue[StaticArray[Byte, 32]]`: copy the bytes from a StaticArray of 32 bytes produced by a ComputedValue.
            * :code:`Address`: copy the value from another Address.
            * :code:`ComputedValue[Address]`: copy the value from an Address produced by a ComputedValue.

        Args:
            value: The new value this Address should take. This must follow the above constraints.

        Returns:
            An expression which stores the given value into this Address.
        """

        match value:
            case ComputedValue():
                pts = value.produced_type_spec()
                if pts == AddressTypeSpec() or pts == StaticArrayTypeSpec(
                    ByteTypeSpec(), AddressLength.Bytes
                ):
                    return value.store_into(self)

                raise TealInputError(
                    f"Got ComputedValue with type spec {pts}, expected AddressTypeSpec or StaticArray[Byte, Literal[AddressLength.Bytes]]"
                )
            case BaseType():
                if (
                    value.type_spec() == AddressTypeSpec()
                    or value.type_spec()
                    == StaticArrayTypeSpec(ByteTypeSpec(), AddressLength.Bytes)
                ):
                    return self.stored_value.store(value.stored_value.load())

                raise TealInputError(
                    f"Got {value} with type spec {value.type_spec()}, expected AddressTypeSpec"
                )
            case str():
                # Addr throws if value is invalid address
                return self.stored_value.store(Addr(value))
            case bytes():
                if len(value) == AddressLength.Bytes:
                    return self.stored_value.store(Bytes(value))
                raise TealInputError(
                    f"Got bytes with length {len(value)}, expected {AddressLength.Bytes}"
                )
            case Expr():
                return Seq(
                    self.stored_value.store(value),
                    Assert(
                        Len(self.stored_value.load()) == Int(AddressLength.Bytes.value)
                    ),
                )
            case CollectionSequence():
                if len(value) != AddressLength.Bytes:
                    raise TealInputError(
                        f"Got bytes with length {len(value)}, expected {AddressLength.Bytes}"
                    )
                return super().set(cast(Sequence[Byte], value))

        raise TealInputError(
            f"Got {type(value)}, expected Sequence, StaticArray, ComputedValue, Address, str, bytes, Expr"
        )
Пример #22
0
    """An Enum object that defines the mode used for the OpUp utility.

    Note: the Explicit mode requires the app id to be provided
    through the foreign apps array in order for it to be accessible
    during evaluation.
    """

    # The app to call must be provided by the user.
    Explicit = 0

    # The app to call is created then deleted for each request to increase budget.
    OnCall = 1


ON_CALL_APP = Bytes("base16", "068101")  # v6 program "int 1"
MIN_TXN_FEE = Int(1000)


class OpUp:
    """Utility for increasing opcode budget during app execution.

    Requires program version 6 or higher.

    Example:
        .. code-block:: python

            # OnCall mode: doesn't accept target_app_id as an argument
            opup = OpUp(OpUpMode.OnCall)
            program_with_opup = Seq(
                ...,
                opup.ensure_budget(Int(1000)),
Пример #23
0
 def encode(self) -> Expr:
     return SetBit(Bytes(b"\x00"), Int(0), self.get())
Пример #24
0
def Reject() -> Expr:
    """Immediately exit the program and mark the execution as unsuccessful."""
    return ExitProgram(Int(0))
Пример #25
0
def Approve() -> Expr:
    """Immediately exit the program and mark the execution as successful."""
    return ExitProgram(Int(1))
Пример #26
0
 def length(self) -> Expr:
     """Get the number of values this tuple holds as an Expr."""
     return Int(self.type_spec().length_static())