PyTeal: Algorand Smart Contracts in Python

PyTeal is a Python language binding for Algorand Smart Contracts (ASC1s).

Algorand Smart Contracts are implemented using a new language that is stack-based, called Transaction Execution Approval Language (TEAL). This a non-Turing complete language that allows branch forwards but prevents recursive logic to maximize safety and performance.

However, TEAL is essentially an assembly language. With PyTeal, developers can express smart contract logic purely using Python. PyTeal provides high level, functional programming style abstactions over TEAL and does type checking at construction time.

The User Guide describes many useful features in PyTeal, and the complete documentation for every expression and operation can be found in the PyTeal Package API documentation.

PyTeal hasn’t been security audited. Use it at your own risk.

Overview

With PyTeal, developers can easily write Algorand Smart Contracts (ASC1s) in Python. PyTeal supports both stateless and statefull smart contracts.

Below is an example of writing a basic stateless smart contract that allows a specific receiver to withdraw funds from an account.

# This example is provided for informational purposes only and has not been audited for security.

from pyteal import *

"""Basic Bank"""


def bank_for_account(receiver):
    """Only allow receiver to withdraw funds from this contract account.

    Args:
        receiver (str): Base 32 Algorand address of the receiver.
    """

    is_payment = Txn.type_enum() == TxnType.Payment
    is_single_tx = Global.group_size() == Int(1)
    is_correct_receiver = Txn.receiver() == Addr(receiver)
    no_close_out_addr = Txn.close_remainder_to() == Global.zero_address()
    no_rekey_addr = Txn.rekey_to() == Global.zero_address()
    acceptable_fee = Txn.fee() <= Int(1000)

    return And(
        is_payment,
        is_single_tx,
        is_correct_receiver,
        no_close_out_addr,
        no_rekey_addr,
        acceptable_fee,
    )


if __name__ == "__main__":
    program = bank_for_account(
        "ZZAF5ARA4MEC5PVDOP64JM5O5MQST63Q2KOY2FLYFLXXD3PFSNJJBYAFZM"
    )
    print(compileTeal(program, mode=Mode.Signature, version=3))

As shown in this exmaple, the logic of smart contract is expressed using PyTeal expressions constructed in Python. PyTeal overloads Python’s arithmetic operators such as < and == (more overloaded operators can be found in Arithmetic Operations), allowing Python developers express smart contract logic more naturally.

Lastly, compileTeal is called to convert an PyTeal expression to a TEAL program, consisting of a sequence of TEAL opcodes. The output of the above example is:

#pragma version 3
txn TypeEnum
int pay
==
global GroupSize
int 1
==
&&
txn Receiver
addr ZZAF5ARA4MEC5PVDOP64JM5O5MQST63Q2KOY2FLYFLXXD3PFSNJJBYAFZM
==
&&
txn CloseRemainderTo
global ZeroAddress
==
&&
txn RekeyTo
global ZeroAddress
==
&&
txn Fee
int 1000
<=
&&
return

Install PyTeal

The easiest way of installing PyTeal is using pip :

$ pip3 install pyteal

Alternatively, choose a distribution file, and run

$ pip3 install [file name]

PyTeal Examples

Here are some additional PyTeal example programs:

Signature Mode

Atomic Swap

Atomic Swap allows the transfer of Algos from a buyer to a seller in exchange for a good or service. This is done using a Hashed Time Locked Contract. In this scheme, the buyer funds a TEAL account with the sale price. The buyer also picks a secret value and encodes a secure hash of this value in the TEAL program. The TEAL program will transfer its balance to the seller if the seller is able to provide the secret value that corresponds to the hash in the program. When the seller renders the good or service to the buyer, the buyer discloses the secret from the program. The seller can immediately verify the secret and withdraw the payment.

# This example is provided for informational purposes only and has not been audited for security.

from pyteal import *

"""Atomic Swap"""

alice = Addr("6ZHGHH5Z5CTPCF5WCESXMGRSVK7QJETR63M3NY5FJCUYDHO57VTCMJOBGY")
bob = Addr("7Z5PWO2C6LFNQFGHWKSK5H47IQP5OJW2M3HA2QPXTY3WTNP5NU2MHBW27M")
secret = Bytes("base32", "2323232323232323")
timeout = 3000


def htlc(
    tmpl_seller=alice,
    tmpl_buyer=bob,
    tmpl_fee=1000,
    tmpl_secret=secret,
    tmpl_hash_fn=Sha256,
    tmpl_timeout=timeout,
):

    fee_cond = Txn.fee() < Int(tmpl_fee)
    safety_cond = And(
        Txn.type_enum() == TxnType.Payment,
        Txn.close_remainder_to() == Global.zero_address(),
        Txn.rekey_to() == Global.zero_address(),
    )

    recv_cond = And(Txn.receiver() == tmpl_seller, tmpl_hash_fn(Arg(0)) == tmpl_secret)

    esc_cond = And(Txn.receiver() == tmpl_buyer, Txn.first_valid() > Int(tmpl_timeout))

    return And(fee_cond, safety_cond, Or(recv_cond, esc_cond))


if __name__ == "__main__":
    print(compileTeal(htlc(), mode=Mode.Signature, version=2))

Split Payment

Split Payment splits payment between tmpl_rcv1 and tmpl_rcv2 on the ratio of tmpl_ratn / tmpl_ratd.

# This example is provided for informational purposes only and has not been audited for security.

from pyteal import *

"""Split Payment"""

tmpl_fee = Int(1000)
tmpl_rcv1 = Addr("6ZHGHH5Z5CTPCF5WCESXMGRSVK7QJETR63M3NY5FJCUYDHO57VTCMJOBGY")
tmpl_rcv2 = Addr("7Z5PWO2C6LFNQFGHWKSK5H47IQP5OJW2M3HA2QPXTY3WTNP5NU2MHBW27M")
tmpl_own = Addr("5MK5NGBRT5RL6IGUSYDIX5P7TNNZKRVXKT6FGVI6UVK6IZAWTYQGE4RZIQ")
tmpl_ratn = Int(1)
tmpl_ratd = Int(3)
tmpl_min_pay = Int(1000)
tmpl_timeout = Int(3000)


def split(
    tmpl_fee=tmpl_fee,
    tmpl_rcv1=tmpl_rcv1,
    tmpl_rcv2=tmpl_rcv2,
    tmpl_own=tmpl_own,
    tmpl_ratn=tmpl_ratn,
    tmpl_ratd=tmpl_ratd,
    tmpl_min_pay=tmpl_min_pay,
    tmpl_timeout=tmpl_timeout,
):

    split_core = And(
        Txn.type_enum() == TxnType.Payment,
        Txn.fee() < tmpl_fee,
        Txn.rekey_to() == Global.zero_address(),
    )

    split_transfer = And(
        Gtxn[0].sender() == Gtxn[1].sender(),
        Txn.close_remainder_to() == Global.zero_address(),
        Gtxn[0].receiver() == tmpl_rcv1,
        Gtxn[1].receiver() == tmpl_rcv2,
        Gtxn[0].amount()
        == ((Gtxn[0].amount() + Gtxn[1].amount()) * tmpl_ratn) / tmpl_ratd,
        Gtxn[0].amount() == tmpl_min_pay,
    )

    split_close = And(
        Txn.close_remainder_to() == tmpl_own,
        Txn.receiver() == Global.zero_address(),
        Txn.amount() == Int(0),
        Txn.first_valid() > tmpl_timeout,
    )

    split_program = And(
        split_core, If(Global.group_size() == Int(2), split_transfer, split_close)
    )

    return split_program


if __name__ == "__main__":
    print(compileTeal(split(), mode=Mode.Signature, version=2))

Periodic Payment

Periodic Payment allows some account to execute periodic withdrawal of funds. This PyTeal program creates an contract account that allows tmpl_rcv to withdraw tmpl_amt every tmpl_period rounds for tmpl_dur after every multiple of tmpl_period.

After tmpl_timeout, all remaining funds in the escrow are available to tmpl_rcv.

# This example is provided for informational purposes only and has not been audited for security.

from pyteal import *

"""Periodic Payment"""

tmpl_fee = Int(1000)
tmpl_period = Int(50)
tmpl_dur = Int(5000)
tmpl_lease = Bytes("base64", "023sdDE2")
tmpl_amt = Int(2000)
tmpl_rcv = Addr("6ZHGHH5Z5CTPCF5WCESXMGRSVK7QJETR63M3NY5FJCUYDHO57VTCMJOBGY")
tmpl_timeout = Int(30000)


def periodic_payment(
    tmpl_fee=tmpl_fee,
    tmpl_period=tmpl_period,
    tmpl_dur=tmpl_dur,
    tmpl_lease=tmpl_lease,
    tmpl_amt=tmpl_amt,
    tmpl_rcv=tmpl_rcv,
    tmpl_timeout=tmpl_timeout,
):

    periodic_pay_core = And(
        Txn.type_enum() == TxnType.Payment,
        Txn.fee() < tmpl_fee,
        Txn.first_valid() % tmpl_period == Int(0),
        Txn.last_valid() == tmpl_dur + Txn.first_valid(),
        Txn.lease() == tmpl_lease,
    )

    periodic_pay_transfer = And(
        Txn.close_remainder_to() == Global.zero_address(),
        Txn.rekey_to() == Global.zero_address(),
        Txn.receiver() == tmpl_rcv,
        Txn.amount() == tmpl_amt,
    )

    periodic_pay_close = And(
        Txn.close_remainder_to() == tmpl_rcv,
        Txn.rekey_to() == Global.zero_address(),
        Txn.receiver() == Global.zero_address(),
        Txn.first_valid() == tmpl_timeout,
        Txn.amount() == Int(0),
    )

    periodic_pay_escrow = periodic_pay_core.And(
        periodic_pay_transfer.Or(periodic_pay_close)
    )

    return periodic_pay_escrow


if __name__ == "__main__":
    print(compileTeal(periodic_payment(), mode=Mode.Signature, version=2))

Application Mode

Voting

Voting allows accounts to register and vote for arbitrary choices. Here a choice is any byte slice and anyone is allowed to register to vote.

This example has a configurable registration period defined by the global state RegBegin and RegEnd which restrict when accounts can register to vote. There is also a separate configurable voting period defined by the global state VotingBegin and VotingEnd which restrict when voting can take place.

An account must register in order to vote. Accounts cannot vote more than once, and if an account opts out of the application before the voting period has concluded, their vote is discarded. The results are visible in the global state of the application, and the winner is the candidate with the highest number of votes.

# This example is provided for informational purposes only and has not been audited for security.

from pyteal import *


def approval_program():
    on_creation = Seq(
        [
            App.globalPut(Bytes("Creator"), Txn.sender()),
            Assert(Txn.application_args.length() == Int(4)),
            App.globalPut(Bytes("RegBegin"), Btoi(Txn.application_args[0])),
            App.globalPut(Bytes("RegEnd"), Btoi(Txn.application_args[1])),
            App.globalPut(Bytes("VoteBegin"), Btoi(Txn.application_args[2])),
            App.globalPut(Bytes("VoteEnd"), Btoi(Txn.application_args[3])),
            Return(Int(1)),
        ]
    )

    is_creator = Txn.sender() == App.globalGet(Bytes("Creator"))

    get_vote_of_sender = App.localGetEx(Int(0), App.id(), Bytes("voted"))

    on_closeout = Seq(
        [
            get_vote_of_sender,
            If(
                And(
                    Global.round() <= App.globalGet(Bytes("VoteEnd")),
                    get_vote_of_sender.hasValue(),
                ),
                App.globalPut(
                    get_vote_of_sender.value(),
                    App.globalGet(get_vote_of_sender.value()) - Int(1),
                ),
            ),
            Return(Int(1)),
        ]
    )

    on_register = Return(
        And(
            Global.round() >= App.globalGet(Bytes("RegBegin")),
            Global.round() <= App.globalGet(Bytes("RegEnd")),
        )
    )

    choice = Txn.application_args[1]
    choice_tally = App.globalGet(choice)
    on_vote = Seq(
        [
            Assert(
                And(
                    Global.round() >= App.globalGet(Bytes("VoteBegin")),
                    Global.round() <= App.globalGet(Bytes("VoteEnd")),
                )
            ),
            get_vote_of_sender,
            If(get_vote_of_sender.hasValue(), Return(Int(0))),
            App.globalPut(choice, choice_tally + Int(1)),
            App.localPut(Int(0), Bytes("voted"), choice),
            Return(Int(1)),
        ]
    )

    program = Cond(
        [Txn.application_id() == Int(0), on_creation],
        [Txn.on_completion() == OnComplete.DeleteApplication, Return(is_creator)],
        [Txn.on_completion() == OnComplete.UpdateApplication, Return(is_creator)],
        [Txn.on_completion() == OnComplete.CloseOut, on_closeout],
        [Txn.on_completion() == OnComplete.OptIn, on_register],
        [Txn.application_args[0] == Bytes("vote"), on_vote],
    )

    return program


def clear_state_program():
    get_vote_of_sender = App.localGetEx(Int(0), App.id(), Bytes("voted"))
    program = Seq(
        [
            get_vote_of_sender,
            If(
                And(
                    Global.round() <= App.globalGet(Bytes("VoteEnd")),
                    get_vote_of_sender.hasValue(),
                ),
                App.globalPut(
                    get_vote_of_sender.value(),
                    App.globalGet(get_vote_of_sender.value()) - Int(1),
                ),
            ),
            Return(Int(1)),
        ]
    )

    return program


if __name__ == "__main__":
    with open("vote_approval.teal", "w") as f:
        compiled = compileTeal(approval_program(), mode=Mode.Application, version=2)
        f.write(compiled)

    with open("vote_clear_state.teal", "w") as f:
        compiled = compileTeal(clear_state_program(), mode=Mode.Application, version=2)
        f.write(compiled)

A reference script that deploys the voting application is below:

# based off https://github.com/algorand/docs/blob/cdf11d48a4b1168752e6ccaf77c8b9e8e599713a/examples/smart_contracts/v2/python/stateful_smart_contracts.py

import base64
import datetime

from algosdk.future import transaction
from algosdk import account, mnemonic
from algosdk.v2client import algod
from pyteal import compileTeal, Mode
from vote import approval_program, clear_state_program

# user declared account mnemonics
creator_mnemonic = "Your 25-word mnemonic goes here"
user_mnemonic = "A second distinct 25-word mnemonic goes here"

# user declared algod connection parameters. Node must have EnableDeveloperAPI set to true in its config
algod_address = "http://localhost:4001"
algod_token = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

# helper function to compile program source
def compile_program(client, source_code):
    compile_response = client.compile(source_code)
    return base64.b64decode(compile_response["result"])


# helper function that converts a mnemonic passphrase into a private signing key
def get_private_key_from_mnemonic(mn):
    private_key = mnemonic.to_private_key(mn)
    return private_key


# helper function that waits for a given txid to be confirmed by the network
def wait_for_confirmation(client, txid):
    last_round = client.status().get("last-round")
    txinfo = client.pending_transaction_info(txid)
    while not (txinfo.get("confirmed-round") and txinfo.get("confirmed-round") > 0):
        print("Waiting for confirmation...")
        last_round += 1
        client.status_after_block(last_round)
        txinfo = client.pending_transaction_info(txid)
    print(
        "Transaction {} confirmed in round {}.".format(
            txid, txinfo.get("confirmed-round")
        )
    )
    return txinfo


def wait_for_round(client, round):
    last_round = client.status().get("last-round")
    print(f"Waiting for round {round}")
    while last_round < round:
        last_round += 1
        client.status_after_block(last_round)
        print(f"Round {last_round}")


# create new application
def create_app(
    client,
    private_key,
    approval_program,
    clear_program,
    global_schema,
    local_schema,
    app_args,
):
    # define sender as creator
    sender = account.address_from_private_key(private_key)

    # declare on_complete as NoOp
    on_complete = transaction.OnComplete.NoOpOC.real

    # get node suggested parameters
    params = client.suggested_params()
    # comment out the next two (2) lines to use suggested fees
    params.flat_fee = True
    params.fee = 1000

    # create unsigned transaction
    txn = transaction.ApplicationCreateTxn(
        sender,
        params,
        on_complete,
        approval_program,
        clear_program,
        global_schema,
        local_schema,
        app_args,
    )

    # sign transaction
    signed_txn = txn.sign(private_key)
    tx_id = signed_txn.transaction.get_txid()

    # send transaction
    client.send_transactions([signed_txn])

    # await confirmation
    wait_for_confirmation(client, tx_id)

    # display results
    transaction_response = client.pending_transaction_info(tx_id)
    app_id = transaction_response["application-index"]
    print("Created new app-id:", app_id)

    return app_id


# opt-in to application
def opt_in_app(client, private_key, index):
    # declare sender
    sender = account.address_from_private_key(private_key)
    print("OptIn from account: ", sender)

    # get node suggested parameters
    params = client.suggested_params()
    # comment out the next two (2) lines to use suggested fees
    params.flat_fee = True
    params.fee = 1000

    # create unsigned transaction
    txn = transaction.ApplicationOptInTxn(sender, params, index)

    # sign transaction
    signed_txn = txn.sign(private_key)
    tx_id = signed_txn.transaction.get_txid()

    # send transaction
    client.send_transactions([signed_txn])

    # await confirmation
    wait_for_confirmation(client, tx_id)

    # display results
    transaction_response = client.pending_transaction_info(tx_id)
    print("OptIn to app-id:", transaction_response["txn"]["txn"]["apid"])


# call application
def call_app(client, private_key, index, app_args):
    # declare sender
    sender = account.address_from_private_key(private_key)
    print("Call from account:", sender)

    # get node suggested parameters
    params = client.suggested_params()
    # comment out the next two (2) lines to use suggested fees
    params.flat_fee = True
    params.fee = 1000

    # create unsigned transaction
    txn = transaction.ApplicationNoOpTxn(sender, params, index, app_args)

    # sign transaction
    signed_txn = txn.sign(private_key)
    tx_id = signed_txn.transaction.get_txid()

    # send transaction
    client.send_transactions([signed_txn])

    # await confirmation
    wait_for_confirmation(client, tx_id)


def format_state(state):
    formatted = {}
    for item in state:
        key = item["key"]
        value = item["value"]
        formatted_key = base64.b64decode(key).decode("utf-8")
        if value["type"] == 1:
            # byte string
            if formatted_key == "voted":
                formatted_value = base64.b64decode(value["bytes"]).decode("utf-8")
            else:
                formatted_value = value["bytes"]
            formatted[formatted_key] = formatted_value
        else:
            # integer
            formatted[formatted_key] = value["uint"]
    return formatted


# read user local state
def read_local_state(client, addr, app_id):
    results = client.account_info(addr)
    for local_state in results["apps-local-state"]:
        if local_state["id"] == app_id:
            if "key-value" not in local_state:
                return {}
            return format_state(local_state["key-value"])
    return {}


# read app global state
def read_global_state(client, addr, app_id):
    results = client.account_info(addr)
    apps_created = results["created-apps"]
    for app in apps_created:
        if app["id"] == app_id:
            return format_state(app["params"]["global-state"])
    return {}


# delete application
def delete_app(client, private_key, index):
    # declare sender
    sender = account.address_from_private_key(private_key)

    # get node suggested parameters
    params = client.suggested_params()
    # comment out the next two (2) lines to use suggested fees
    params.flat_fee = True
    params.fee = 1000

    # create unsigned transaction
    txn = transaction.ApplicationDeleteTxn(sender, params, index)

    # sign transaction
    signed_txn = txn.sign(private_key)
    tx_id = signed_txn.transaction.get_txid()

    # send transaction
    client.send_transactions([signed_txn])

    # await confirmation
    wait_for_confirmation(client, tx_id)

    # display results
    transaction_response = client.pending_transaction_info(tx_id)
    print("Deleted app-id:", transaction_response["txn"]["txn"]["apid"])


# close out from application
def close_out_app(client, private_key, index):
    # declare sender
    sender = account.address_from_private_key(private_key)

    # get node suggested parameters
    params = client.suggested_params()
    # comment out the next two (2) lines to use suggested fees
    params.flat_fee = True
    params.fee = 1000

    # create unsigned transaction
    txn = transaction.ApplicationCloseOutTxn(sender, params, index)

    # sign transaction
    signed_txn = txn.sign(private_key)
    tx_id = signed_txn.transaction.get_txid()

    # send transaction
    client.send_transactions([signed_txn])

    # await confirmation
    wait_for_confirmation(client, tx_id)

    # display results
    transaction_response = client.pending_transaction_info(tx_id)
    print("Closed out from app-id: ", transaction_response["txn"]["txn"]["apid"])


# clear application
def clear_app(client, private_key, index):
    # declare sender
    sender = account.address_from_private_key(private_key)

    # get node suggested parameters
    params = client.suggested_params()
    # comment out the next two (2) lines to use suggested fees
    params.flat_fee = True
    params.fee = 1000

    # create unsigned transaction
    txn = transaction.ApplicationClearStateTxn(sender, params, index)

    # sign transaction
    signed_txn = txn.sign(private_key)
    tx_id = signed_txn.transaction.get_txid()

    # send transaction
    client.send_transactions([signed_txn])

    # await confirmation
    wait_for_confirmation(client, tx_id)

    # display results
    transaction_response = client.pending_transaction_info(tx_id)
    print("Cleared app-id:", transaction_response["txn"]["txn"]["apid"])


# convert 64 bit integer i to byte string
def intToBytes(i):
    return i.to_bytes(8, "big")


def main():
    # initialize an algodClient
    algod_client = algod.AlgodClient(algod_token, algod_address)

    # define private keys
    creator_private_key = get_private_key_from_mnemonic(creator_mnemonic)
    user_private_key = get_private_key_from_mnemonic(user_mnemonic)

    # declare application state storage (immutable)
    local_ints = 0
    local_bytes = 1
    global_ints = (
        24  # 4 for setup + 20 for choices. Use a larger number for more choices.
    )
    global_bytes = 1
    global_schema = transaction.StateSchema(global_ints, global_bytes)
    local_schema = transaction.StateSchema(local_ints, local_bytes)

    # get PyTeal approval program
    approval_program_ast = approval_program()
    # compile program to TEAL assembly
    approval_program_teal = compileTeal(
        approval_program_ast, mode=Mode.Application, version=2
    )
    # compile program to binary
    approval_program_compiled = compile_program(algod_client, approval_program_teal)

    # get PyTeal clear state program
    clear_state_program_ast = clear_state_program()
    # compile program to TEAL assembly
    clear_state_program_teal = compileTeal(
        clear_state_program_ast, mode=Mode.Application, version=2
    )
    # compile program to binary
    clear_state_program_compiled = compile_program(
        algod_client, clear_state_program_teal
    )

    # configure registration and voting period
    status = algod_client.status()
    regBegin = status["last-round"] + 10
    regEnd = regBegin + 10
    voteBegin = regEnd + 1
    voteEnd = voteBegin + 10

    print(f"Registration rounds: {regBegin} to {regEnd}")
    print(f"Vote rounds: {voteBegin} to {voteEnd}")

    # create list of bytes for app args
    app_args = [
        intToBytes(regBegin),
        intToBytes(regEnd),
        intToBytes(voteBegin),
        intToBytes(voteEnd),
    ]

    # create new application
    app_id = create_app(
        algod_client,
        creator_private_key,
        approval_program_compiled,
        clear_state_program_compiled,
        global_schema,
        local_schema,
        app_args,
    )

    # read global state of application
    print(
        "Global state:",
        read_global_state(
            algod_client, account.address_from_private_key(creator_private_key), app_id
        ),
    )

    # wait for registration period to start
    wait_for_round(algod_client, regBegin)

    # opt-in to application
    opt_in_app(algod_client, user_private_key, app_id)

    wait_for_round(algod_client, voteBegin)

    # call application without arguments
    call_app(algod_client, user_private_key, app_id, [b"vote", b"choiceA"])

    # read local state of application from user account
    print(
        "Local state:",
        read_local_state(
            algod_client, account.address_from_private_key(user_private_key), app_id
        ),
    )

    # wait for registration period to start
    wait_for_round(algod_client, voteEnd)

    # read global state of application
    global_state = read_global_state(
        algod_client, account.address_from_private_key(creator_private_key), app_id
    )
    print("Global state:", global_state)

    max_votes = 0
    max_votes_choice = None
    for key, value in global_state.items():
        if (
            key
            not in (
                "RegBegin",
                "RegEnd",
                "VoteBegin",
                "VoteEnd",
                "Creator",
            )
            and isinstance(value, int)
        ):
            if value > max_votes:
                max_votes = value
                max_votes_choice = key

    print("The winner is:", max_votes_choice)

    # delete application
    delete_app(algod_client, creator_private_key, app_id)

    # clear application from user account
    clear_app(algod_client, user_private_key, app_id)


if __name__ == "__main__":
    main()

Example output for deployment would be:

Registration rounds: 592 to 602
Vote rounds: 603 to 613
Waiting for confirmation...
Transaction KXJHR6J4QSCAHO36L77DPJ53CLZBCCSPSBAOGTGQDRA7WECDXUEA confirmed in round 584.
Created new app-id: 29
Global state: {'RegEnd': 602, 'VoteBegin': 603, 'VoteEnd': 613, 'Creator': '49y8gDrKSnM77cgRyFzYdlkw18SDVNKhhOiS6NVVH8U=', 'RegBegin': 592}
Waiting for round 592
Round 585
Round 586
Round 587
Round 588
Round 589
Round 590
Round 591
Round 592
OptIn from account:  FVQEFNOSD25TDBTTTIU2I5KW5DHR6PADYMZESTOCQ2O3ME4OWXEI7OHVRY
Waiting for confirmation...
Transaction YWXOAREFSUYID6QLWQHANTXK3NR2XOVTIQYKMD27F3VXJKP7CMYQ confirmed in round 595.
OptIn to app-id: 29
Waiting for round 603
Round 596
Round 597
Round 598
Round 599
Round 600
Round 601
Round 602
Round 603
Call from account: FVQEFNOSD25TDBTTTIU2I5KW5DHR6PADYMZESTOCQ2O3ME4OWXEI7OHVRY
Waiting for confirmation...
Transaction WNV4DTPEMVGUXNRZHMWNSCUU7AQJOCFTBKJT6NV2KN6THT4QGKNQ confirmed in round 606.
Local state: {'voted': 'choiceA'}
Waiting for round 613
Round 607
Round 608
Round 609
Round 610
Round 611
Round 612
Round 613
Global state: {'RegBegin': 592, 'RegEnd': 602, 'VoteBegin': 603, 'VoteEnd': 613, 'choiceA': 1, 'Creator': '49y8gDrKSnM77cgRyFzYdlkw18SDVNKhhOiS6NVVH8U='}
The winner is: choiceA
Waiting for confirmation...
Transaction 535KBWJ7RQX4ISV763IUUICQWI6VERYBJ7J6X7HPMAMFNKJPSNPQ confirmed in round 616.
Deleted app-id: 29
Waiting for confirmation...
Transaction Z56HDAJYARUC4PWGWQLCBA6TZYQOOLNOXY5XRM3IYUEEUCT5DRMA confirmed in round 618.
Cleared app-id: 29

Asset

Asset is an implementation of a custom asset type using smart contracts. While Algorand has ASAs, in some blockchains the only way to create a custom asset is through smart contracts.

At creation, the creator specifies the total supply of the asset. Initially this supply is placed in a reserve and the creator is made an admin. Any admin can move funds from the reserve into the balance of any account that has opted into the application using the mint argument. Additionally, any admin can move funds from any account’s balance into the reserve using the burn argument.

Accounts are free to transfer funds in their balance to any other account that has opted into the application. When an account opts out of the application, their balance is added to the reserve.

# This example is provided for informational purposes only and has not been audited for security.

from pyteal import *


def approval_program():
    on_creation = Seq(
        [
            Assert(Txn.application_args.length() == Int(1)),
            App.globalPut(Bytes("total supply"), Btoi(Txn.application_args[0])),
            App.globalPut(Bytes("reserve"), Btoi(Txn.application_args[0])),
            App.localPut(Int(0), Bytes("admin"), Int(1)),
            App.localPut(Int(0), Bytes("balance"), Int(0)),
            Return(Int(1)),
        ]
    )

    is_admin = App.localGet(Int(0), Bytes("admin"))

    on_closeout = Seq(
        [
            App.globalPut(
                Bytes("reserve"),
                App.globalGet(Bytes("reserve"))
                + App.localGet(Int(0), Bytes("balance")),
            ),
            Return(Int(1)),
        ]
    )

    register = Seq([App.localPut(Int(0), Bytes("balance"), Int(0)), Return(Int(1))])

    # configure the admin status of the account Txn.accounts[1]
    # sender must be admin
    new_admin_status = Btoi(Txn.application_args[1])
    set_admin = Seq(
        [
            Assert(And(is_admin, Txn.application_args.length() == Int(2))),
            App.localPut(Int(1), Bytes("admin"), new_admin_status),
            Return(Int(1)),
        ]
    )
    # NOTE: The above set_admin code is carefully constructed. If instead we used the following code:
    # Seq([
    #     Assert(Txn.application_args.length() == Int(2)),
    #     App.localPut(Int(1), Bytes("admin"), new_admin_status),
    #     Return(is_admin)
    # ])
    # It would be vulnerable to the following attack: a sender passes in their own address as
    # Txn.accounts[1], so then the line App.localPut(Int(1), Bytes("admin"), new_admin_status)
    # changes the sender's admin status, meaning the final Return(is_admin) can return anything the
    # sender wants. This allows anyone to become an admin!

    # move assets from the reserve to Txn.accounts[1]
    # sender must be admin
    mint_amount = Btoi(Txn.application_args[1])
    mint = Seq(
        [
            Assert(Txn.application_args.length() == Int(2)),
            Assert(mint_amount <= App.globalGet(Bytes("reserve"))),
            App.globalPut(
                Bytes("reserve"), App.globalGet(Bytes("reserve")) - mint_amount
            ),
            App.localPut(
                Int(1),
                Bytes("balance"),
                App.localGet(Int(1), Bytes("balance")) + mint_amount,
            ),
            Return(is_admin),
        ]
    )

    # transfer assets from the sender to Txn.accounts[1]
    transfer_amount = Btoi(Txn.application_args[1])
    transfer = Seq(
        [
            Assert(Txn.application_args.length() == Int(2)),
            Assert(transfer_amount <= App.localGet(Int(0), Bytes("balance"))),
            App.localPut(
                Int(0),
                Bytes("balance"),
                App.localGet(Int(0), Bytes("balance")) - transfer_amount,
            ),
            App.localPut(
                Int(1),
                Bytes("balance"),
                App.localGet(Int(1), Bytes("balance")) + transfer_amount,
            ),
            Return(Int(1)),
        ]
    )

    program = Cond(
        [Txn.application_id() == Int(0), on_creation],
        [Txn.on_completion() == OnComplete.DeleteApplication, Return(is_admin)],
        [Txn.on_completion() == OnComplete.UpdateApplication, Return(is_admin)],
        [Txn.on_completion() == OnComplete.CloseOut, on_closeout],
        [Txn.on_completion() == OnComplete.OptIn, register],
        [Txn.application_args[0] == Bytes("set admin"), set_admin],
        [Txn.application_args[0] == Bytes("mint"), mint],
        [Txn.application_args[0] == Bytes("transfer"), transfer],
    )

    return program


def clear_state_program():
    program = Seq(
        [
            App.globalPut(
                Bytes("reserve"),
                App.globalGet(Bytes("reserve"))
                + App.localGet(Int(0), Bytes("balance")),
            ),
            Return(Int(1)),
        ]
    )

    return program


if __name__ == "__main__":
    with open("asset_approval.teal", "w") as f:
        compiled = compileTeal(approval_program(), mode=Mode.Application, version=2)
        f.write(compiled)

    with open("asset_clear_state.teal", "w") as f:
        compiled = compileTeal(clear_state_program(), mode=Mode.Application, version=2)
        f.write(compiled)

Security Token

Security Token is an extension of the Asset example with more features and restrictions. There are two types of admins, contract admins and transfer admins.

Contract admins can delete the smart contract if the entire supply is in the reserve. They can promote accounts to transfer or contract admins. They can also mint and burn funds.

Transfer admins can impose maximum balance limitations on accounts, temporarily lock accounts, assign accounts to transfer groups, and impose transaction restrictions between transaction groups.

Both contract and transfer admins can pause trading of funds and freeze individual accounts.

Accounts can only transfer funds if trading is not paused, both the sender and receive accounts are not frozen or temporarily locked, transfer group restrictions are not in place between them, and the receiver’s account does not have a maximum balance restriction that would be invalidated.

# This example is provided for informational purposes only and has not been audited for security.

from pyteal import *


def approval_program():
    on_creation = Seq(
        [
            Assert(Txn.application_args.length() == Int(1)),
            App.globalPut(Bytes("total supply"), Btoi(Txn.application_args[0])),
            App.globalPut(Bytes("reserve"), Btoi(Txn.application_args[0])),
            App.globalPut(Bytes("paused"), Int(0)),
            App.localPut(Int(0), Bytes("contract admin"), Int(1)),
            App.localPut(Int(0), Bytes("transfer admin"), Int(1)),
            App.localPut(Int(0), Bytes("balance"), Int(0)),
            Return(Int(1)),
        ]
    )

    is_contract_admin = App.localGet(Int(0), Bytes("contract admin"))
    is_transfer_admin = App.localGet(Int(0), Bytes("transfer admin"))
    is_any_admin = is_contract_admin.Or(is_transfer_admin)

    can_delete = And(
        is_contract_admin,
        App.globalGet(Bytes("total supply")) == App.globalGet(Bytes("reserve")),
    )

    on_closeout = Seq(
        [
            App.globalPut(
                Bytes("reserve"),
                App.globalGet(Bytes("reserve"))
                + App.localGet(Int(0), Bytes("balance")),
            ),
            Return(Int(1)),
        ]
    )

    register = Seq([App.localPut(Int(0), Bytes("balance"), Int(0)), Return(Int(1))])

    # pause all transfers
    # sender must be any admin
    new_pause_value = Btoi(Txn.application_args[1])
    pause = Seq(
        [
            Assert(Txn.application_args.length() == Int(2)),
            App.globalPut(Bytes("paused"), new_pause_value),
            Return(is_any_admin),
        ]
    )

    # configure the admin status of the account Txn.accounts[1]
    # sender must be contract admin
    new_admin_type = Txn.application_args[1]
    new_admin_status = Btoi(Txn.application_args[2])
    set_admin = Seq(
        [
            Assert(
                And(
                    is_contract_admin,
                    Txn.application_args.length() == Int(3),
                    Or(
                        new_admin_type == Bytes("contract admin"),
                        new_admin_type == Bytes("transfer admin"),
                    ),
                    Txn.accounts.length() == Int(1),
                )
            ),
            App.localPut(Int(1), new_admin_type, new_admin_status),
            Return(Int(1)),
        ]
    )
    # NOTE: The above set_admin code is carefully constructed. If instead we used the following code:
    # Seq([
    #     Assert(And(
    #         Txn.application_args.length() == Int(3),
    #         Or(new_admin_type == Bytes("contract admin"), new_admin_type == Bytes("transfer admin")),
    #         Txn.accounts.length() == Int(1)
    #     )),
    #     App.localPut(Int(1), new_admin_type, new_admin_status),
    #     Return(is_contract_admin)
    # ])
    # It would be vulnerable to the following attack: a sender passes in their own address as
    # Txn.accounts[1], so then the line App.localPut(Int(1), new_admin_type, new_admin_status)
    # changes the sender's admin status, meaning the final Return(is_contract_admin) can return
    # anything the sender wants. This allows anyone to become an admin!

    # freeze Txn.accounts[1]
    # sender must be any admin
    new_freeze_value = Btoi(Txn.application_args[1])
    freeze = Seq(
        [
            Assert(
                And(
                    Txn.application_args.length() == Int(2),
                    Txn.accounts.length() == Int(1),
                )
            ),
            App.localPut(Int(1), Bytes("frozen"), new_freeze_value),
            Return(is_any_admin),
        ]
    )

    # modify the max balance of Txn.accounts[1]
    # if max_balance_value is 0, will delete the existing max balance limitation on the account
    # sender must be transfer admin
    max_balance_value = Btoi(Txn.application_args[1])
    max_balance = Seq(
        [
            Assert(
                And(
                    Txn.application_args.length() == Int(2),
                    Txn.accounts.length() == Int(1),
                )
            ),
            If(
                max_balance_value == Int(0),
                App.localDel(Int(1), Bytes("max balance")),
                App.localPut(Int(1), Bytes("max balance"), max_balance_value),
            ),
            Return(is_transfer_admin),
        ]
    )

    # lock Txn.accounts[1] until a UNIX timestamp
    # sender must be transfer admin
    lock_until_value = Btoi(Txn.application_args[1])
    lock_until = Seq(
        [
            Assert(
                And(
                    Txn.application_args.length() == Int(2),
                    Txn.accounts.length() == Int(1),
                )
            ),
            If(
                lock_until_value == Int(0),
                App.localDel(Int(1), Bytes("lock until")),
                App.localPut(Int(1), Bytes("lock until"), lock_until_value),
            ),
            Return(is_transfer_admin),
        ]
    )

    set_transfer_group = Seq(
        [
            Assert(
                And(
                    Txn.application_args.length() == Int(3),
                    Txn.accounts.length() == Int(1),
                )
            ),
            App.localPut(
                Int(1), Bytes("transfer group"), Btoi(Txn.application_args[2])
            ),
        ]
    )

    def getRuleKey(sendGroup, receiveGroup):
        return Concat(Bytes("rule"), Itob(sendGroup), Itob(receiveGroup))

    lock_transfer_key = getRuleKey(
        Btoi(Txn.application_args[2]), Btoi(Txn.application_args[3])
    )
    lock_transfer_until = Btoi(Txn.application_args[4])
    lock_transfer_group = Seq(
        [
            Assert(Txn.application_args.length() == Int(5)),
            If(
                lock_transfer_until == Int(0),
                App.globalDel(lock_transfer_key),
                App.globalPut(lock_transfer_key, lock_transfer_until),
            ),
        ]
    )

    # sender must be transfer admin
    transfer_group = Seq(
        [
            Assert(Txn.application_args.length() > Int(2)),
            Cond(
                [Txn.application_args[1] == Bytes("set"), set_transfer_group],
                [Txn.application_args[1] == Bytes("lock"), lock_transfer_group],
            ),
            Return(is_transfer_admin),
        ]
    )

    # move assets from the reserve to Txn.accounts[1]
    # sender must be contract admin
    mint_amount = Btoi(Txn.application_args[1])
    mint = Seq(
        [
            Assert(
                And(
                    Txn.application_args.length() == Int(2),
                    Txn.accounts.length() == Int(1),
                    mint_amount <= App.globalGet(Bytes("reserve")),
                )
            ),
            App.globalPut(
                Bytes("reserve"), App.globalGet(Bytes("reserve")) - mint_amount
            ),
            App.localPut(
                Int(1),
                Bytes("balance"),
                App.localGet(Int(1), Bytes("balance")) + mint_amount,
            ),
            Return(is_contract_admin),
        ]
    )

    # move assets from Txn.accounts[1] to the reserve
    # sender must be contract admin
    burn_amount = Btoi(Txn.application_args[1])
    burn = Seq(
        [
            Assert(
                And(
                    Txn.application_args.length() == Int(2),
                    Txn.accounts.length() == Int(1),
                    burn_amount <= App.localGet(Int(1), Bytes("balance")),
                )
            ),
            App.globalPut(
                Bytes("reserve"), App.globalGet(Bytes("reserve")) + burn_amount
            ),
            App.localPut(
                Int(1),
                Bytes("balance"),
                App.localGet(Int(1), Bytes("balance")) - burn_amount,
            ),
            Return(is_contract_admin),
        ]
    )

    # transfer assets from the sender to Txn.accounts[1]
    transfer_amount = Btoi(Txn.application_args[1])
    receiver_max_balance = App.localGetEx(Int(1), App.id(), Bytes("max balance"))
    transfer = Seq(
        [
            Assert(
                And(
                    Txn.application_args.length() == Int(2),
                    Txn.accounts.length() == Int(1),
                    transfer_amount <= App.localGet(Int(0), Bytes("balance")),
                )
            ),
            receiver_max_balance,
            If(
                Or(
                    App.globalGet(Bytes("paused")),
                    App.localGet(Int(0), Bytes("frozen")),
                    App.localGet(Int(1), Bytes("frozen")),
                    App.localGet(Int(0), Bytes("lock until"))
                    >= Global.latest_timestamp(),
                    App.localGet(Int(1), Bytes("lock until"))
                    >= Global.latest_timestamp(),
                    App.globalGet(
                        getRuleKey(
                            App.localGet(Int(0), Bytes("transfer group")),
                            App.localGet(Int(1), Bytes("transfer group")),
                        )
                    )
                    >= Global.latest_timestamp(),
                    And(
                        receiver_max_balance.hasValue(),
                        receiver_max_balance.value()
                        < App.localGet(Int(1), Bytes("balance")) + transfer_amount,
                    ),
                ),
                Return(Int(0)),
            ),
            App.localPut(
                Int(0),
                Bytes("balance"),
                App.localGet(Int(0), Bytes("balance")) - transfer_amount,
            ),
            App.localPut(
                Int(1),
                Bytes("balance"),
                App.localGet(Int(1), Bytes("balance")) + transfer_amount,
            ),
            Return(Int(1)),
        ]
    )

    program = Cond(
        [Txn.application_id() == Int(0), on_creation],
        [Txn.on_completion() == OnComplete.DeleteApplication, Return(can_delete)],
        [
            Txn.on_completion() == OnComplete.UpdateApplication,
            Return(is_contract_admin),
        ],
        [Txn.on_completion() == OnComplete.CloseOut, on_closeout],
        [Txn.on_completion() == OnComplete.OptIn, register],
        [Txn.application_args[0] == Bytes("pause"), pause],
        [Txn.application_args[0] == Bytes("set admin"), set_admin],
        [Txn.application_args[0] == Bytes("freeze"), freeze],
        [Txn.application_args[0] == Bytes("max balance"), max_balance],
        [Txn.application_args[0] == Bytes("lock until"), lock_until],
        [Txn.application_args[0] == Bytes("transfer group"), transfer_group],
        [Txn.application_args[0] == Bytes("mint"), mint],
        [Txn.application_args[0] == Bytes("burn"), burn],
        [Txn.application_args[0] == Bytes("transfer"), transfer],
    )

    return program


def clear_state_program():
    program = Seq(
        [
            App.globalPut(
                Bytes("reserve"),
                App.globalGet(Bytes("reserve"))
                + App.localGet(Int(0), Bytes("balance")),
            ),
            Return(Int(1)),
        ]
    )

    return program


if __name__ == "__main__":
    with open("security_token_approval.teal", "w") as f:
        compiled = compileTeal(approval_program(), mode=Mode.Application, version=2)
        f.write(compiled)

    with open("security_token_clear_state.teal", "w") as f:
        compiled = compileTeal(clear_state_program(), mode=Mode.Application, version=2)
        f.write(compiled)

Data Types and Constants

A PyTeal expression has one of the following two data types:

For example, all the transaction arguments (e.g. Arg(0)) are of type TealType.bytes. The first valid round of current transaction (Txn.first_valid()) is typed TealType.uint64.

Integers

Int(n) creates a TealType.uint64 constant, where n >= 0 and n < 2 ** 64.

Bytes

A byte slice is a binary string. There are several ways to encode a byte slice in PyTeal:

UTF-8

Byte slices can be created from UTF-8 encoded strings. For example:

Bytes("hello world")

Base16

Byte slices can be created from a RFC 4648#section-8 base16 encoded binary string, e.g. "0xA21212EF" or "A21212EF". For example:

Bytes("base16", "0xA21212EF")
Bytes("base16", "A21212EF") # "0x" is optional

Base32

Byte slices can be created from a RFC 4648#section-6 base32 encoded binary string with or without padding, e.g. "7Z5PWO2C6LFNQFGHWKSK5H47IQP5OJW2M3HA2QPXTY3WTNP5NU2MHBW27M".

Bytes("base32", "7Z5PWO2C6LFNQFGHWKSK5H47IQP5OJW2M3HA2QPXTY3WTNP5NU2MHBW27M")

Base64

Byte slices can be created from a RFC 4648#section-4 base64 encoded binary string, e.g. "Zm9vYmE=".

Bytes("base64", "Zm9vYmE=")

Type Checking

All PyTeal expressions are type checked at construction time, for example, running the following code triggers a TealTypeError:

Int(0) < Arg(0)

Since < (overloaded Python operator, see Arithmetic Operations for more details) requires both operands of type TealType.uint64, while Arg(0) is of type TealType.bytes.

Conversion

Converting a value to its corresponding value in the other data type is supported by the following two operators:

  • Itob(n): generate a TealType.bytes value from a TealType.uint64 value n
  • Btoi(b): generate a TealType.uint64 value from a TealType.bytes value b

Note: These operations are not meant to convert between human-readable strings and numbers. Itob produces a big-endian 8-byte encoding of an unsigned integer, not a human readable string. For example, Itob(Int(1)) will produce the string "\x00\x00\x00\x00\x00\x00\x00\x01" not the string "1".

Arithmetic Operations

An arithmetic expression is an expression that results in a TealType.uint64 value. In PyTeal, arithmetic expressions include integer and boolean operators (booleans are the integers 0 or 1). The table below summarized all arithmetic expressions in PyTeal.

Operator Overloaded Semantics Example
Lt(a, b) a < b 1 if a is less than b, 0 otherwise Int(1) < Int(5)
Gt(a, b) a > b 1 if a is greater than b, 0 otherwise Int(1) > Int(5)
Le(a, b) a <= b 1 if a is no greater than b, 0 otherwise Int(1) <= Int(5)
Ge(a, b) a >= b 1 if a is no less than b, 0 otherwise Int(1) >= Int(5)
Add(a, b) a + b a + b, error (panic) if overflow Int(1) + Int(5)
Minus(a, b) a - b a - b, error if underflow Int(5) - Int(1)
Mul(a, b) a * b a * b, error if overflow Int(2) * Int(3)
Div(a, b) a / b a / b, error if divided by zero Int(3) / Int(2)
Mod(a, b) a % b a % b, modulo operation Int(7) % Int(3)
Exp(a, b) a ** b a ** b, exponent operation Int(7) ** Int(3)
Eq(a, b) a == b 1 if a equals b, 0 otherwise Int(7) == Int(7)
Neq(a, b) a != b 0 if a equals b, 1 otherwise Int(7) != Int(7)
And(a, b)   1 if a > 0 && b > 0, 0 otherwise And(Int(1), Int(1))
Or(a, b)   1 if a > 0 || b > 0, 0 otherwise Or(Int(1), Int(0))
Not(a)   1 if a equals 0, 0 otherwise Not(Int(0))
BitwiseAnd(a,b) a & b a & b, bitwise and operation Int(1) & Int(3)
BitwiseOr(a,b) a | b a | b, bitwise or operation Int(2) | Int(5)
BitwiseXor(a,b) a ^ b a ^ b, bitwise xor operation Int(3) ^ Int(7)
BitwiseNot(a) ~a ~a, bitwise complement operation ~Int(1)

Most of the above operations take two TealType.uint64 values as inputs. In addition, Eq(a, b) (==) and Neq(a, b) (!=) also work for byte slices. For example, Arg(0) == Arg(1) and Arg(0) != Arg(1) are valid PyTeal expressions.

Both And and Or also support more than 2 arguments when called as functions:

  • And(a, b, ...)
  • Or(a, b, ...)

The associativity and precedence of the overloaded Python arithmetic operators are the same as the original python operators . For example:

  • Int(1) + Int(2) + Int(3) is equivalent to Add(Add(Int(1), Int(2)), Int(3))
  • Int(1) + Int(2) * Int(3) is equivalent to Add(Int(1), Mul(Int(2), Int(3)))

Byteslice Arithmetic

Byteslice arithemetic is available for Teal V4 and above. Byteslice arithmetic operators allow up to 512-bit arithmetic. In PyTeal, byteslice arithmetic expressions include TealType.Bytes values as arguments (with the exception of BytesZero) and must be 64 bytes or less. The table below summarizes the byteslize arithmetic operations in PyTeal.

Operator Return Type Example Example Result
BytesLt(a, b) TealType.uint64 BytesLt(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 0
BytesGt(a, b) TealType.uint64 BytesGt(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 1
BytesLe(a, b) TealType.uint64 BytesLe(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 0
BytesGe(a, b) TealType.uint64 BytesGe(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 1
BytesEq(a, b) TealType.uint64 BytesEq(Bytes("base16", "0xFF"), Bytes("base16", "0xFF")) 1
BytesNeq(a, b) TealType.uint64 BytesNeq(Bytes("base16", "0xFF"), Bytes("base16", "0xFF")) 0
BytesAdd(a, b) TealType.Bytes BytesAdd(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 0x01FD
BytesMinus(a, b) TealType.Bytes BytesMinus(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 0x01
BytesMul(a, b) TealType.Bytes BytesMul(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 0xFD02
BytesDiv(a, b) TealType.Bytes BytesDiv(Bytes("base16", "0xFF"), Bytes("base16", "0x11")) 0x0F
BytesMod(a, b) TealType.Bytes BytesMod(Bytes("base16", "0xFF"), Bytes("base16", "0x12")) 0x03
BytesAnd(a, b) TealType.Bytes BytesAnd(Bytes("base16", "0xBEEF"), Bytes("base16", "0x1337")) 0x1227
BytesOr(a, b) TealType.Bytes BytesOr(Bytes("base16", "0xBEEF"), Bytes("base16", "0x1337")) 0xBFFF
BytesXor(a, b) TealType.Bytes BytesXor(Bytes("base16", "0xBEEF"), Bytes("base16", "0x1337")) 0xADD8
BytesNot(a) TealType.Bytes BytesNot(Bytes("base16", "0xFF00")) 0x00FF
BytesZero(a) TealType.Bytes BytesZero(Int(4)) 0x00000000

Currently, byteslice arithmetic operations are not overloaded, and must be explicitly called.

Bit and Byte Operations

In addition to the standard arithmetic operators above, PyTeal also supports operations that manipulate the individual bits and bytes of PyTeal values.

To use these operations, you’ll need to provide an index specifying which bit or byte to access. These indexes have different meanings depending on whether you are manipulating integers or byte slices:

  • For integers, bit indexing begins with low-order bits. For example, the bit at index 4 of the integer 16 (000...0001000 in binary) is 1. Every other index has a bit value of 0. Any index less than 64 is valid, regardless of the integer’s value.

    Byte indexing is not supported for integers.

  • For byte strings, bit indexing begins at the first bit. For example, the bit at index 0 of the base16 byte string 0xf0 (11110000 in binary) is 1. Any index less than 4 has a bit value of 1, and any index 4 or greater has a bit value of 0. Any index less than 8 times the length of the byte string is valid.

    Likewise, byte indexing begins at the first byte of the string. For example, the byte at index 0 of that the base16 string 0xff00 (1111111100000000 in binary) is 255 (111111111 in binary), and the byte at index 1 is 0. Any index less than the length of the byte string is valid.

Bit Manipulation

The GetBit expression can extract individual bit values from integers and byte strings. For example,

GetBit(Int(16), Int(0)) # get the 0th bit of 16, produces 0
GetBit(Int(16), Int(4)) # get the 4th bit of 16, produces 1
GetBit(Int(16), Int(63)) # get the 63rd bit of 16, produces 0
GetBit(Int(16), Int(64)) # get the 64th bit of 16, invalid index

GetBit(Bytes("base16", "0xf0"), Int(0)) # get the 0th bit of 0xf0, produces 1
GetBit(Bytes("base16", "0xf0"), Int(7)) # get the 7th bit of 0xf0, produces 0
GetBit(Bytes("base16", "0xf0"), Int(8)) # get the 8th bit of 0xf0, invalid index

Additionally, the SetBit expression can modify individual bit values from integers and byte strings. For example,

SetBit(Int(0), Int(4), Int(1)) # set the 4th bit of 0 to 1, produces 16
SetBit(Int(4), Int(0), Int(1)) # set the 0th bit of 4 to 1, produces 5
SetBit(Int(4), Int(0), Int(0)) # set the 0th bit of 4 to 0, produces 4

SetBit(Bytes("base16", "0x00"), Int(0), Int(1)) # set the 0th bit of 0x00 to 1, produces 0x80
SetBit(Bytes("base16", "0x00"), Int(3), Int(1)) # set the 3rd bit of 0x00 to 1, produces 0x10
SetBit(Bytes("base16", "0x00"), Int(7), Int(1)) # set the 7th bit of 0x00 to 1, produces 0x01

Byte Manipulation

In addition to manipulating bits, individual bytes in byte strings can be manipulated.

The GetByte expression can extract individual bytes from byte strings. For example,

GetByte(Bytes("base16", "0xff00"), Int(0)) # get the 0th byte of 0xff00, produces 255
GetByte(Bytes("base16", "0xff00"), Int(1)) # get the 1st byte of 0xff00, produces 0
GetByte(Bytes("base16", "0xff00"), Int(2)) # get the 2nd byte of 0xff00, invalid index

GetByte(Bytes("abc"), Int(0)) # get the 0th byte of "abc", produces 97 (ASCII 'a')
GetByte(Bytes("abc"), Int(1)) # get the 1st byte of "abc", produces 98 (ASCII 'b')
GetByte(Bytes("abc"), Int(2)) # get the 2nd byte of "abc", produces 99 (ASCII 'c')

Additionally, the SetByte expression can modify individual bytes in byte strings. For example,

SetByte(Bytes("base16", "0xff00"), Int(0), Int(0)) # set the 0th byte of 0xff00 to 0, produces 0x0000
SetByte(Bytes("base16", "0xff00"), Int(0), Int(128)) # set the 0th byte of 0xff00 to 128, produces 0x8000

SetByte(Bytes("abc"), Int(0), Int(98)) # set the 0th byte of "abc" to 98 (ASCII 'b'), produces "bbc"
SetByte(Bytes("abc"), Int(1), Int(66)) # set the 1st byte of "abc" to 66 (ASCII 'B'), produces "aBc"

Byte Operators

TEAL byte slices are similar to strings and can be manipulated in the same way.

Length

The length of a byte slice can be obtained using the Len expression. For example:

Len(Bytes("")) # will produce 0
Len(Bytes("algorand")) # will produce 8

Concatenation

Byte slices can be combined using the Concat expression. This expression takes at least two arguments and produces a new byte slice consisting of each argument, one after another. For example:

Concat(Bytes("a"), Bytes("b"), Bytes("c")) # will produce "abc"

Substring Extraction

Byte slices can be extracted from other byte slices using the Substring and Extract expressions. These expressions are extremely similar, except one specifies a substring by start and end indexes, while the other uses a start index and length. Use whichever makes sense for your application.

Substring

The Substring expression can extract part of a byte slice given start and end indices. For example:

Substring(Bytes("algorand"), Int(2), Int(8)) # will produce "gorand"

Extract

Note

Extract is only available in TEAL version 5 or higher.

The Extract expression can extract part of a byte slice given the start index and length. For example:

Extract(Bytes("algorand"), Int(2), Int(6)) # will produce "gorand"

Manipulating Individual Bits and Bytes

The individual bits and bytes in a byte string can be extracted and changed. See Bit and Byte Operations for more information.

Transaction Fields and Global Parameters

PyTeal smart contracts can access properties of the current transaction and the state of the blockchain when they are running.

Transaction Fields

Information about the current transaction being evaluated can be obtained using the Txn object using the PyTeal expressions shown below.

Since numerous transaction fields exist, the fields are logically organized into tables by transaction type.

Fields by Transaction Type

Common Fields
Operator Type Min TEAL Version Notes
Txn.type() TealType.bytes 2  
Txn.type_enum() TealType.uint64 2 see table below
Txn.sender() TealType.bytes 2 32 byte address
Txn.fee() TealType.uint64 2 in microAlgos
Txn.first_valid() TealType.uint64 2 round number
Txn.last_valid() TealType.uint64 2 round number
Txn.note() TealType.bytes 2 transaction note in bytes
Txn.lease() TealType.bytes 2 transaction lease in bytes
Txn.group_index() TealType.uint64 2 position of this transaction within a transaction group, starting at 0
Txn.tx_id() TealType.bytes 2 the computed ID for this transaction, 32 bytes
Txn.rekey_to() TealType.bytes 2 32 byte address
Application Call
Operator Type Min TEAL Version Notes
Txn.application_id() TealType.uint64 2  
Txn.on_completion() TealType.uint64 2  
Txn.approval_program() TealType.bytes 2  
Txn.global_num_uints() TealType.uint64 3 Maximum global integers in app schema
Txn.global_num_byte_slices() TealType.uint64 3 Maximum global byte strings in app schema
Txn.local_num_uints() TealType.uint64 3 Maximum local integers in app schema
Txn.local_num_byte_slices() TealType.uint64 3 Maximum local byte strings in app schema
Txn.accounts TealType.bytes[] 2 Array of application accounts
Txn.assets TealType.uint64[] 3 Array of application assets
Txn.applications TealType.uint64[] 3 Array of applications
Txn.clear_state_program() TealType.bytes 2  
Txn.extra_program_pages() TealType.uint64 4 Number of extra program pages for app
Txn.application_args TealType.bytes[] 2 Array of application arguments
Txn.created_application_id() TealType.uint64 5 The ID of the newly created application in this transaction. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions.
Txn.logs TealType.bytes[] 5 Array of application logged items. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions.
Txn.last_log() TealType.bytes[] 6 The last message emitted. Empty bytes if none were emitted. Application mode only.
Asset Config
Operator Type Min TEAL Version Notes
Txn.config_asset() TealType.uint64 2 ID of asset being configured
Txn.config_asset_total() TealType.uint64 2  
Txn.config_asset_decimals() TealType.uint64 2  
Txn.config_asset_default_frozen() TealType.uint64 2  
Txn.config_asset_unit_name() TealType.bytes 2  
Txn.config_asset_name() TealType.bytes 2  
Txn.config_asset_url() TealType.bytes 2  
Txn.config_asset_metadata_hash() TealType.bytes 2  
Txn.config_asset_manager() TealType.bytes 2 32 byte address
Txn.config_asset_reserve() TealType.bytes 2 32 byte address
Txn.config_asset_freeze() TealType.bytes 2 32 byte address
Txn.config_asset_clawback() TealType.bytes 2 32 byte address
Txn.created_asset_id() TealType.uint64 5 The ID of the newly created asset in this transaction. In v5, only valid on inner transactions. >= v6 works with top-level and inner transactions.
Asset Freeze
Operator Type Min TEAL Version Notes
Txn.freeze_asset() TealType.uint64 2  
Txn.freeze_asset_account() TealType.bytes 2 32 byte address
Txn.freeze_asset_frozen() TealType.uint64 2  
Asset Transfer
Operator Type Min TEAL Version Notes
Txn.xfer_asset() TealType.uint64 2 ID of asset being transferred
Txn.asset_amount() TealType.uint64 2 value in Asset’s units
Txn.asset_sender() TealType.bytes 2 32 byte address, causes clawback of all value if sender is the clawback
Txn.asset_receiver() TealType.bytes 2 32 byte address
Txn.asset_close_to() TealType.bytes 2 32 byte address
Key Registration
Operator Type Min TEAL Version Notes
Txn.vote_pk() TealType.bytes 2 32 byte address
Txn.selection_pk() TealType.bytes 2 32 byte address
Txn.state_proof_pk TealType.bytes 6 64 byte state proof public key commitment.
Txn.vote_first() TealType.uint64 2  
Txn.vote_last() TealType.uint64 2  
Txn.vote_key_dilution() TealType.uint64 2  
Txn.nonparticipation() TealType.uint64 5 Marks an account nonparticipating for rewards
Payment
Operator Type Min TEAL Version Notes
Txn.receiver() TealType.bytes 2 32 byte address
Txn.amount() TealType.uint64 2 in microAlgos
Txn.close_remainder_to() TealType.bytes 2 32 byte address

Transaction Types

The Txn.type_enum() values can be checked using the TxnType enum:

Value Numerical Value Type String Description
TxnType.Unknown 0 unknown unknown type, invalid
TxnType.Payment 1 pay payment
TxnType.KeyRegistration 2 keyreg key registration
TxnType.AssetConfig 3 acfg asset config
TxnType.AssetTransfer 4 axfer asset transfer
TxnType.AssetFreeze 5 afrz asset freeze
TxnType.ApplicationCall 6 appl application call

Transaction Array Fields

Some of the exposed transaction fields are arrays with the type TealType.uint64[] or TealType.bytes[]. These fields are Txn.application_args, Txn.assets, Txn.accounts, Txn.applications, and InnerTxn.logs.

The length of these array fields can be found using the .length() method, and individual items can be accessed using bracket notation. For example:

Txn.application_args.length() # get the number of application arguments in the transaction
Txn.application_args[0] # get the first application argument
Txn.application_args[1] # get the second application argument

# as of TEAL v5, PyTeal expressions can be used to dynamically index into array properties as well
Txn.application_args[Txn.application_args.length() - Int(1)] # get the last application argument
Special case: Txn.accounts and Txn.applications

The Txn.accounts and Txn.applications arrays are special cases. Normal arrays in PyTeal are 0-indexed, but these are 1-indexed with special values at index 0.

For the accounts array, Txn.accounts[0] is always equivalent to Txn.sender().

For the applications array, Txn.applications[0] is always equivalent to Txn.application_id().

IMPORTANT: Since these arrays are 1-indexed, their lengths are handled differently. For example, if Txn.accounts.length() or Txn.applications.length() is 2, then indexes 0, 1, and 2 will be present. In fact, the index 0 will always evaluate to the special values above, even when length() is 0.

Atomic Transfer Groups

Atomic Transfers are irreducible batch transactions that allow groups of transactions to be submitted at one time. If any of the transactions fail, then all the transactions will fail. PyTeal allows programs to access information about the transactions in an atomic transfer group using the Gtxn object. This object acts like a list of TxnObject, meaning all of the above transaction fields on Txn are available on the elements of Gtxn. For example:

Gtxn[0].sender() # get the sender of the first transaction in the atomic transfer group
Gtxn[1].receiver() # get the receiver of the second transaction in the atomic transfer group

# as of TEAL v3, PyTeal expressions can be used to dynamically index into Gtxn as well
Gtxn[Txn.group_index() - Int(1)].sender() # get the sender of the previous transaction in the atomic transfer group

Gtxn is zero-indexed and the maximum size of an atomic transfer group is 16. The size of the current transaction group is available as Global.group_size(). A standalone transaction will have a group size of 1.

To find the current transaction’s index in the transfer group, use Txn.group_index(). If the current transaction is standalone, it’s group index will be 0.

Inner Transactions

Note

Inner transactions are only available in TEAL version 5 or higher.

Inner transactions can be created and submitted with expressions from the InnerTxnBuilder class. The properties of the most recently submitted inner transaction can be accessed using the InnerTxn object. This object is an instance of TxnObject, meaning all of the above transaction fields on Txn are available on InnerTxn as well.

Global Parameters

Information about the current state of the blockchain can be obtained using the following Global expressions:

Operator Type Min TEAL Version Notes
Global.min_txn_fee() TealType.uint64 2 in microAlgos
Global.min_balance() TealType.uint64 2 in mircoAlgos
Global.max_txn_life() TealType.uint64 2 number of rounds
Global.zero_address() TealType.bytes 2 32 byte address of all zero bytes
Global.group_size() TealType.uint64 2 number of txns in this atomic transaction group, at least 1
Global.logic_sig_version() TealType.uint64 2 the maximum supported TEAL version
Global.round() TealType.uint64 2 the current round number
Global.latest_timestamp() TealType.uint64 2 the latest confirmed block UNIX timestamp
Global.current_application_id() TealType.uint64 2 the ID of the current application executing
Global.creator_address() TealType.bytes 3 32 byte address of the creator of the current application
Global.current_application_address() TealType.bytes 5 32 byte address of the current application controlled account
Global.group_id() TealType.bytes 5 32 byte ID of the current transaction group

Cryptographic Primitives

Algorand Smart Contracts support 4 cryptographic primitives, including 3 cryptographic hash functions and 1 digital signature verification. Each of these cryptographic primitives is associated with a cost, which is a number indicating its relative performance overhead comparing with simple TEAL operations such as addition and substraction. Simple TEAL opcodes have cost 1, and more advanced cryptographic operations have a larger cost. Below is how you express cryptographic primitives in PyTeal:

Operator Cost Description
Sha256(e) 35 SHA-256 hash function, produces 32 bytes
Keccak256(e) 130 Keccak-256 hash funciton, produces 32 bytes
Sha512_256(e) 45 SHA-512/256 hash function, produces 32 bytes
Ed25519Verify(d, s, p) 1900* 1 if s is the signature of d signed by private key p, else 0

* Ed25519Verify is only available in signature mode.

Note the cost amount is accurate for version 2 of TEAL and higher.

These cryptographic primitives cover the most used ones in blockchains and cryptocurrencies. For example, Bitcoin uses SHA-256 for creating Bitcoin addresses; Alogrand uses ed25519 signature scheme for authorization and uses SHA-512/256 hash function for creating contract account addresses from TEAL bytecode.

Scratch Space

Scratch space is a temporary place to store values for later use in your program. It is temporary because any changes to scratch space do not persist beyond the current tranasaction. Scratch space can be used in both Application and Signature mode.

Scratch space consists of 256 scratch slots, each capable of storing one integer or byte slice. When using the ScratchVar class to work with scratch space, a slot is automatically assigned to each variable.

Writing and Reading

To write to scratch space, first create a ScratchVar object and pass in the TealType of the values that you will store there. It is possible to create a ScratchVar that can store both integers and byte slices by passing no arguments to the ScratchVar constructor, but note that no type checking takes places in this situation. It is also possible to manually specify which slot ID the compiler should assign the scratch slot to in the TEAL code. If no slot ID is specified, the compiler will assign it to any available slot.

To write or read values, use the corresponding ScratchVar.store or ScratchVar.load methods.

For example:

myvar = ScratchVar(TealType.uint64) # assign a scratch slot in any available slot
program = Seq([
    myvar.store(Int(5)),
    Assert(myvar.load() == Int(5))
])
anotherVar = ScratchVar(TealType.bytes, 4) # assign this scratch slot to slot #4

Loading Values from Group Transactions

Since TEAL version 4 and above, programs can load values from transactions within an atomic group transaction. For instance, you can import values from the scratch space of another application call, and you can access the generated ID of a new application or asset. These operations are only permitted in application mode.

Accessing IDs of New Apps and Assets

The generated ID of an asset or application from a creation transaction in the current atomic group can be accessed using the GeneratedID expression. The specified transaction index may be a Python int or a PyTeal expression that must be evaluated to a uint64 at runtime. The transaction index must be less than the index of the current transaction and the maximum allowed group size (16).

For example:

GeneratedID(0) # retrieves the ID from the 0th transaction in current group
GeneratedID(Int(10)) # retrieves the ID from the 10th transaction in group

Note that if the index is a Python int, it is interpreted as an immediate value (uint8) and will be translated to a TEAL gaid op. Otherwise, it will be translated to a TEAL gaids op.

Loading Scratch Slots

The scratch value from another transaction in the current atomic group can be accessed using the ImportScratchValue expression. The transaction index may be a Python int or a PyTeal expression that must be evaluated to a uint64 at runtime, and the scratch slot ID to load from must be a Python int. The transaction index must be less than the index of the current transaction and the maximum allowed group size (16), and the slot ID must be less than the maximum number of scratch slots (256).

For example, assume an atomic transaction group contains app calls to the following applications, where App A is called from the first transaction (index 0) and App B is called from the second or later transaction. Then the greeting value will be successfully passed between the two contracts.

App A:

# App is called at transaction index 0
greeting = ScratchVar(TealType.bytes, 20) # this variable will live in scratch slot 20
program = Seq([
    If(Txn.sender() == App.globalGet(Bytes("creator")))
    .Then(greeting.store(Bytes("hi creator!")))
    .Else(greeting.store(Bytes("hi user!"))),
    Return(Int(1))
])

App B:

greetingFromPreviousApp = ImportScratchValue(0, 20) # loading scratch slot 20 from the transaction at index 0
program = Seq([
    # not shown: make sure that the transaction at index 0 is an app call to App A
    App.globalPut(Bytes("greeting from prev app"), greetingFromPreviousApp),
    Return(Int(1))
])

Note that if the index is a Python int, it is interpreted as an immediate value (uint8) and will be translated to a TEAL gload op. Otherwise, it will be translated to a TEAL gloads op.

Control Flow

PyTeal provides several control flow expressions to create programs.

Exiting the Program: Approve and Reject

Note

The Approve and Reject expressions are only available in TEAL version 4 or higher. Prior to this, Return(Int(1)) is equivalent to Approve() and Return(Int(0)) is equivalent to Reject().

The Approve and Reject expressions cause the program to immediately exit. If Approve is used, then the execution is marked as successful, and if Reject is used, then the execution is marked as unsuccessful.

These expressions also work inside subroutines.

Chaining Expressions: Seq

The Seq expression can be used to create a sequence of multiple expressions. It’s arguments are the expressions to include in the sequence, either as a variable number of arguments, or as a single list

For example:

Seq(
    App.globalPut(Bytes("creator"), Txn.sender()),
    Return(Int(1))
)

A Seq expression will take on the value of its last expression. Additionally, all expressions in a Seq expression, except the last one, must not return anything (e.g. evaluate to TealType.none). This restriction is in place because intermediate values must not add things to the TEAL stack. As a result, the following is an invalid sequence:

Invalid Seq expression
Seq(
    Txn.sender(),
    Return(Int(1))
)

If you must include an operation that returns a value in the earlier part of a sequence, you can wrap the value in a Pop expression to discard it. For example,

Seq(
    Pop(Txn.sender()),
    Return(Int(1))
)

Simple Branching: If

In an If expression,

If(test-expr, then-expr, else-expr)

the test-expr is always evaluated and needs to be typed TealType.uint64. If it results in a value greater than 0, then the then-expr is evaluated. Otherwise, else-expr is evaluated. Note that then-expr and else-expr must evaluate to the same type (e.g. both TealType.uint64).

You may also invoke an If expression without an else-expr:

If(test-expr, then-expr)

In this case, then-expr must be typed TealType.none.

There is also an alternate way to write an If expression that makes reading complex statements easier to read.

If(test-expr)
.Then(then-expr)
.ElseIf(test-expr)
.Then(then-expr)
.Else(else-expr)

Checking Conditions: Assert

The Assert expression can be used to ensure that conditions are met before continuing the program. The syntax for Assert is:

Assert(test-expr)

If test-expr is always evaluated and must be typed TealType.uint64. If test-expr results in a value greater than 0, the program continues. Otherwise, the program immediately exits and indicates that it encountered an error.

Example:

Assert(Txn.type_enum() == TxnType.Payment)

The above example will cause the program to immediately fail with an error if the transaction type is not a payment.

Chaining Tests: Cond

A Cond expression chains a series of tests to select a result expression. The syntax of Cond is:

Cond([test-expr-1, body-1],
     [test-expr-2, body-2],
     . . . )

Each test-expr is evaluated in order. If it produces 0, the paired body is ignored, and evaluation proceeds to the next test-expr. As soon as a test-expr produces a true value (> 0), its body is evaluated to produce the value for this Cond expression. If none of test-expr s evaluates to a true value, the Cond expression will be evaluated to err, a TEAL opcode that causes the runtime panic.

In a Cond expression, each test-expr needs to be typed TealType.uint64. A body could be typed either TealType.uint64 or TealType.bytes. However, all body s must have the same data type. Otherwise, a TealTypeError is triggered.

Example:

Cond([Global.group_size() == Int(5), bid],
     [Global.group_size() == Int(4), redeem],
     [Global.group_size() == Int(1), wrapup])

This PyTeal code branches on the size of the atomic transaction group.

Looping: While

Note

This expression is only available in TEAL version 4 or higher.

The While expression can be used to create simple loops in PyTeal. The syntax of While is:

While(loop-condition).Do(loop-body)

The loop-condition expression must evaluate to TealType.uint64, and the loop-body expression must evaluate to TealType.none.

The loop-body expression will continue to execute as long as loop-condition produces a true value (> 0).

For example, the following code uses ScratchVar to iterate through every transaction in the current group and sum up all of their fees.

totalFees = ScratchVar(TealType.uint64)
i = ScratchVar(TealType.uint64)

Seq([
    i.store(Int(0)),
    totalFees.store(Int(0)),
    While(i.load() < Global.group_size()).Do(Seq([
        totalFees.store(totalFees.load() + Gtxn[i.load()].fee()),
        i.store(i.load() + Int(1))
    ]))
])

Looping: For

Note

This expression is only available in TEAL version 4 or higher.

Similar to While, the For expression can also be used to create loops in PyTeal. The syntax of For is:

For(loop-start, loop-condition, loop-step).Do(loop-body)

The loop-start, loop-step, and loop-body expressions must evaluate to TealType.none, and the the loop-condition expression must evaluate to TealType.uint64.

When a For expression is executed, loop-start is executed first. Then the expressions loop-condition, loop-body, and loop-step will continue to execute in order as long as loop-condition produces a true value (> 0).

For example, the following code uses ScratchVar to iterate through every transaction in the current group and sum up all of their fees. The code here is functionally equivalent to the While loop example above.

totalFees = ScratchVar(TealType.uint64)
i = ScratchVar(TealType.uint64)

Seq([
    totalFees.store(Int(0)),
    For(i.store(Int(0)), i.load() < Global.group_size(), i.store(i.load() + Int(1))).Do(
        totalFees.store(totalFees.load() + Gtxn[i.load()].fee())
    )
])

Exiting Loops: Continue and Break

The expressions Continue and Break can be used to exit While and For loops in different ways.

When Continue is present in the loop body, it instructs the program to skip the remainder of the loop body. The loop may continue to execute as long as its condition remains true.

For example, the code below iterates though every transaction in the current group and counts how many are payments, using the Continue expression.

numPayments = ScratchVar(TealType.uint64)
i = ScratchVar(TealType.uint64)

Seq([
    numPayments.store(Int(0)),
    For(i.store(Int(0)), i.load() < Global.group_size(), i.store(i.load() + Int(1))).Do(Seq([
        If(Gtxn[i.load()].type_enum() != TxnType.Payment)
        .Then(Continue()),
        numPayments.store(numPayments.load() + Int(1))
    ]))
])

When Break is present in the loop body, it instructs the program to completely exit the current loop. The loop will not continue to execute, even if its condition remains true.

For example, the code below finds the index of the first payment transaction in the current group, using the Break expression.

firstPaymentIndex = ScratchVar(TealType.uint64)
i = ScratchVar(TealType.uint64)

Seq([
    # store a default value in case no payment transactions are found
    firstPaymentIndex.store(Global.group_size()),
    For(i.store(Int(0)), i.load() < Global.group_size(), i.store(i.load() + Int(1))).Do(
        If(Gtxn[i.load()].type_enum() == TxnType.Payment)
        .Then(Seq([
            firstPaymentIndex.store(i.load()),
            Break()
        ]))
    ),
    # assert that a payment was found
    Assert(firstPaymentIndex.load() < Global.group_size())
])

Subroutines

Note

Subroutines are only available in TEAL version 4 or higher.

A subroutine is section of code that can be called multiple times from within a program. Subroutines are PyTeal’s equivalent to functions. Subroutines can accept any number of arguments, and these arguments must be PyTeal expressions. Additionally, a subroutine may return a single value, or no value.

Creating Subroutines

To create a subroutine, apply the Subroutine function decorator to a Python function which implements the subroutine. This decorator takes one argument, which is the return type of the subroutine. TealType.none indicates that the subroutine does not return a value, and any other type (e.g. TealType.uint64 or TealType.bytes) indicates the return type of the single value the subroutine returns.

For example,

@Subroutine(TealType.uint64)
def isEven(i):
    return i % Int(2) == Int(0)

Calling Subroutines

To call a subroutine, simply call it like a normal Python function and pass in its arguments. For example,

App.globalPut(Bytes("value_is_even"), isEven(Int(10)))

Recursion

Recursion with subroutines is also possible. For example, the subroutine below also checks if its argument is even, but uses recursion to do so.

@Subroutine(TealType.uint64)
def recursiveIsEven(i):
    return (
        If(i == Int(0))
        .Then(Int(1))
        .ElseIf(i == Int(1))
        .Then(Int(0))
        .Else(recursiveIsEven(i - Int(2)))
    )

Exiting Subroutines

The Return expression can be used to explicitly return from a subroutine.

If the subroutine does not return a value, Return should be called with no arguments. For example, the subroutine below asserts that the first payment transaction in the current group has a fee of 0:

@Subroutine(TealType.none)
def assertFirstPaymentHasZeroFee():
    i = ScratchVar(TealType.uint64)

    return Seq([
        For(i.store(Int(0)), i.load() < Global.group_size(), i.store(i.load() + Int(1))).Do(
            If(Gtxn[i.load()].type_enum() == TxnType.Payment)
            .Then(Seq([
                Assert(Gtxn[i.load()].fee() == Int(0)),
                Return()
            ]))
        ),
        # no payments found
        Err()
    ])

Otherwise if the subroutine does return a value, that value should be the argument to the Return expression. For example, the subroutine below checks whether the current group contains a payment transaction:

@Subroutine(TealType.uint64)
def hasPayment():
    i = ScratchVar(TealType.uint64)

    return Seq([
        For(i.store(Int(0)), i.load() < Global.group_size(), i.store(i.load() + Int(1))).Do(
            If(Gtxn[i.load()].type_enum() == TxnType.Payment)
            .Then(Return(Int(1)))
        ),
        Return(Int(0))
    ])

Return can also be called from the main program. In this case, a single integer argument should be provided, which is the success value for the current execution. A true value (> 0) is equivalent to Approve, and a false value is equivalent to Reject.

State Access and Manipulation

PyTeal can be used to write Stateful Algorand Smart Contracts as well. Stateful contracts, also known as applications, can access and manipulate state on the Algorand blockchain.

State consists of key-value pairs, where keys are byte slices and values can be integers or byte slices. There are multiple types of state that an application can use.

State Operation Table

Context Write Read Delete Check If Exists
Current App Global App.globalPut App.globalGet App.globalDel App.globalGetEx
Current App Local App.localPut App.localGet App.localDel App.localGetEx
Other App Global   App.globalGetEx   App.globalGetEx
Other App Local   App.localGetEx   App.localGetEx

Global State

Global state consists of key-value pairs that are stored in the application’s global context. It can be manipulated as follows:

Writing Global State

To write to global state, use the App.globalPut function. The first argument is the key to write to, and the second argument is the value to write. For example:

App.globalPut(Bytes("status"), Bytes("active")) # write a byte slice
App.globalPut(Bytes("total supply"), Int(100)) # write a uint64

Reading Global State

To read from global state, use the App.globalGet function. The only argument it takes is the key to read from. For example:

App.globalGet(Bytes("status"))
App.globalGet(Bytes("total supply"))

If you try to read from a key that does not exist in your app’s global state, the integer 0 is returned.

Deleting Global State

To delete a key from global state, use the App.globalDel function. The only argument it takes is the key to delete. For example:

App.globalDel(Bytes("status"))
App.globalDel(Bytes("total supply"))

If you try to delete a key that does not exist in your app’s global state, nothing happens.

Local State

Local state consists of key-value pairs that are stored in a unique context for each account that has opted into your application. As a result, you will need to specify an account when manipulating local state. This is done by passing in the address of an account. In order to read or manipulate an account’s local state, that account must be presented in the Txn.accounts array.

Note: The Txn.accounts array does not behave like a normal array. It’s actually a 1-indexed array with a special value at index 0, the sender’s account. See Special case: Txn.accounts and Txn.applications for more details.

Writing Local State

To write to the local state of an account, use the App.localPut function. The first argument is the address of the account to write to, the second argument is the key to write to, and the third argument is the value to write. For example:

App.localPut(Txn.sender(), Bytes("role"), Bytes("admin")) # write a byte slice to the sender's account
App.localPut(Txn.sender(), Bytes("balance"), Int(10)) # write a uint64 to the sender's account
App.localPut(Txn.accounts[1], Bytes("balance"), Int(10)) # write a uint64 to Txn.account[1]

Note: It is only possible to write to the local state of an account if that account has opted into your application. If the account has not opted in, the program will fail with an error. The function App.optedIn can be used to check if an account has opted into an app.

Reading Local State

To read from the local state of an account, use the App.localGet function. The first argument is the address of the account to read from, and the second argument is the key to read. For example:

App.localGet(Txn.sender(), Bytes("role")) # read from the sender's account
App.localGet(Txn.sender(), Bytes("balance")) # read from the sender's account
App.localGet(Txn.accounts[1], Bytes("balance")) # read from Txn.accounts[1]

If you try to read from a key that does not exist in your app’s global state, the integer 0 is returned.

Deleting Local State

To delete a key from local state of an account, use the App.localDel function. The first argument is the address of the corresponding account, and the second argument is the key to delete. For example:

App.localDel(Txn.sender(), Bytes("role")) # delete "role" from the sender's account
App.localDel(Txn.sender(), Bytes("balance")) # delete "balance" from the sender's account
App.localDel(Txn.accounts[1], Bytes("balance")) # delete "balance" from Txn.accounts[1]

If you try to delete a key that does not exist in the account’s local state, nothing happens.

External State

The above functions allow an app to read and write state in its own context. Additionally, it’s possible for applications to read state written by other applications. This is possible using the App.globalGetEx and App.localGetEx functions.

Unlike the other state access functions, App.globalGetEx and App.localGetEx return a MaybeValue. This value cannot be used directly, but has methods MaybeValue.hasValue() and MaybeValue.value(). If the key being accessed exists in the context of the app being read, hasValue() will return 1 and value() will return its value. Otherwise, hasValue() and value() will return 0.

Note: Even though the MaybeValue returned by App.globalGetEx and App.localGetEx cannot be used directly, it must be included in the application before hasValue() and value() are called on it. You will probably want to use Seq to do this.

Since these functions are the only way to check whether a key exists, it can be useful to use them in the current application’s context too.

External Global

To read a value from the global state of another application, use the App.globalGetEx function.

In order to use this function you need to pass in an integer that represents an application to read from. This integer corresponds to an actual application ID that appears in the Txn.applications array.

Note: The Txn.applications array does not behave like a normal array. It’s actually a 1-indexed array with a special value at index 0, the current application’s ID. See Special case: Txn.accounts and Txn.applications for more details.

Now that you have an integer that represents an application to read from, pass this as the first argument to App.globalGetEx, and pass the key to read as the second argument. For example:

# get "status" from the global context of Txn.applications[0] (the current app)
# if "status" has not been set, returns "none"
myStatus = App.globalGetEx(Txn.applications[0], Bytes("status"))

program = Seq([
    myStatus,
    If(myStatus.hasValue(), myStatus.value(), Bytes("none"))
])

# get "status" from the global context of Txn.applications[1]
# if "status" has not been set, returns "none"
otherStatus = App.globalGetEx(Txn.applications[1], Bytes("status"))
program = Seq([
    otherStatus,
    If(otherStatus.hasValue(), otherStatus.value(), Bytes("none"))
])

# get "total supply" from the global context of Txn.applications[1]
# if "total supply" has not been set, returns the default value of 0
otherSupply = App.globalGetEx(Txn.applications[1], Bytes("total supply"))
program = Seq([
    otherSupply,
    otherSupply.value()
])

External Local

To read a value from an account’s local state for another application, use the App.localGetEx function.

The first argument is the address of the account to read from (in the same format as App.localGet), the second argument is the ID of the application to read from, and the third argument is the key to read.

Note: The second argument is the actual ID of the application to read from, not an index into Txn.applications. This means that you can read from any application that the account has opted into, not just applications included in Txn.applications. The ID 0 is still a special value that refers to the ID of the current application, but you could also use Global.current_application_id() or Txn.application_id() to refer to the current application.

For example:

# get "role" from the local state of Txn.accounts[0] (the sender) for the current app
# if "role" has not been set, returns "none"
myAppSenderRole = App.localGetEx(Txn.accounts[0], Int(0), Bytes("role"))
program = Seq([
    myAppSenderRole,
    If(myAppSenderRole.hasValue(), myAppSenderRole.value(), Bytes("none"))
])

# get "role" from the local state of Txn.accounts[1] for the current app
# if "role" has not been set, returns "none"
myAppOtherAccountRole = App.localGetEx(Txn.accounts[1], Int(0), Bytes("role"))
program = Seq([
    myAppOtherAccountRole,
    If(myAppOtherAccountRole.hasValue(), myAppOtherAccountRole.value(), Bytes("none"))
])

# get "role" from the local state of Txn.accounts[0] (the sender) for the app with ID 31
# if "role" has not been set, returns "none"
otherAppSenderRole = App.localGetEx(Txn.accounts[0], Int(31), Bytes("role"))
program = Seq([
    otherAppSenderRole,
    If(otherAppSenderRole.hasValue(), otherAppSenderRole.value(), Bytes("none"))
])

# get "role" from the local state of Txn.accounts[1] for the app with ID 31
# if "role" has not been set, returns "none"
otherAppOtherAccountRole = App.localGetEx(Txn.accounts[1], Int(31), Bytes("role"))
program = Seq([
    otherAppOtherAccountRole,
    If(otherAppOtherAccountRole.hasValue(), otherAppOtherAccountRole.value(), Bytes("none"))
])

Asset Information

In addition to manipulating state on the blockchain, stateful smart contracts can also look up information about assets and account balances.

Algo Balances

The Balance expression can be used to look up an account’s balance in microAlgos (1 Algo = 1,000,000 microAlgos). For example,

senderBalance = Balance(Txn.sender()) # get the balance of the sender
account1Balance = Balance(Txn.accounts[1]) # get the balance of Txn.accounts[1]

The MinBalance expression can be used to find an account’s minimum balance. This amount is also in microAlgos. For example,

senderMinBalance = MinBalance(Txn.sender()) # get the minimum balance of the sender by passing the account address (bytes)
account1MinBalance = MinBalance(Txn.accounts[1]) # get the minimum balance of Txn.accounts[1] by passing the account address (bytes)

Additionally, Balance and MinBalance can be used together to calculate how many Algos an account can spend without closing. For example,

senderSpendableBalance = Balance(Txn.sender()) - MinBalance(Txn.sender()) # calculate how many Algos the sender can spend
account1SpendableBalance = Balance(Txn.accounts[1]) - MinBalance(Txn.accounts[1]) # calculate how many Algos Txn.accounts[1] can spend

Asset Holdings

In addition to Algos, the Algorand blockchain also supports additional on-chain assets called Algorand Standard Assets (ASAs). The AssetHolding group of expressions can be used to look up information about the ASAs that an account holds.

Similar to external state expressions, these expression return a MaybeValue. This value cannot be used directly, but has methods MaybeValue.hasValue() and MaybeValue.value().

If the account has opted into the asset being looked up, hasValue() will return 1 and value() will return the value being looked up (either the asset’s balance or frozen status). Otherwise, hasValue() and value() will return 0.

Balances

The AssetHolding.balance expression can be used to look up how many units of an asset an account holds. For example,

# get the balance of the sender for asset `Txn.assets[0]`
# if the account is not opted into that asset, returns 0
senderAssetBalance = AssetHolding.balance(Txn.sender(), Txn.assets[0])
program = Seq([
    senderAssetBalance,
    senderAssetBalance.value()
])

# get the balance of Txn.accounts[1] for asset `Txn.assets[1]`
# if the account is not opted into that asset, exit with an error
account1AssetBalance = AssetHolding.balance(Txn.accounts[1], Txn.assets[1])
program = Seq([
    account1AssetBalance,
    Assert(account1AssetBalance.hasValue()),
    account1AssetBalance.value()
])

Frozen

The AssetHolding.frozen expression can be used to check if an asset is frozen for an account. A value of 1 indicates frozen and 0 indicates not frozen. For example,

# get the frozen status of the sender for asset `Txn.assets[0]`
# if the account is not opted into that asset, returns 0
senderAssetFrozen = AssetHolding.frozen(Txn.sender(), Txn.assets[0])
program = Seq([
    senderAssetFrozen,
    senderAssetFrozen.value()
])

# get the frozen status of Txn.accounts[1] for asset `Txn.assets[1]`
# if the account is not opted into that asset, exit with an error
account1AssetFrozen = AssetHolding.frozen(Txn.accounts[1], Txn.assets[1])
program = Seq([
    account1AssetFrozen,
    Assert(account1AssetFrozen.hasValue()),
    account1AssetFrozen.value()
])

Asset Parameters

Every ASA has parameters that contain information about the asset and how it behaves. These parameters can be read by TEAL applications for any asset in the Txn.assets array.

The AssetParam group of expressions are used to access asset parameters. Like AssetHolding, these expressions return a MaybeValue.

The hasValue() method will return 0 only if the asset being looked up does not exist (i.e. the ID in Txn.assets does not represent an asset).

For optional parameters that are not set, hasValue() will still return 1 and value() will return a zero-length byte string (all optional parameters are TealType.bytes).

The different parameters that can be accessed are summarized by the table below. More information about each parameter can be found on the Algorand developer website.

Expression Type Description
AssetParam.total() TealType.uint64 The total number of units of the asset.
AssetParam.decimals() TealType.uint64 The number of decimals the asset should be formatted with.
AssetParam.defaultFrozen() TealType.uint64 Whether the asset is frozen by default.
AssetParam.unitName() TealType.bytes The name of the asset’s units.
AssetParam.name() TealType.bytes The name of the asset.
AssetParam.url() TealType.bytes A URL associated with the asset.
AssetParam.metadataHash() TealType.bytes A 32-byte hash associated with the asset.
AssetParam.manager() TealType.bytes The address of the asset’s manager account.
AssetParam.reserve() TealType.bytes The address of the asset’s reserve account.
AssetParam.freeze() TealType.bytes The address of the asset’s freeze account.
AssetParam.clawback() TealType.bytes The address of the asset’s clawback account.

Here’s an example that uses an asset parameter:

# get the total number of units for asset `Txn.assets[0]`
# if the asset is invalid, exit with an error
assetTotal = AssetParam.total(Txn.assets[0])

program = Seq([
    assetTotal,
    Assert(assetTotal.hasValue()),
    assetTotal.value()
])

TEAL Versions

Each version of PyTeal compiles contracts for a specific version of TEAL. Newer versions of TEAL introduce new opcodes and transaction fields, so PyTeal must be updated to support these new features. Below is a table which shows the relationship between TEAL and PyTeal versions.

TEAL Version PyTeal Version
1 <= 0.5.4
2 >= 0.6.0
3 >= 0.7.0
4 >= 0.8.0

In order to support TEAL v2, PyTeal v0.6.0 breaks backward compatibility with v0.5.4. PyTeal programs written for PyTeal version 0.5.4 and below will not compile properly and most likely will display an error of the form AttributeError: * object has no attribute 'teal'.

WARNING: before updating PyTeal to a version with generates TEAL v2 contracts and fixing the programs to use the global function compileTeal rather the class method .teal(), make sure your program abides by the TEAL safety guidelines https://developer.algorand.org/docs/reference/teal/guidelines/. Changing a v1 TEAL program to a v2 TEAL program without any code changes is insecure because v2 TEAL programs allow rekeying. Specifically, you must add a check that the RekeyTo property of any transaction is set to the zero address when updating an older PyTeal program from v0.5.4 and below.

PyTeal Package

pyteal.Txn = <pyteal.TxnObject object>

The current transaction being evaluated. This is an instance of TxnObject.

pyteal.Gtxn = <pyteal.TxnGroup object>

The current group of transactions being evaluated. This is an instance of TxnGroup.

pyteal.InnerTxn = <pyteal.TxnObject object>

The most recently submitted inner transaction. This is an instance of TxnObject.

class pyteal.Expr

Bases: abc.ABC

Abstract base class for PyTeal expressions.

And(other: pyteal.Expr) → pyteal.Expr

Take the logical And of this expression and another one.

This expression must evaluate to uint64.

This is the same as using And() with two arguments.

Or(other: pyteal.Expr) → pyteal.Expr

Take the logical Or of this expression and another one.

This expression must evaluate to uint64.

This is the same as using Or() with two arguments.

getDefinitionTrace() → List[str]
has_return() → bool

Check if this expression always returns from the current subroutine or program.

type_of() → pyteal.TealType

Get the return type of this expression.

class pyteal.LeafExpr

Bases: pyteal.Expr

Leaf expression base class.

has_return()

Check if this expression always returns from the current subroutine or program.

class pyteal.Addr(address: str)

Bases: pyteal.LeafExpr

An expression that represents an Algorand address.

__init__(address: str) → None

Create a new Addr expression.

Parameters:address – A string containing a valid base32 Algorand address
type_of()

Get the return type of this expression.

class pyteal.Bytes(arg1: Union[str, bytes, bytearray], arg2: str = None)

Bases: pyteal.LeafExpr

An expression that represents a byte string.

__init__(arg1: Union[str, bytes, bytearray], arg2: str = None) → None

Create a new byte string.

Depending on the encoding, there are different arguments to pass:

For UTF-8 strings:
Pass the string as the only argument. For example, Bytes("content").
For raw bytes or bytearray objects:
Pass the bytes or bytearray as the only argument. For example, Bytes(b"content").
For base16, base32, or base64 strings:
Pass the base as the first argument and the string as the second argument. For example, Bytes("base16", "636F6E74656E74"), Bytes("base32", "ORFDPQ6ARJK"), Bytes("base64", "Y29udGVudA==").
Special case for base16:
The prefix “0x” may be present in a base16 byte string. For example, Bytes("base16", "0x636F6E74656E74").
type_of()

Get the return type of this expression.

class pyteal.Int(value: int)

Bases: pyteal.LeafExpr

An expression that represents a uint64.

__init__(value: int) → None

Create a new uint64.

Parameters:value – The integer value this uint64 will represent. Must be a positive value less than 2**64.
type_of()

Get the return type of this expression.

class pyteal.EnumInt(name: str)

Bases: pyteal.LeafExpr

An expression that represents uint64 enum values.

__init__(name: str) → None

Create an expression to reference a uint64 enum value.

Parameters:name – The name of the enum value.
type_of()

Get the return type of this expression.

class pyteal.MethodSignature(methodName: str)

Bases: pyteal.LeafExpr

An expression that represents an ABI method selector

__init__(methodName: str) → None

Create a new method selector for ABI method call.

Parameters:methodName – A string containing a valid ABI method signature
type_of() → pyteal.TealType

Get the return type of this expression.

class pyteal.Arg(index: Union[int, pyteal.Expr])

Bases: pyteal.LeafExpr

An expression to get an argument when running in signature verification mode.

__init__(index: Union[int, pyteal.Expr]) → None

Get an argument for this program.

Should only be used in signature verification mode. For application mode arguments, see TxnObject.application_args.

Parameters:index – The index of the argument to get. The index must be between 0 and 255 inclusive. Starting in TEAL v5, the index may be a PyTeal expression that evaluates to uint64.
type_of()

Get the return type of this expression.

class pyteal.TxnType

Bases: object

Enum of all possible transaction types.

ApplicationCall = <pyteal.EnumInt object>
AssetConfig = <pyteal.EnumInt object>
AssetFreeze = <pyteal.EnumInt object>
AssetTransfer = <pyteal.EnumInt object>
KeyRegistration = <pyteal.EnumInt object>
Payment = <pyteal.EnumInt object>
Unknown = <pyteal.EnumInt object>
class pyteal.TxnField(id: int, name: str, type: pyteal.TealType, is_array: bool, min_version: int)

Bases: enum.Enum

An enumeration.

accounts = (28, 'Accounts', <TealType.bytes: 1>, True, 2)
amount = (8, 'Amount', <TealType.uint64: 0>, False, 2)
application_args = (26, 'ApplicationArgs', <TealType.bytes: 1>, True, 2)
application_id = (24, 'ApplicationID', <TealType.uint64: 0>, False, 2)
applications = (50, 'Applications', <TealType.uint64: 0>, True, 3)
approval_program = (30, 'ApprovalProgram', <TealType.bytes: 1>, False, 2)
asset_amount = (18, 'AssetAmount', <TealType.uint64: 0>, False, 2)
asset_close_to = (21, 'AssetCloseTo', <TealType.bytes: 1>, False, 2)
asset_receiver = (20, 'AssetReceiver', <TealType.bytes: 1>, False, 2)
asset_sender = (19, 'AssetSender', <TealType.bytes: 1>, False, 2)
assets = (48, 'Assets', <TealType.uint64: 0>, True, 3)
clear_state_program = (31, 'ClearStateProgram', <TealType.bytes: 1>, False, 2)
close_remainder_to = (9, 'CloseRemainderTo', <TealType.bytes: 1>, False, 2)
config_asset = (33, 'ConfigAsset', <TealType.uint64: 0>, False, 2)
config_asset_clawback = (44, 'ConfigAssetClawback', <TealType.bytes: 1>, False, 2)
config_asset_decimals = (35, 'ConfigAssetDecimals', <TealType.uint64: 0>, False, 2)
config_asset_default_frozen = (36, 'ConfigAssetDefaultFrozen', <TealType.uint64: 0>, False, 2)
config_asset_freeze = (43, 'ConfigAssetFreeze', <TealType.bytes: 1>, False, 2)
config_asset_manager = (41, 'ConfigAssetManager', <TealType.bytes: 1>, False, 2)
config_asset_metadata_hash = (40, 'ConfigAssetMetadataHash', <TealType.bytes: 1>, False, 2)
config_asset_name = (38, 'ConfigAssetName', <TealType.bytes: 1>, False, 2)
config_asset_reserve = (42, 'ConfigAssetReserve', <TealType.bytes: 1>, False, 2)
config_asset_total = (34, 'ConfigAssetTotal', <TealType.uint64: 0>, False, 2)
config_asset_unit_name = (37, 'ConfigAssetUnitName', <TealType.bytes: 1>, False, 2)
config_asset_url = (39, 'ConfigAssetURL', <TealType.bytes: 1>, False, 2)
created_application_id = (61, 'CreatedApplicationID', <TealType.uint64: 0>, False, 5)
created_asset_id = (60, 'CreatedAssetID', <TealType.uint64: 0>, False, 5)
extra_program_pages = (56, 'ExtraProgramPages', <TealType.uint64: 0>, False, 4)
fee = (1, 'Fee', <TealType.uint64: 0>, False, 2)
first_valid = (2, 'FirstValid', <TealType.uint64: 0>, False, 2)
first_valid_time = (3, 'FirstValidTime', <TealType.uint64: 0>, False, 2)
freeze_asset = (45, 'FreezeAsset', <TealType.uint64: 0>, False, 2)
freeze_asset_account = (46, 'FreezeAssetAccount', <TealType.bytes: 1>, False, 2)
freeze_asset_frozen = (47, 'FreezeAssetFrozen', <TealType.uint64: 0>, False, 2)
global_num_byte_slices = (53, 'GlobalNumByteSlice', <TealType.uint64: 0>, False, 3)
global_num_uints = (52, 'GlobalNumUint', <TealType.uint64: 0>, False, 3)
group_index = (22, 'GroupIndex', <TealType.uint64: 0>, False, 2)
last_log = (62, 'LastLog', <TealType.bytes: 1>, False, 6)
last_valid = (4, 'LastValid', <TealType.uint64: 0>, False, 2)
lease = (6, 'Lease', <TealType.bytes: 1>, False, 2)
local_num_byte_slices = (55, 'LocalNumByteSlice', <TealType.uint64: 0>, False, 3)
local_num_uints = (54, 'LocalNumUint', <TealType.uint64: 0>, False, 3)
logs = (58, 'Logs', <TealType.bytes: 1>, True, 5)
nonparticipation = (57, 'Nonparticipation', <TealType.uint64: 0>, False, 5)
note = (5, 'Note', <TealType.bytes: 1>, False, 2)
num_accounts = (2, 'NumAccounts', <TealType.uint64: 0>, False, 2)
num_app_args = (27, 'NumAppArgs', <TealType.uint64: 0>, False, 2)
num_applications = (51, 'NumApplications', <TealType.uint64: 0>, False, 3)
num_assets = (49, 'NumAssets', <TealType.uint64: 0>, False, 3)
num_logs = (59, 'NumLogs', <TealType.uint64: 0>, False, 5)
on_completion = (25, 'OnCompletion', <TealType.uint64: 0>, False, 2)
receiver = (7, 'Receiver', <TealType.bytes: 1>, False, 2)
rekey_to = (32, 'RekeyTo', <TealType.bytes: 1>, False, 2)
selection_pk = (11, 'SelectionPK', <TealType.bytes: 1>, False, 2)
sender = (0, 'Sender', <TealType.bytes: 1>, False, 2)
state_proof_pk = (63, 'StateProofPK', <TealType.bytes: 1>, False, 6)
tx_id = (23, 'TxID', <TealType.bytes: 1>, False, 2)
type = (15, 'Type', <TealType.bytes: 1>, False, 2)
type_enum = (16, 'TypeEnum', <TealType.uint64: 0>, False, 2)
type_of() → pyteal.TealType
vote_first = (12, 'VoteFirst', <TealType.uint64: 0>, False, 2)
vote_key_dilution = (14, 'VoteKeyDilution', <TealType.uint64: 0>, False, 2)
vote_last = (13, 'VoteLast', <TealType.uint64: 0>, False, 2)
vote_pk = (10, 'VotePK', <TealType.bytes: 1>, False, 2)
xfer_asset = (17, 'XferAsset', <TealType.uint64: 0>, False, 2)
class pyteal.TxnExpr(op: pyteal.Op, name: str, field: pyteal.TxnField)

Bases: pyteal.LeafExpr

An expression that accesses a transaction field from the current transaction.

type_of()

Get the return type of this expression.

class pyteal.TxnaExpr(staticOp: pyteal.Op, dynamicOp: Optional[pyteal.Op], name: str, field: pyteal.TxnField, index: Union[int, pyteal.Expr])

Bases: pyteal.LeafExpr

An expression that accesses a transaction array field from the current transaction.

type_of()

Get the return type of this expression.

class pyteal.TxnArray(txnObject: pyteal.TxnObject, accessField: pyteal.TxnField, lengthField: pyteal.TxnField)

Bases: pyteal.Array

Represents a transaction array field.

__getitem__(index: Union[int, pyteal.Expr]) → pyteal.TxnaExpr

Get the value at a given index in this array.

length() → pyteal.TxnExpr

Get the length of the array.

class pyteal.TxnObject(makeTxnExpr: Callable[[pyteal.TxnField], pyteal.TxnExpr], makeTxnaExpr: Callable[[pyteal.TxnField, Union[int, pyteal.Expr]], pyteal.TxnaExpr])

Bases: object

Represents a transaction and its fields.

accounts

The accounts array in an ApplicationCall transaction.

Type:TxnArray
amount() → pyteal.TxnExpr

Get the amount of the transaction in micro Algos.

Only set when type_enum() is TxnType.Payment.

For more information, see https://developer.algorand.org/docs/reference/transactions/#amount

application_args

Application call arguments array.

Type:TxnArray
application_id() → pyteal.TxnExpr

Get the application ID from the ApplicationCall portion of the current transaction.

Only set when type_enum() is TxnType.ApplicationCall.

applications

The applications array in an ApplicationCall transaction.

Type:TxnArray

Requires TEAL version 3 or higher.

approval_program() → pyteal.TxnExpr

Get the approval program.

Only set when type_enum() is TxnType.ApplicationCall.

asset_amount() → pyteal.TxnExpr

Get the amount of the asset being transferred, measured in the asset’s units.

Only set when type_enum() is TxnType.AssetTransfer.

For more information, see https://developer.algorand.org/docs/reference/transactions/#assetamount

asset_close_to() → pyteal.TxnExpr

Get the closeout address of the asset transfer.

Only set when type_enum() is TxnType.AssetTransfer.

For more information, see https://developer.algorand.org/docs/reference/transactions/#assetcloseto

asset_receiver() → pyteal.TxnExpr

Get the recipient of the asset transfer.

Only set when type_enum() is TxnType.AssetTransfer.

For more information, see https://developer.algorand.org/docs/reference/transactions/#assetreceiver

asset_sender() → pyteal.TxnExpr

Get the 32 byte address of the subject of clawback.

Only set when type_enum() is TxnType.AssetTransfer.

For more information, see https://developer.algorand.org/docs/reference/transactions/#assetsender

assets

The foreign asset array in an ApplicationCall transaction.

Type:TxnArray

Requires TEAL version 3 or higher.

clear_state_program() → pyteal.TxnExpr

Get the clear state program.

Only set when type_enum() is TxnType.ApplicationCall.

close_remainder_to() → pyteal.TxnExpr

Get the 32 byte address of the CloseRemainderTo field.

Only set when type_enum() is TxnType.Payment.

For more information, see https://developer.algorand.org/docs/reference/transactions/#closeremainderto

config_asset() → pyteal.TxnExpr

Get the asset ID in asset config transaction.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#configasset

config_asset_clawback() → pyteal.TxnExpr

Get the 32 byte asset clawback address.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#clawbackaddr

config_asset_decimals() → pyteal.TxnExpr

Get the number of digits to display after the decimal place when displaying the asset.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#decimals

config_asset_default_frozen() → pyteal.TxnExpr

Check if the asset’s slots are frozen by default or not.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#defaultfrozen

config_asset_freeze() → pyteal.TxnExpr

Get the 32 byte asset freeze address.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#freezeaddr

config_asset_manager() → pyteal.TxnExpr

Get the 32 byte asset manager address.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#manageraddr

config_asset_metadata_hash() → pyteal.TxnExpr

Get the 32 byte commitment to some unspecified asset metdata.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#metadatahash

config_asset_name() → pyteal.TxnExpr

Get the asset name.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#assetname

config_asset_reserve() → pyteal.TxnExpr

Get the 32 byte asset reserve address.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#reserveaddr

config_asset_total() → pyteal.TxnExpr

Get the total number of units of this asset created.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#total

config_asset_unit_name() → pyteal.TxnExpr

Get the unit name of the asset.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#unitname

config_asset_url() → pyteal.TxnExpr

Get the asset URL.

Only set when type_enum() is TxnType.AssetConfig.

For more information, see https://developer.algorand.org/docs/reference/transactions/#url

created_application_id() → pyteal.TxnExpr

Get the application ID allocated by the creation of an application.

Only set when type_enum() is TxnType.ApplicationCall and this is an app creation call.

Requires TEAL version 5 or higher.

  • v5 - Only works on inner transactions.
  • >= v6 - Works on top-level and inner transactions.
created_asset_id() → pyteal.TxnExpr

Get the asset ID allocated by the creation of an ASA.

Only set when type_enum() is TxnType.AssetConfig and this is an asset creation transaction.

Requires TEAL version 5 or higher.

  • v5 - Only works on inner transactions.
  • >= v6 - Works on top-level and inner transactions.
extra_program_pages() → pyteal.TxnExpr

Get the number of additional pages for each of the application’s approval and clear state programs.

1 additional page means 2048 more total bytes, or 1024 for each program.

Only set when type_enum() is TxnType.ApplicationCall and this is an app creation call.

Requires TEAL version 4 or higher.

fee() → pyteal.TxnExpr

Get the transaction fee in micro Algos.

For more information, see https://developer.algorand.org/docs/reference/transactions/#fee

first_valid() → pyteal.TxnExpr

Get the first valid round number.

For more information, see https://developer.algorand.org/docs/reference/transactions/#firstvalid

freeze_asset() → pyteal.TxnExpr

Get the asset ID being frozen or un-frozen.

Only set when type_enum() is TxnType.AssetFreeze.

For more information, see https://developer.algorand.org/docs/reference/transactions/#freezeasset

freeze_asset_account() → pyteal.TxnExpr

Get the 32 byte address of the account whose asset slot is being frozen or un-frozen.

Only set when type_enum() is TxnType.AssetFreeze.

For more information, see https://developer.algorand.org/docs/reference/transactions/#freezeaccount

freeze_asset_frozen() → pyteal.TxnExpr

Get the new frozen value for the asset.

Only set when type_enum() is TxnType.AssetFreeze.

For more information, see https://developer.algorand.org/docs/reference/transactions/#assetfrozen

global_num_byte_slices() → pyteal.TxnExpr

Get the schema count of global state byte slices in an application creation call.

Only set when type_enum() is TxnType.ApplicationCall and this is an app creation call.

Requires TEAL version 3 or higher.

global_num_uints() → pyteal.TxnExpr

Get the schema count of global state integers in an application creation call.

Only set when type_enum() is TxnType.ApplicationCall and this is an app creation call.

Requires TEAL version 3 or higher.

group_index() → pyteal.TxnExpr

Get the position of the transaction within the atomic transaction group.

A stand-alone transaction is implictly element 0 in a group of 1.

For more information, see https://developer.algorand.org/docs/reference/transactions/#group

last_log() → pyteal.TxnExpr

A convenience method for getting the last logged message from a transaction.

Only application calls may log a message. Returns an empty string if no messages were logged.

Only set when type_enum() is TxnType.ApplicationCall.

Requires TEAL version 6 or higher.

last_valid() → pyteal.TxnExpr

Get the last valid round number.

For more information, see https://developer.algorand.org/docs/reference/transactions/#lastvalid

lease() → pyteal.TxnExpr

Get the transaction lease.

For more information, see https://developer.algorand.org/docs/reference/transactions/#lease

local_num_byte_slices() → pyteal.TxnExpr

Get the schema count of local state byte slices in an application creation call.

Only set when type_enum() is TxnType.ApplicationCall and this is an app creation call.

Requires TEAL version 3 or higher.

local_num_uints() → pyteal.TxnExpr

Get the schema count of local state integers in an application creation call.

Only set when type_enum() is TxnType.ApplicationCall and this is an app creation call.

Requires TEAL version 3 or higher.

logs

The log messages emitted by an application call.

Type:TxnArray

Requires TEAL version 5 or higher.

  • v5 - Only works on inner transactions.
  • >= v6 - Works on top-level and inner transactions.
nonparticipation() → pyteal.TxnExpr

Marks an account nonparticipating for rewards.

Only set when type_enum() is TxnType.KeyRegistration.

For more information, see https://developer.algorand.org/docs/reference/transactions/#nonparticipation

Requires TEAL version 5 or higher.

note() → pyteal.TxnExpr

Get the transaction note.

For more information, see https://developer.algorand.org/docs/reference/transactions/#note

on_completion() → pyteal.TxnExpr

Get the on completion action from the ApplicationCall portion of the transaction.

Only set when type_enum() is TxnType.ApplicationCall.

receiver() → pyteal.TxnExpr

Get the 32 byte address of the receiver.

Only set when type_enum() is TxnType.Payment.

For more information, see https://developer.algorand.org/docs/reference/transactions/#receiver

rekey_to() → pyteal.TxnExpr

Get the sender’s new 32 byte AuthAddr.

For more information, see https://developer.algorand.org/docs/reference/transactions/#rekeyto

selection_pk() → pyteal.TxnExpr

Get the VRF public key.

Only set when type_enum() is TxnType.KeyRegistration.

For more information, see https://developer.algorand.org/docs/reference/transactions/#selectionpk

sender() → pyteal.TxnExpr

Get the 32 byte address of the sender.

For more information, see https://developer.algorand.org/docs/reference/transactions/#sender

state_proof_pk() → pyteal.TxnExpr

Get the state proof public key commitment from a transaction.

Requires TEAL version 6 or higher.

tx_id() → pyteal.TxnExpr

Get the 32 byte computed ID for the transaction.

type() → pyteal.TxnExpr

Get the type of this transaction as a byte string.

In most cases it is preferable to use type_enum() instead.

For more information, see https://developer.algorand.org/docs/reference/transactions/#type

type_enum() → pyteal.TxnExpr

Get the type of this transaction.

See TxnType for possible values.

vote_first() → pyteal.TxnExpr

Get the first round that the participation key is valid.

Only set when type_enum() is TxnType.KeyRegistration.

For more information, see https://developer.algorand.org/docs/reference/transactions/#votefirst

vote_key_dilution() → pyteal.TxnExpr

Get the dilution for the 2-level participation key.

Only set when type_enum() is TxnType.KeyRegistration.

For more information, see https://developer.algorand.org/docs/reference/transactions/#votekeydilution

vote_last() → pyteal.TxnExpr

Get the last round that the participation key is valid.

Only set when type_enum() is TxnType.KeyRegistration.

For more information, see https://developer.algorand.org/docs/reference/transactions/#votelast

vote_pk() → pyteal.TxnExpr

Get the root participation public key.

Only set when type_enum() is TxnType.KeyRegistration.

For more information, see https://developer.algorand.org/docs/reference/transactions/#votepk

xfer_asset() → pyteal.TxnExpr

Get the ID of the asset being transferred.

Only set when type_enum() is TxnType.AssetTransfer.

For more information, see https://developer.algorand.org/docs/reference/transactions/#xferasset

class pyteal.GtxnExpr(txnIndex: Union[int, pyteal.Expr], field: pyteal.TxnField)

Bases: pyteal.TxnExpr

An expression that accesses a transaction field from a transaction in the current group.

class pyteal.GtxnaExpr(txnIndex: Union[int, pyteal.Expr], field: pyteal.TxnField, index: Union[int, pyteal.Expr])

Bases: pyteal.TxnaExpr

An expression that accesses a transaction array field from a transaction in the current group.

class pyteal.TxnGroup

Bases: object

Represents a group of transactions.

__getitem__(txnIndex: Union[int, pyteal.Expr]) → pyteal.TxnObject
class pyteal.GeneratedID(txnIndex: Union[int, pyteal.Expr])

Bases: pyteal.LeafExpr

An expression to obtain the ID of an asset or application created by another transaction in the current group.

__init__(txnIndex: Union[int, pyteal.Expr]) → None

Create an expression to extract the created ID from a transaction in the current group.

Requires TEAL version 4 or higher. This operation is only permitted in application mode.

Parameters:
  • txnIndex – The index of the transaction from which the created ID should be obtained.
  • index may be a Python int, or it may be a PyTeal expression that evaluates at (This) –
  • If it's an expression, it must evaluate to a uint64. In all cases, the index (runtime.) –
  • be less than the index of the current transaction. (must) –
type_of()

Get the return type of this expression.

class pyteal.ImportScratchValue(txnIndex: Union[int, pyteal.Expr], slotId: Union[int, pyteal.Expr])

Bases: pyteal.LeafExpr

An expression to load a scratch value created by another transaction in the current group

__init__(txnIndex: Union[int, pyteal.Expr], slotId: Union[int, pyteal.Expr]) → None

Create an expression to load a scratch space slot from a transaction in the current group.

Requires TEAL version 4 or higher. This operation is only permitted in application mode.

Parameters:
  • txnIndex – The index of the transaction from which the created ID should be obtained. This index may be a Python int, or it may be a PyTeal expression that evaluates at runtime. If it’s an expression, it must evaluate to a uint64. In all cases, the index must be less than the index of the current transaction.
  • slotId – The index of the scratch slot that should be loaded. This index may be a Python int, or it may be a PyTeal expression that evaluates at runtime. If it’s an expression, it must evaluate to a uint64. In all cases, the index must be in the range [0, 256).
type_of()

Get the return type of this expression.

class pyteal.Global(field: pyteal.GlobalField)

Bases: pyteal.LeafExpr

An expression that accesses a global property.

classmethod caller_app_address() → pyteal.Global

Get the address of the app that submitted the InnerTransaction that triggered this app to execute.

If not called from another app, this will return the ZeroAddress

Requires TEAL version 6 or higher.

classmethod caller_app_id() → pyteal.Global

Get the id of the app that submitted the InnerTransaction that triggered this app to execute.

If not called from another app, this will return 0

Requires TEAL version 6 or higher.

classmethod creator_address() → pyteal.Global

Address of the creator of the current application.

Fails during Signature mode. Requires TEAL version 3 or higher.

classmethod current_application_address() → pyteal.Global

Get the address of that the current application controls.

Fails during Signature mode. Requires TEAL version 5 or higher.

classmethod current_application_id() → pyteal.Global

Get the ID of the current application executing.

Fails during Signature mode.

classmethod group_id() → pyteal.Global

Get the ID of the current transaction group.

If the current transaction is not part of a group, this will return 32 zero bytes.

Requires TEAL version 5 or higher.

classmethod group_size() → pyteal.Global

Get the number of transactions in this atomic transaction group.

This will be at least 1.

classmethod latest_timestamp() → pyteal.Global

Get the latest confirmed block UNIX timestamp.

Fails if negative.

classmethod logic_sig_version() → pyteal.Global

Get the maximum supported TEAL version.

classmethod max_txn_life() → pyteal.Global

Get the maximum number of rounds a transaction can have.

classmethod min_balance() → pyteal.Global

Get the minumum balance in micro Algos.

classmethod min_txn_fee() → pyteal.Global

Get the minumum transaction fee in micro Algos.

classmethod opcode_budget() → pyteal.Global

Get the remaining opcode execution budget

Requires TEAL version 6 or higher.

classmethod round() → pyteal.Global

Get the current round number.

type_of()

Get the return type of this expression.

classmethod zero_address() → pyteal.Global

Get the 32 byte zero address.

class pyteal.GlobalField(id: int, name: str, type: pyteal.TealType, min_version: int)

Bases: enum.Enum

An enumeration.

caller_app_address = (14, 'CallerApplicationAddress', <TealType.bytes: 1>, 6)
caller_app_id = (13, 'CallerApplicationID', <TealType.uint64: 0>, 6)
creator_address = (9, 'CreatorAddress', <TealType.bytes: 1>, 3)
current_app_address = (10, 'CurrentApplicationAddress', <TealType.bytes: 1>, 5)
current_app_id = (8, 'CurrentApplicationID', <TealType.uint64: 0>, 2)
group_id = (11, 'GroupID', <TealType.bytes: 1>, 5)
group_size = (4, 'GroupSize', <TealType.uint64: 0>, 2)
latest_timestamp = (7, 'LatestTimestamp', <TealType.uint64: 0>, 2)
logic_sig_version = (5, 'LogicSigVersion', <TealType.uint64: 0>, 2)
max_txn_life = (2, 'MaxTxnLife', <TealType.uint64: 0>, 2)
min_balance = (1, 'MinBalance', <TealType.uint64: 0>, 2)
min_txn_fee = (0, 'MinTxnFee', <TealType.uint64: 0>, 2)
opcode_budget = (12, 'OpcodeBudget', <TealType.uint64: 0>, 6)
round = (6, 'Round', <TealType.uint64: 0>, 2)
type_of() → pyteal.TealType
zero_address = (3, 'ZeroAddress', <TealType.bytes: 1>, 2)
class pyteal.App(field: pyteal.AppField, args)

Bases: pyteal.LeafExpr

An expression related to applications.

classmethod globalDel(key: pyteal.Expr) → pyteal.App

Delete a key from the global state of the current application.

Parameters:key – The key to delete from the global application state. Must evaluate to bytes.
classmethod globalGet(key: pyteal.Expr) → pyteal.App

Read from the global state of the current application.

Parameters:key – The key to read from the global application state. Must evaluate to bytes.
classmethod globalGetEx(app: pyteal.Expr, key: pyteal.Expr) → pyteal.MaybeValue

Read from the global state of an application.

Parameters:
  • app – An index into Txn.ForeignApps that corresponds to the application to read from, must be evaluated to uint64 (or, since v4, an application id that appears in Txn.ForeignApps or is the CurrentApplicationID, must be evaluated to uint64).
  • key – The key to read from the global application state. Must evaluate to bytes.
classmethod globalPut(key: pyteal.Expr, value: pyteal.Expr) → pyteal.App

Write to the global state of the current application.

Parameters:
  • key – The key to write in the global application state. Must evaluate to bytes.
  • value – THe value to write in the global application state. Can evaluate to any type.
classmethod id() → pyteal.Global

Get the ID of the current running application.

This is the same as Global.current_application_id().

classmethod localDel(account: pyteal.Expr, key: pyteal.Expr) → pyteal.App

Delete a key from an account’s local state for the current application.

Parameters:
  • account – An index into Txn.Accounts that corresponds to the account to check, must be evaluated to uint64 (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender, must be evaluated to bytes).
  • key – The key to delete from the account’s local state. Must evaluate to bytes.
classmethod localGet(account: pyteal.Expr, key: pyteal.Expr) → pyteal.App

Read from an account’s local state for the current application.

Parameters:
  • account – An index into Txn.Accounts that corresponds to the account to check, must be evaluated to uint64 (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender, must be evaluated to bytes).
  • key – The key to read from the account’s local state. Must evaluate to bytes.
classmethod localGetEx(account: pyteal.Expr, app: pyteal.Expr, key: pyteal.Expr) → pyteal.MaybeValue

Read from an account’s local state for an application.

Parameters:
  • account – An index into Txn.Accounts that corresponds to the account to check, must be evaluated to uint64 (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender, must be evaluated to bytes).
  • app – An index into Txn.ForeignApps that corresponds to the application to read from, must be evaluated to uint64 (or, since v4, an application id that appears in Txn.ForeignApps or is the CurrentApplicationID, must be evaluated to int).
  • key – The key to read from the account’s local state. Must evaluate to bytes.
classmethod localPut(account: pyteal.Expr, key: pyteal.Expr, value: pyteal.Expr) → pyteal.App

Write to an account’s local state for the current application.

Parameters:
  • account – An index into Txn.Accounts that corresponds to the account to check, must be evaluated to uint64 (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender, must be evaluated to bytes).
  • key – The key to write in the account’s local state. Must evaluate to bytes.
  • value – The value to write in the account’s local state. Can evaluate to any type.
classmethod optedIn(account: pyteal.Expr, app: pyteal.Expr) → pyteal.App

Check if an account has opted in for an application.

Parameters:
  • account – An index into Txn.Accounts that corresponds to the account to check, must be evaluated to uint64 (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender, must be evaluated to bytes).
  • app – An index into Txn.ForeignApps that corresponds to the application to read from, must be evaluated to uint64 (or, since v4, an application id that appears in Txn.ForeignApps or is the CurrentApplicationID, must be evaluated to int).
type_of()

Get the return type of this expression.

class pyteal.AppField(op: pyteal.Op, type: pyteal.TealType)

Bases: enum.Enum

Enum of app fields used to create App objects.

get_op() → pyteal.Op
globalDel = (<Op.app_global_del: OpType(value='app_global_del', mode=<Mode.Application: 2>, min_version=2)>, <TealType.none: 3>)
globalGet = (<Op.app_global_get: OpType(value='app_global_get', mode=<Mode.Application: 2>, min_version=2)>, <TealType.anytype: 2>)
globalGetEx = (<Op.app_global_get_ex: OpType(value='app_global_get_ex', mode=<Mode.Application: 2>, min_version=2)>, <TealType.none: 3>)
globalPut = (<Op.app_global_put: OpType(value='app_global_put', mode=<Mode.Application: 2>, min_version=2)>, <TealType.none: 3>)
localDel = (<Op.app_local_del: OpType(value='app_local_del', mode=<Mode.Application: 2>, min_version=2)>, <TealType.none: 3>)
localGet = (<Op.app_local_get: OpType(value='app_local_get', mode=<Mode.Application: 2>, min_version=2)>, <TealType.anytype: 2>)
localGetEx = (<Op.app_local_get_ex: OpType(value='app_local_get_ex', mode=<Mode.Application: 2>, min_version=2)>, <TealType.none: 3>)
localPut = (<Op.app_local_put: OpType(value='app_local_put', mode=<Mode.Application: 2>, min_version=2)>, <TealType.none: 3>)
optedIn = (<Op.app_opted_in: OpType(value='app_opted_in', mode=<Mode.Application: 2>, min_version=2)>, <TealType.uint64: 0>)
type_of() → pyteal.TealType
class pyteal.OnComplete

Bases: object

An enum of values that TxnObject.on_completion() may return.

ClearState = <pyteal.EnumInt object>
CloseOut = <pyteal.EnumInt object>
DeleteApplication = <pyteal.EnumInt object>
NoOp = <pyteal.EnumInt object>
OptIn = <pyteal.EnumInt object>
UpdateApplication = <pyteal.EnumInt object>
class pyteal.AppParam

Bases: object

classmethod address(app: pyteal.Expr) → pyteal.MaybeValue

Get the escrow address for the application.

Parameters:app – An index into Txn.ForeignApps that correspond to the application to check. Must evaluate to uint64.
classmethod approvalProgram(app: pyteal.Expr) → pyteal.MaybeValue

Get the bytecode of Approval Program for the application.

Parameters:app – An index into Txn.ForeignApps that correspond to the application to check. Must evaluate to uint64.
classmethod clearStateProgram(app: pyteal.Expr) → pyteal.MaybeValue

Get the bytecode of Clear State Program for the application.

Parameters:app – An index into Txn.ForeignApps that correspond to the application to check. Must evaluate to uint64.
classmethod creator(app: pyteal.Expr) → pyteal.MaybeValue

Get the creator address for the application.

Parameters:app – An index into Txn.ForeignApps that correspond to the application to check. Must evaluate to uint64.
classmethod extraProgramPages(app: pyteal.Expr) → pyteal.MaybeValue

Get the number of Extra Program Pages of code space for the application.

Parameters:app – An index into Txn.ForeignApps that correspond to the application to check. Must evaluate to uint64.
classmethod globalNumByteSlice(app: pyteal.Expr) → pyteal.MaybeValue

Get the number of byte array values allowed in Global State for the application.

Parameters:app – An index into Txn.ForeignApps that correspond to the application to check. Must evaluate to uint64.
classmethod globalNumUnit(app: pyteal.Expr) → pyteal.MaybeValue

Get the number of uint64 values allowed in Global State for the application.

Parameters:app – An index into Txn.ForeignApps that correspond to the application to check. Must evaluate to uint64.
classmethod localNumByteSlice(app: pyteal.Expr) → pyteal.MaybeValue

Get the number of byte array values allowed in Local State for the application.

Parameters:app – An index into Txn.ForeignApps that correspond to the application to check. Must evaluate to uint64.
classmethod localNumUnit(app: pyteal.Expr) → pyteal.MaybeValue

Get the number of uint64 values allowed in Local State for the application.

Parameters:app – An index into Txn.ForeignApps that correspond to the application to check. Must evaluate to uint64.
class pyteal.AssetHolding

Bases: object

classmethod balance(account: pyteal.Expr, asset: pyteal.Expr) → pyteal.MaybeValue

Get the amount of an asset held by an account.

Parameters:
  • account – An index into Txn.Accounts that corresponds to the account to check, must be evaluated to uint64 (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender, must be evaluated to bytes).
  • asset – The ID of the asset to get, must be evaluated to uint64 (or, since v4, a Txn.ForeignAssets offset).
classmethod frozen(account: pyteal.Expr, asset: pyteal.Expr) → pyteal.MaybeValue

Check if an asset is frozen for an account.

A value of 1 indicates frozen and 0 indicates not frozen.

Parameters:
  • account – An index into Txn.Accounts that corresponds to the account to check, must be evaluated to uint64 (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender, must be evaluated to bytes).
  • asset – The ID of the asset to get, must be evaluated to uint64 (or, since v4, a Txn.ForeignAssets offset).
class pyteal.AssetParam

Bases: object

classmethod clawback(asset: pyteal.Expr) → pyteal.MaybeValue

Get the clawback address for an asset.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
classmethod creator(asset: pyteal.Expr) → pyteal.MaybeValue

Get the creator address for an asset.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check. Must evaluate to uint64.
classmethod decimals(asset: pyteal.Expr) → pyteal.MaybeValue

Get the number of decimals for an asset.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
classmethod defaultFrozen(asset: pyteal.Expr) → pyteal.MaybeValue

Check if an asset is frozen by default.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
classmethod freeze(asset: pyteal.Expr) → pyteal.MaybeValue

Get the freeze address for an asset.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
classmethod manager(asset: pyteal.Expr) → pyteal.MaybeValue

Get the manager address for an asset.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
classmethod metadataHash(asset: pyteal.Expr) → pyteal.MaybeValue

Get the arbitrary commitment for an asset.

If set, this will be 32 bytes long.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
classmethod name(asset: pyteal.Expr) → pyteal.MaybeValue

Get the name of an asset.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
classmethod reserve(asset: pyteal.Expr) → pyteal.MaybeValue

Get the reserve address for an asset.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
classmethod total(asset: pyteal.Expr) → pyteal.MaybeValue

Get the total number of units of an asset.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
classmethod unitName(asset: pyteal.Expr) → pyteal.MaybeValue

Get the unit name of an asset.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
classmethod url(asset: pyteal.Expr) → pyteal.MaybeValue

Get the URL of an asset.

Parameters:asset – An index into Txn.ForeignAssets that corresponds to the asset to check, must be evaluated to uint64 (or since v4, an asset ID that appears in Txn.ForeignAssets).
class pyteal.AccountParam

Bases: object

classmethod authAddr(acct: pyteal.Expr) → pyteal.MaybeValue

Get the authorizing address for an account. If the account is not rekeyed, the empty addresss is returned.

Parameters:acct – An index into Txn.accounts that corresponds to the application to check or an address available at runtime. May evaluate to uint64 or an address.
classmethod balance(acct: pyteal.Expr) → pyteal.MaybeValue

Get the current balance in microalgos an account.

Parameters:acct – An index into Txn.accounts that corresponds to the application to check or an address available at runtime. May evaluate to uint64 or an address.
classmethod minBalance(acct: pyteal.Expr) → pyteal.MaybeValue

Get the minimum balance in microalgos for an account.

Parameters:acct – An index into Txn.accounts that corresponds to the application to check or an address available at runtime. May evaluate to uint64 or an address.
class pyteal.InnerTxnBuilder

Bases: object

This class represents expressions used to create, modify, and submit inner transactions.

Inner transactions are transactions which applications can dynamically create. Each inner transaction will appear as a transaction inside of the current transaction being executed.

As of TEAL version 5, only the transaction types TxnType.Payment, TxnType.AssetTransfer, TxnType.AssetConfig, and TxnType.AssetFreeze are allowed. Additionally, not all fields are allowed to be set. For example, it is not currently allowed to set the rekeyTo field of an inner transaction.

classmethod Begin() → pyteal.Expr

Begin preparation of a new inner transaction.

This new inner transaction is initialized with its sender to the application address (Global.current_application_address); fee to the minimum allowable, taking into account MinTxnFee and credit from overpaying in earlier transactions; FirstValid/LastValid to the values in the top-level transaction, and all other fields to zero values.

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

classmethod Next() → pyteal.Expr

Begin preparation of a new inner transaction (in the same transaction group).

This new inner transaction is initialized with its sender to the application address (Global.current_application_address); fee to the minimum allowable, taking into account MinTxnFee and credit from overpaying in earlier transactions; FirstValid/LastValid to the values in the top-level transaction, and all other fields to zero values.

Requires TEAL version 6 or higher. This operation is only permitted in application mode.

classmethod SetField(field: pyteal.TxnField, value: Union[pyteal.Expr, List[pyteal.Expr]]) → pyteal.Expr

Set a field of the current inner transaction.

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.

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

Parameters:
  • 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.
classmethod SetFields(fields: Dict[pyteal.TxnField, Union[pyteal.Expr, List[pyteal.Expr]]]) → pyteal.Expr

Set multiple fields of the current inner transaction.

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.

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

Parameters:fields – A dictionary whose keys are fields to set and whose values are the value each field should take. Each value must evaluate to a type that is compatible with the field being set.
classmethod Submit() → pyteal.Expr

Execute the current inner transaction.

InnerTxnBuilder.Begin and InnerTxnBuilder.SetField must be called before submitting an inner transaction.

This will fail if 256 inner transactions have already been executed, or if the inner transaction itself fails. Upon failure, the current program will immediately exit and fail as well.

If the inner transaction is successful, then its effects can be immediately observed by this program with stateful expressions such as Balance. Additionally, the fields of the most recently submitted inner transaction can be examined using the InnerTxn object. If the inner transaction creates an asset, the new asset ID can be found by looking at InnerTxn.created_asset_id().

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

class pyteal.InnerTxnAction

Bases: enum.Enum

An enumeration.

Begin = <Op.itxn_begin: OpType(value='itxn_begin', mode=<Mode.Application: 2>, min_version=5)>
Next = <Op.itxn_next: OpType(value='itxn_next', mode=<Mode.Application: 2>, min_version=6)>
Submit = <Op.itxn_submit: OpType(value='itxn_submit', mode=<Mode.Application: 2>, min_version=5)>
class pyteal.GitxnExpr(txnIndex: int, field: pyteal.TxnField)

Bases: pyteal.TxnExpr

An expression that accesses an inner transaction field from an inner transaction in the last inner group.

class pyteal.GitxnaExpr(txnIndex: int, field: pyteal.TxnField, index: Union[int, pyteal.Expr])

Bases: pyteal.TxnaExpr

An expression that accesses an inner transaction array field from an inner transaction in the last inner group.

class pyteal.InnerTxnGroup

Bases: object

Represents a group of inner transactions.

__getitem__(txnIndex: int) → pyteal.TxnObject
class pyteal.Array

Bases: abc.ABC

Represents a variable length array of objects.

__getitem__(index: int)

Get the value at a given index in this array.

length() → pyteal.Expr

Get the length of the array.

class pyteal.Tmpl(op: pyteal.Op, type: pyteal.TealType, name: str)

Bases: pyteal.LeafExpr

Template expression for creating placeholder values.

classmethod Addr(placeholder: str)

Create a new Addr template.

Parameters:placeholder – The name to use for this template variable. Must start with TMPL_ and only consist of uppercase alphanumeric characters and underscores.
classmethod Bytes(placeholder: str)

Create a new Bytes template.

Parameters:placeholder – The name to use for this template variable. Must start with TMPL_ and only consist of uppercase alphanumeric characters and underscores.
classmethod Int(placeholder: str)

Create a new Int template.

Parameters:placeholder – The name to use for this template variable. Must start with TMPL_ and only consist of uppercase alphanumeric characters and underscores.
type_of()

Get the return type of this expression.

class pyteal.Nonce(base: str, nonce: str, child: pyteal.Expr)

Bases: pyteal.Expr

A meta expression only used to change the hash of a TEAL program.

__init__(base: str, nonce: str, child: pyteal.Expr) → None

Create a new Nonce.

The Nonce expression behaves exactly like the child expression passed into it, except it uses the provided nonce string to alter its structure in a way that does not affect execution.

Parameters:
  • base – The base of the nonce. Must be one of utf8, base16, base32, or base64.
  • nonce – An arbitrary nonce string that conforms to base.
  • child – The expression to wrap.
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.UnaryExpr(op: pyteal.Op, inputType: pyteal.TealType, outputType: pyteal.TealType, arg: pyteal.Expr)

Bases: pyteal.Expr

An expression with a single argument.

has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

pyteal.Btoi(arg: pyteal.Expr) → pyteal.UnaryExpr

Convert a byte string to a uint64.

pyteal.Itob(arg: pyteal.Expr) → pyteal.UnaryExpr

Convert a uint64 string to a byte string.

pyteal.Len(arg: pyteal.Expr) → pyteal.UnaryExpr

Get the length of a byte string.

pyteal.BitLen(arg: pyteal.Expr) → pyteal.UnaryExpr

Get the index of the highest nonzero bit in an integer.

If the argument is 0, 0 will be returned.

If the argument is a byte array, it is interpreted as a big-endian unsigned integer.

Requires TEAL version 4 or higher.

pyteal.Sha256(arg: pyteal.Expr) → pyteal.UnaryExpr

Get the SHA-256 hash of a byte string.

pyteal.Sha512_256(arg: pyteal.Expr) → pyteal.UnaryExpr

Get the SHA-512/256 hash of a byte string.

pyteal.Keccak256(arg: pyteal.Expr) → pyteal.UnaryExpr

Get the KECCAK-256 hash of a byte string.

pyteal.Not(arg: pyteal.Expr) → pyteal.UnaryExpr

Get the logical inverse of a uint64.

If the argument is 0, then this will produce 1. Otherwise this will produce 0.

pyteal.BitwiseNot(arg: pyteal.Expr) → pyteal.UnaryExpr

Get the bitwise inverse of a uint64.

Produces ~arg.

pyteal.Sqrt(arg: pyteal.Expr) → pyteal.UnaryExpr

Get the integer square root of a uint64.

This will return the largest integer X such that X^2 <= arg.

Requires TEAL version 4 or higher.

pyteal.Pop(arg: pyteal.Expr) → pyteal.UnaryExpr

Pop a value from the stack.

pyteal.Balance(account: pyteal.Expr) → pyteal.UnaryExpr

Get the balance of a user in microAlgos.

Argument must be an index into Txn.Accounts that corresponds to the account to read from, must be evaluated to uint64 (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender).

This operation is only permitted in application mode.

pyteal.MinBalance(account: pyteal.Expr) → pyteal.UnaryExpr

Get the minimum balance of a user in microAlgos.

For more information about minimum balances, see: https://developer.algorand.org/docs/features/accounts/#minimum-balance

Argument must be an index into Txn.Accounts that corresponds to the account to read from, must be evaluated to uint64 (or, since v4, an account address that appears in Txn.Accounts or is Txn.Sender).

Requires TEAL version 3 or higher. This operation is only permitted in application mode.

class pyteal.BinaryExpr(op: pyteal.Op, inputType: Union[pyteal.TealType, Tuple[pyteal.TealType, pyteal.TealType]], outputType: pyteal.TealType, argLeft: pyteal.Expr, argRight: pyteal.Expr)

Bases: pyteal.Expr

An expression with two arguments.

has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

pyteal.Add(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Add two numbers.

Produces left + right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.Minus(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Subtract two numbers.

Produces left - right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.Mul(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Multiply two numbers.

Produces left * right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.Div(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Divide two numbers.

Produces left / right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.Mod(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Modulo expression.

Produces left % right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.Exp(a: pyteal.Expr, b: pyteal.Expr) → pyteal.BinaryExpr

Exponential expression.

Produces a ** b.

Requires TEAL version 4 or higher.

Parameters:
  • a – Must evaluate to uint64.
  • b – Must evaluate to uint64.
pyteal.Divw(hi: pyteal.Expr, lo: pyteal.Expr, y: pyteal.Expr) → pyteal.TernaryExpr

Performs wide division by interpreting hi and lo as a uint128 value.

Requires TEAL version 6 or higher.

Parameters:
  • hi – Quotient’s high 64 bits. Must evaluate to uint64.
  • lo – Quotient’s low 64 bits. Must evaluate to uint64.
  • y – Divisor. Must evaluate to uint64.
pyteal.BitwiseAnd(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Bitwise and expression.

Produces left & right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.BitwiseOr(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Bitwise or expression.

Produces left | right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.BitwiseXor(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Bitwise xor expression.

Produces left ^ right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.ShiftLeft(a: pyteal.Expr, b: pyteal.Expr) → pyteal.BinaryExpr

Bitwise left shift expression.

Produces a << b. This is equivalent to a times 2^b, modulo 2^64.

Requires TEAL version 4 or higher.

Parameters:
  • a – Must evaluate to uint64.
  • b – Must evaluate to uint64.
pyteal.ShiftRight(a: pyteal.Expr, b: pyteal.Expr) → pyteal.BinaryExpr

Bitwise right shift expression.

Produces a >> b. This is equivalent to a divided by 2^b.

Requires TEAL version 4 or higher.

Parameters:
  • a – Must evaluate to uint64.
  • b – Must evaluate to uint64.
pyteal.Eq(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Equality expression.

Checks if left == right.

Parameters:
  • left – A value to check.
  • right – The other value to check. Must evaluate to the same type as left.
pyteal.Neq(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Difference expression.

Checks if left != right.

Parameters:
  • left – A value to check.
  • right – The other value to check. Must evaluate to the same type as left.
pyteal.Lt(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Less than expression.

Checks if left < right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.Le(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Less than or equal to expression.

Checks if left <= right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.Gt(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Greater than expression.

Checks if left > right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.Ge(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Greater than or equal to expression.

Checks if left >= right.

Parameters:
  • left – Must evaluate to uint64.
  • right – Must evaluate to uint64.
pyteal.GetBit(value: pyteal.Expr, index: pyteal.Expr) → pyteal.BinaryExpr

Get the bit value of an expression at a specific index.

The meaning of index differs if value is an integer or a byte string.

  • For integers, bit indexing begins with low-order bits. For example, GetBit(Int(16), Int(4)) yields 1. Any other valid index would yield a bit value of 0. Any integer less than 64 is a valid index.
  • For byte strings, bit indexing begins at the first byte. For example, GetBit(Bytes("base16", "0xf0"), Int(0)) yields 1. Any index less than 4 would yield 1, and any valid index 4 or greater would yield 0. Any integer less than 8*Len(value) is a valid index.

Requires TEAL version 3 or higher.

Parameters:
  • value – The value containing bits. Can evaluate to any type.
  • index – The index of the bit to extract. Must evaluate to uint64.
pyteal.GetByte(value: pyteal.Expr, index: pyteal.Expr) → pyteal.BinaryExpr

Extract a single byte as an integer from a byte string.

Similar to GetBit, indexing begins at the first byte. For example, GetByte(Bytes("base16", "0xff0000"), Int(0)) yields 255. Any other valid index would yield 0.

Requires TEAL version 3 or higher.

Parameters:
  • value – The value containing the bytes. Must evaluate to bytes.
  • index – The index of the byte to extract. Must evaluate to an integer less than Len(value).
pyteal.Ed25519Verify(data: pyteal.Expr, sig: pyteal.Expr, key: pyteal.Expr) → pyteal.TernaryExpr

Verify the ed25519 signature of the concatenation (“ProgData” + hash_of_current_program + data).

Parameters:
  • data – The data signed by the public key. Must evalutes to bytes.
  • sig – The proposed 64-byte signature of the concatenation (“ProgData” + hash_of_current_program + data). Must evalute to bytes.
  • key – The 32 byte public key that produced the signature. Must evaluate to bytes.
pyteal.Substring(string: pyteal.Expr, start: pyteal.Expr, end: pyteal.Expr) → pyteal.Expr

Take a substring of a byte string.

Produces a new byte string consisting of the bytes starting at start up to but not including end.

This expression is similar to Extract, except this expression uses start and end indexes, while Extract uses a start index and length.

Requires TEAL version 2 or higher.

Parameters:
  • string – The byte string.
  • start – The starting index for the substring. Must be an integer less than or equal to Len(string).
  • end – The ending index for the substring. Must be an integer greater or equal to start, but less than or equal to Len(string).
pyteal.Extract(string: pyteal.Expr, start: pyteal.Expr, length: pyteal.Expr) → pyteal.Expr

Extract a section of a byte string.

Produces a new byte string consisting of the bytes starting at start up to but not including start + length.

This expression is similar to Substring, except this expression uses a start index and length, while Substring uses start and end indexes.

Requires TEAL version 5 or higher.

Parameters:
  • string – The byte string.
  • start – The starting index for the extraction. Must be an integer less than or equal to Len(string).
  • length – The number of bytes to extract. Must be an integer such that start + length <= Len(string).
pyteal.Suffix(string: pyteal.Expr, start: pyteal.Expr) → pyteal.Expr

Take a suffix of a byte string.

Produces a new byte string consisting of the suffix of the byte string starting at start

This expression is similar to Substring and Extract, except this expression only uses a start index.

Requires TEAL version 5 or higher.

Parameters:
  • string – The byte string.
  • start – The starting index for the suffix. Must be an integer less than or equal to Len(string).
pyteal.SetBit(value: pyteal.Expr, index: pyteal.Expr, newBitValue: pyteal.Expr) → pyteal.TernaryExpr

Set the bit value of an expression at a specific index.

The meaning of index differs if value is an integer or a byte string.

  • For integers, bit indexing begins with low-order bits. For example, SetBit(Int(0), Int(4), Int(1)) yields the integer 16 (2^4). Any integer less than 64 is a valid index.
  • For byte strings, bit indexing begins at the first byte. For example, SetBit(Bytes("base16", "0x00"), Int(7), Int(1)) yields the byte string 0x01. Any integer less than 8*Len(value) is a valid index.

Requires TEAL version 3 or higher.

Parameters:
  • value – The value containing bits. Can evaluate to any type.
  • index – The index of the bit to set. Must evaluate to uint64.
  • newBitValue – The new bit value to set. Must evaluate to the integer 0 or 1.
pyteal.SetByte(value: pyteal.Expr, index: pyteal.Expr, newByteValue: pyteal.Expr) → pyteal.TernaryExpr

Set a single byte in a byte string from an integer value.

Similar to SetBit, indexing begins at the first byte. For example, SetByte(Bytes("base16", "0x000000"), Int(0), Int(255)) yields the byte string 0xff0000.

Requires TEAL version 3 or higher.

Parameters:
  • value – The value containing the bytes. Must evaluate to bytes.
  • index – The index of the byte to set. Must evaluate to an integer less than Len(value).
  • newByteValue – The new byte value to set. Must evaluate to an integer less than 256.
class pyteal.NaryExpr(op: pyteal.Op, inputType: pyteal.TealType, outputType: pyteal.TealType, args: Sequence[pyteal.Expr])

Bases: pyteal.Expr

N-ary expression base class.

This type of expression takes an arbitrary number of arguments.

has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

pyteal.And(*args) → pyteal.NaryExpr

Logical and expression.

Produces 1 if all arguments are nonzero. Otherwise produces 0.

All arguments must be PyTeal expressions that evaluate to uint64, and there must be at least one argument.

Example

And(Txn.amount() == Int(500), Txn.fee() <= Int(10))

pyteal.Or(*args) → pyteal.NaryExpr

Logical or expression.

Produces 1 if any argument is nonzero. Otherwise produces 0.

All arguments must be PyTeal expressions that evaluate to uint64, and there must be at least one argument.

pyteal.Concat(*args) → pyteal.NaryExpr

Concatenate byte strings.

Produces a new byte string consisting of the contents of each of the passed in byte strings joined together.

All arguments must be PyTeal expressions that evaluate to bytes, and there must be at least one argument.

Example

Concat(Bytes("hello"), Bytes(" "), Bytes("world"))

class pyteal.WideRatio(numeratorFactors: List[pyteal.Expr], denominatorFactors: List[pyteal.Expr])

Bases: pyteal.Expr

A class used to calculate expressions of the form (N_1 * N_2 * N_3 * ...) / (D_1 * D_2 * D_3 * ...)

Use this class if all inputs to the expression are uint64s, the output fits in a uint64, and all intermediate values fit in a uint128.

__init__(numeratorFactors: List[pyteal.Expr], denominatorFactors: List[pyteal.Expr]) → None

Create a new WideRatio expression with the given numerator and denominator factors.

This will calculate (N_1 * N_2 * N_3 * ...) / (D_1 * D_2 * D_3 * ...), where each N_i represents an element in numeratorFactors and each D_i represents an element in denominatorFactors.

Requires TEAL version 5 or higher.

Parameters:
  • numeratorFactors – The factors in the numerator of the ratio. This list must have at least 1 element. If this list has exactly 1 element, then denominatorFactors must have more than 1 element (otherwise basic division should be used).
  • denominatorFactors – The factors in the denominator of the ratio. This list must have at least 1 element.
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.If(cond: pyteal.Expr, thenBranch: pyteal.Expr = None, elseBranch: pyteal.Expr = None)

Bases: pyteal.Expr

Simple two-way conditional expression.

Else(elseBranch: pyteal.Expr)
ElseIf(cond)
Then(thenBranch: pyteal.Expr)
__init__(cond: pyteal.Expr, thenBranch: pyteal.Expr = None, elseBranch: pyteal.Expr = None) → None

Create a new If expression.

When this If expression is executed, the condition will be evaluated, and if it produces a true value, thenBranch will be executed and used as the return value for this expression. Otherwise, elseBranch will be executed and used as the return value, if it is provided.

Parameters:
  • cond – The condition to check. Must evaluate to uint64.
  • thenBranch – Expression to evaluate if the condition is true.
  • elseBranch (optional) – Expression to evaluate if the condition is false. Must evaluate to the same type as thenBranch, if provided. Defaults to None.
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.Cond(*argv)

Bases: pyteal.Expr

A chainable branching expression that supports an arbitrary number of conditions.

__init__(*argv)

Create a new Cond expression.

At least one argument must be provided, and each argument must be a list with two elements. The first element is a condition which evalutes to uint64, and the second is the body of the condition, which will execute if that condition is true. All condition bodies must have the same return type. During execution, each condition is tested in order, and the first condition to evaluate to a true value will cause its associated body to execute and become the value for this Cond expression. If no condition evalutes to a true value, the Cond expression produces an error and the TEAL program terminates.

Example

Cond([Global.group_size() == Int(5), bid],
    [Global.group_size() == Int(4), redeem],
    [Global.group_size() == Int(1), wrapup])
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.Seq(*exprs)

Bases: pyteal.Expr

A control flow expression to represent a sequence of expressions.

__init__(*exprs)

Create a new Seq expression.

The new Seq expression will take on the return value of the final expression in the sequence.

Parameters:exprs – The expressions to include in this sequence. All expressions that are not the final one in this list must not return any values.

Example

Seq([
    App.localPut(Bytes("key"), Bytes("value")),
    Int(1)
])
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.Assert(cond: pyteal.Expr)

Bases: pyteal.Expr

A control flow expression to verify that a condition is true.

__init__(cond: pyteal.Expr) → None

Create an assert statement that raises an error if the condition is false.

Parameters:cond – The condition to check. Must evaluate to a uint64.
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.Err

Bases: pyteal.Expr

Expression that causes the program to immediately fail when executed.

has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.Return(value: pyteal.Expr = None)

Bases: pyteal.Expr

Return a value from the current execution context.

__init__(value: pyteal.Expr = None) → None

Create a new Return expression.

If called from the main program, this will immediately exit the program and the value returned will be the program’s success value (must be a uint64, 0 indicates failure, 1 or greater indicates success).

If called from within a subroutine, this will return from the current subroutine with either no value if the subroutine does not produce a return value, or the given return value if it does produce a return value.

has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

pyteal.Approve() → pyteal.Expr

Immediately exit the program and mark the execution as successful.

pyteal.Reject() → pyteal.Expr

Immediately exit the program and mark the execution as unsuccessful.

class pyteal.Subroutine(returnType: pyteal.TealType, name: str = None)

Bases: object

Used to create a PyTeal subroutine from a Python function.

This class is meant to be used as a function decorator. For example:

@Subroutine(TealType.uint64)
def mySubroutine(a: Expr, b: Expr) -> Expr:
    return a + b

program = Seq([
    App.globalPut(Bytes("key"), mySubroutine(Int(1), Int(2))),
    Approve(),
])
__init__(returnType: pyteal.TealType, name: str = None) → None

Define a new subroutine with the given return type.

Parameters:returnType – The type that the return value of this subroutine must conform to. TealType.none indicates that this subroutine does not return any value.
class pyteal.SubroutineDefinition(implementation: Callable[[...], pyteal.Expr], returnType: pyteal.TealType, nameStr: str = None)

Bases: object

argumentCount() → int
getDeclaration() → pyteal.SubroutineDeclaration
invoke(args: List[pyteal.Expr]) → pyteal.SubroutineCall
name() → str
nextSubroutineId = 0
class pyteal.SubroutineDeclaration(subroutine: pyteal.SubroutineDefinition, body: pyteal.Expr)

Bases: pyteal.Expr

has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.SubroutineCall(subroutine: pyteal.SubroutineDefinition, args: List[pyteal.Expr])

Bases: pyteal.Expr

has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.SubroutineFnWrapper(fnImplementation: Callable[[...], pyteal.Expr], returnType: pyteal.TealType, name: str = None)

Bases: object

has_return()
name() → str
type_of()
class pyteal.ScratchSlot(requestedSlotId: int = None)

Bases: object

Represents the allocation of a scratch space slot.

__init__(requestedSlotId: int = None)

Initializes a scratch slot with a particular id

Parameters:
  • requestedSlotId (optional) – A scratch slot id that the compiler must store the value.
  • id may be a Python int in the range [0-256) (This) –
load(type: pyteal.TealType = <TealType.anytype: 2>) → pyteal.ScratchLoad

Get an expression to load a value from this slot.

Parameters:type (optional) – The type being loaded from this slot, if known. Defaults to TealType.anytype.
nextSlotId = 256
store(value: pyteal.Expr = None) → pyteal.Expr

Get an expression to store a value in this slot.

Parameters:
  • value (optional) – The value to store in this slot. If not included, the last value on
  • stack will be stored. NOTE (the) – storing the last value on the stack breaks the typical
  • of PyTeal, only use if you know what you're doing. (semantics) –
class pyteal.ScratchLoad(slot: pyteal.ScratchSlot, type: pyteal.TealType = <TealType.anytype: 2>)

Bases: pyteal.Expr

Expression to load a value from scratch space.

__init__(slot: pyteal.ScratchSlot, type: pyteal.TealType = <TealType.anytype: 2>)

Create a new ScratchLoad expression.

Parameters:
  • slot – The slot to load the value from.
  • type (optional) – The type being loaded from this slot, if known. Defaults to TealType.anytype.
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.ScratchStore(slot: pyteal.ScratchSlot, value: pyteal.Expr)

Bases: pyteal.Expr

Expression to store a value in scratch space.

__init__(slot: pyteal.ScratchSlot, value: pyteal.Expr)

Create a new ScratchStore expression.

Parameters:
  • slot – The slot to store the value in.
  • value – The value to store.
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.ScratchStackStore(slot: pyteal.ScratchSlot)

Bases: pyteal.Expr

Expression to store a value from the stack in scratch space.

NOTE: This expression breaks the typical semantics of PyTeal, only use if you know what you’re doing.

__init__(slot: pyteal.ScratchSlot)

Create a new ScratchStackStore expression.

Parameters:slot – The slot to store the value in.
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.ScratchVar(type: pyteal.TealType = <TealType.anytype: 2>, slotId: int = None)

Bases: object

Interface around Scratch space, similiar to get/put local/global state

Example

myvar = ScratchVar(TealType.uint64)
Seq([
    myvar.store(Int(5)),
    Assert(myvar.load() == Int(5))
])
__init__(type: pyteal.TealType = <TealType.anytype: 2>, slotId: int = None)

Create a new ScratchVar with an optional type.

Parameters:
  • type (optional) – The type that this variable can hold. An error will be thrown if an expression with an incompatiable type is stored in this variable. Defaults to TealType.anytype.
  • slotId (optional) – A scratch slot id that the compiler must store the value. This id may be a Python int in the range [0-256).
load() → pyteal.ScratchLoad

Load value from Scratch Space

storage_type() → pyteal.TealType

Get the type of expressions that can be stored in this ScratchVar.

store(value: pyteal.Expr) → pyteal.Expr

Store value in Scratch Space

Parameters:value – The value to store. Must conform to this ScratchVar’s type.
class pyteal.MaybeValue(op: pyteal.Op, type: pyteal.TealType, *, immediate_args: List[Union[str, int]] = None, args: List[pyteal.Expr] = None)

Bases: pyteal.MultiValue

Represents a get operation returning a value that may not exist.

__init__(op: pyteal.Op, type: pyteal.TealType, *, immediate_args: List[Union[str, int]] = None, args: List[pyteal.Expr] = None)

Create a new MaybeValue.

Parameters:
  • op – The operation that returns values.
  • type – The type of the returned value.
  • immediate_args (optional) – Immediate arguments for the op. Defaults to None.
  • args (optional) – Stack arguments for the op. Defaults to None.
hasValue() → pyteal.ScratchLoad

Check if the value exists.

This will return 1 if the value exists, otherwise 0.

slotOk

Get the scratch slot that stores hasValue.

Note: This is mainly added for backwards compatability and normally shouldn’t be used directly in pyteal code.

slotValue

Get the scratch slot that stores the value or the zero value for the type if the value doesn’t exist.

Note: This is mainly added for backwards compatability and normally shouldn’t be used directly in pyteal code.

value() → pyteal.ScratchLoad

Get the value.

If the value exists, it will be returned. Otherwise, the zero value for this type will be returned (i.e. either 0 or an empty byte string, depending on the type).

class pyteal.MultiValue(op: pyteal.Op, types: List[pyteal.TealType], *, immediate_args: List[Union[str, int]] = None, args: List[pyteal.Expr] = None)

Bases: pyteal.LeafExpr

Represents an operation that returns more than one value

__init__(op: pyteal.Op, types: List[pyteal.TealType], *, immediate_args: List[Union[str, int]] = None, args: List[pyteal.Expr] = None)

Create a new MultiValue.

Parameters:
  • op – The operation that returns values.
  • types – The types of the returned values.
  • immediate_args (optional) – Immediate arguments for the op. Defaults to None.
  • args (optional) – Stack arguments for the op. Defaults to None.
outputReducer(reducer: Callable[[...], pyteal.Expr]) → pyteal.Expr
type_of()

Get the return type of this expression.

pyteal.BytesAdd(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Add two numbers as bytes.

Produces left + right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesMinus(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Subtract two numbers as bytes.

Produces left - right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesDiv(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Divide two numbers as bytes.

Produces left / right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Panics if right is 0.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesMul(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Multiply two numbers as bytes.

Produces left * right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesMod(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Modulo expression with bytes as arguments.

Produces left % right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Panics if right is 0.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesAnd(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Bitwise and expression with bytes as arguments.

Produces left & right. Left and right are zero-left extended to the greater of their lengths. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesOr(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Bitwise or expression with bytes as arguments.

Produces left | right. Left and right are zero-left extended to the greater of their lengths. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesXor(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Bitwise xor expression with bytes as arguments.

Produces left ^ right. Left and right are zero-left extended to the greater of their lengths. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesEq(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Equality expression with bytes as arguments.

Checks if left == right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesNeq(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Difference expression with bytes as arguments.

Checks if left != right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesLt(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Less than expression with bytes as arguments.

Checks if left < right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesLe(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Less than or equal to expression with bytes as arguments.

Checks if left <= right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesGt(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Greater than expression with bytes as arguments.

Checks if left > right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesGe(left: pyteal.Expr, right: pyteal.Expr) → pyteal.BinaryExpr

Greater than or equal to expression with bytes as arguments.

Checks if left >= right, where left and right are interpreted as big-endian unsigned integers. Arguments must not exceed 64 bytes.

Requires TEAL version 4 or higher.

Parameters:
  • left – Must evaluate to bytes.
  • right – Must evaluate to bytes.
pyteal.BytesNot(arg: pyteal.Expr) → pyteal.UnaryExpr

Get the bitwise inverse of bytes.

Produces ~arg. Argument must not exceed 64 bytes.

Requires TEAL version 4 or higher.

pyteal.BytesSqrt(arg: pyteal.Expr) → pyteal.UnaryExpr

Get the bytes square root of bytes.

This will return the largest integer X such that X^2 <= arg.

Requires TEAL version 6 or higher.

pyteal.BytesZero(arg: pyteal.Expr) → pyteal.UnaryExpr

Get a byte-array of a specified length, containing all zero bytes.

Argument must evaluate to uint64.

Requires TEAL version 4 or higher.

pyteal.ExtractUint16(string: pyteal.Expr, offset: pyteal.Expr) → pyteal.BinaryExpr

Extract 2 bytes (16 bits) and convert them to an integer.

The bytes starting at offset up to but not including offset + 2 will be interpreted as a big-endian unsigned integer.

If offset + 2 exceeds Len(string), the program fails.

Requires TEAL version 5 or higher.

Parameters:
  • string – The bytestring to extract from. Must evaluate to bytes.
  • offset – The offset in the bytestring to start extracing. Must evaluate to uint64.
pyteal.ExtractUint32(string: pyteal.Expr, offset: pyteal.Expr) → pyteal.BinaryExpr

Extract 4 bytes (32 bits) and convert them to an integer.

The bytes starting at offset up to but not including offset + 4 will be interpreted as a big-endian unsigned integer.

If offset + 4 exceeds Len(string), the program fails.

Requires TEAL version 5 or higher.

Parameters:
  • string – The bytestring to extract from. Must evaluate to bytes.
  • offset – The offset in the bytestring to start extracing. Must evaluate to uint64.
pyteal.ExtractUint64(string: pyteal.Expr, offset: pyteal.Expr) → pyteal.BinaryExpr

Extract 8 bytes (64 bits) and convert them to an integer.

The bytes starting at offset up to but not including offset + 8 will be interpreted as a big-endian unsigned integer.

If offset + 8 exceeds Len(string), the program fails.

Requires TEAL version 5 or higher.

Parameters:
  • string – The bytestring to extract from. Must evaluate to bytes.
  • offset – The offset in the bytestring to start extracing. Must evaluate to uint64.
pyteal.Log(message: pyteal.Expr) → pyteal.UnaryExpr

Write a message to log state of the current application.

This will fail if called more than MaxLogCalls times in a program (32 as of TEAL v5), or if the sum of the lengths of all logged messages in a program exceeds 1024 bytes.

Parameters:message – The message to write. Must evaluate to bytes.

Requires TEAL version 5 or higher.

class pyteal.While(cond: pyteal.Expr)

Bases: pyteal.Expr

While expression.

Do(doBlock: pyteal.Expr)
__init__(cond: pyteal.Expr) → None

Create a new While expression.

When this While expression is executed, the condition will be evaluated, and if it produces a true value, doBlock will be executed and return to the start of the expression execution. Otherwise, no branch will be executed.

Parameters:cond – The condition to check. Must evaluate to uint64.
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.For(start: pyteal.Expr, cond: pyteal.Expr, step: pyteal.Expr)

Bases: pyteal.Expr

For expression.

Do(doBlock: pyteal.Expr)
__init__(start: pyteal.Expr, cond: pyteal.Expr, step: pyteal.Expr) → None

Create a new For expression.

When this For expression is executed, the condition will be evaluated, and if it produces a true value, doBlock will be executed and return to the start of the expression execution. Otherwise, no branch will be executed.

Parameters:
  • start – Expression setting the variable’s initial value
  • cond – The condition to check. Must evaluate to uint64.
  • step – Expression to update the variable’s value.
has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.Break

Bases: pyteal.Expr

A break expression

__init__() → None

Create a new break expression.

This operation is only permitted in a loop.

has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.Continue

Bases: pyteal.Expr

A continue expression

__init__() → None

Create a new continue expression.

This operation is only permitted in a loop.

has_return()

Check if this expression always returns from the current subroutine or program.

type_of()

Get the return type of this expression.

class pyteal.Op

Bases: enum.Enum

Enum of program opcodes.

acct_params_get = OpType(value='acct_params_get', mode=<Mode.Application: 2>, min_version=6)
add = OpType(value='+', mode=<Mode.Application|Signature: 3>, min_version=2)
addr = OpType(value='addr', mode=<Mode.Application|Signature: 3>, min_version=2)
addw = OpType(value='addw', mode=<Mode.Application|Signature: 3>, min_version=2)
app_global_del = OpType(value='app_global_del', mode=<Mode.Application: 2>, min_version=2)
app_global_get = OpType(value='app_global_get', mode=<Mode.Application: 2>, min_version=2)
app_global_get_ex = OpType(value='app_global_get_ex', mode=<Mode.Application: 2>, min_version=2)
app_global_put = OpType(value='app_global_put', mode=<Mode.Application: 2>, min_version=2)
app_local_del = OpType(value='app_local_del', mode=<Mode.Application: 2>, min_version=2)
app_local_get = OpType(value='app_local_get', mode=<Mode.Application: 2>, min_version=2)
app_local_get_ex = OpType(value='app_local_get_ex', mode=<Mode.Application: 2>, min_version=2)
app_local_put = OpType(value='app_local_put', mode=<Mode.Application: 2>, min_version=2)
app_opted_in = OpType(value='app_opted_in', mode=<Mode.Application: 2>, min_version=2)
app_params_get = OpType(value='app_params_get', mode=<Mode.Application: 2>, min_version=5)
arg = OpType(value='arg', mode=<Mode.Signature: 1>, min_version=2)
args = OpType(value='args', mode=<Mode.Signature: 1>, min_version=5)
assert_ = OpType(value='assert', mode=<Mode.Application|Signature: 3>, min_version=3)
asset_holding_get = OpType(value='asset_holding_get', mode=<Mode.Application: 2>, min_version=2)
asset_params_get = OpType(value='asset_params_get', mode=<Mode.Application: 2>, min_version=2)
b = OpType(value='b', mode=<Mode.Application|Signature: 3>, min_version=2)
b_add = OpType(value='b+', mode=<Mode.Application|Signature: 3>, min_version=4)
b_and = OpType(value='b&', mode=<Mode.Application|Signature: 3>, min_version=4)
b_div = OpType(value='b/', mode=<Mode.Application|Signature: 3>, min_version=4)
b_eq = OpType(value='b==', mode=<Mode.Application|Signature: 3>, min_version=4)
b_ge = OpType(value='b>=', mode=<Mode.Application|Signature: 3>, min_version=4)
b_gt = OpType(value='b>', mode=<Mode.Application|Signature: 3>, min_version=4)
b_le = OpType(value='b<=', mode=<Mode.Application|Signature: 3>, min_version=4)
b_lt = OpType(value='b<', mode=<Mode.Application|Signature: 3>, min_version=4)
b_minus = OpType(value='b-', mode=<Mode.Application|Signature: 3>, min_version=4)
b_mod = OpType(value='b%', mode=<Mode.Application|Signature: 3>, min_version=4)
b_mul = OpType(value='b*', mode=<Mode.Application|Signature: 3>, min_version=4)
b_neq = OpType(value='b!=', mode=<Mode.Application|Signature: 3>, min_version=4)
b_not = OpType(value='b~', mode=<Mode.Application|Signature: 3>, min_version=4)
b_or = OpType(value='b|', mode=<Mode.Application|Signature: 3>, min_version=4)
b_xor = OpType(value='b^', mode=<Mode.Application|Signature: 3>, min_version=4)
balance = OpType(value='balance', mode=<Mode.Application: 2>, min_version=2)
bitlen = OpType(value='bitlen', mode=<Mode.Application|Signature: 3>, min_version=4)
bitwise_and = OpType(value='&', mode=<Mode.Application|Signature: 3>, min_version=2)
bitwise_not = OpType(value='~', mode=<Mode.Application|Signature: 3>, min_version=2)
bitwise_or = OpType(value='|', mode=<Mode.Application|Signature: 3>, min_version=2)
bitwise_xor = OpType(value='^', mode=<Mode.Application|Signature: 3>, min_version=2)
bnz = OpType(value='bnz', mode=<Mode.Application|Signature: 3>, min_version=2)
bsqrt = OpType(value='bsqrt', mode=<Mode.Application|Signature: 3>, min_version=6)
btoi = OpType(value='btoi', mode=<Mode.Application|Signature: 3>, min_version=2)
byte = OpType(value='byte', mode=<Mode.Application|Signature: 3>, min_version=2)
bytec = OpType(value='bytec', mode=<Mode.Application|Signature: 3>, min_version=2)
bytec_0 = OpType(value='bytec_0', mode=<Mode.Application|Signature: 3>, min_version=2)
bytec_1 = OpType(value='bytec_1', mode=<Mode.Application|Signature: 3>, min_version=2)
bytec_2 = OpType(value='bytec_2', mode=<Mode.Application|Signature: 3>, min_version=2)
bytec_3 = OpType(value='bytec_3', mode=<Mode.Application|Signature: 3>, min_version=2)
bytecblock = OpType(value='bytecblock', mode=<Mode.Application|Signature: 3>, min_version=2)
bz = OpType(value='bz', mode=<Mode.Application|Signature: 3>, min_version=2)
bzero = OpType(value='bzero', mode=<Mode.Application|Signature: 3>, min_version=4)
callsub = OpType(value='callsub', mode=<Mode.Application|Signature: 3>, min_version=4)
concat = OpType(value='concat', mode=<Mode.Application|Signature: 3>, min_version=2)
cover = OpType(value='cover', mode=<Mode.Application|Signature: 3>, min_version=5)
dig = OpType(value='dig', mode=<Mode.Application|Signature: 3>, min_version=3)
div = OpType(value='/', mode=<Mode.Application|Signature: 3>, min_version=2)
divmodw = OpType(value='divmodw', mode=<Mode.Application|Signature: 3>, min_version=4)
divw = OpType(value='divw', mode=<Mode.Application|Signature: 3>, min_version=6)
dup = OpType(value='dup', mode=<Mode.Application|Signature: 3>, min_version=2)
dup2 = OpType(value='dup2', mode=<Mode.Application|Signature: 3>, min_version=2)
ecdsa_pk_decompress = OpType(value='ecdsa_pk_decompress', mode=<Mode.Application|Signature: 3>, min_version=5)
ecdsa_pk_recover = OpType(value='ecdsa_pk_recover', mode=<Mode.Application|Signature: 3>, min_version=5)
ecdsa_verify = OpType(value='ecdsa_verify', mode=<Mode.Application|Signature: 3>, min_version=5)
ed25519verify = OpType(value='ed25519verify', mode=<Mode.Application|Signature: 3>, min_version=2)
eq = OpType(value='==', mode=<Mode.Application|Signature: 3>, min_version=2)
err = OpType(value='err', mode=<Mode.Application|Signature: 3>, min_version=2)
exp = OpType(value='exp', mode=<Mode.Application|Signature: 3>, min_version=4)
expw = OpType(value='expw', mode=<Mode.Application|Signature: 3>, min_version=4)
extract = OpType(value='extract', mode=<Mode.Application|Signature: 3>, min_version=5)
extract3 = OpType(value='extract3', mode=<Mode.Application|Signature: 3>, min_version=5)
extract_uint16 = OpType(value='extract_uint16', mode=<Mode.Application|Signature: 3>, min_version=5)
extract_uint32 = OpType(value='extract_uint32', mode=<Mode.Application|Signature: 3>, min_version=5)
extract_uint64 = OpType(value='extract_uint64', mode=<Mode.Application|Signature: 3>, min_version=5)
gaid = OpType(value='gaid', mode=<Mode.Application: 2>, min_version=4)
gaids = OpType(value='gaids', mode=<Mode.Application: 2>, min_version=4)
ge = OpType(value='>=', mode=<Mode.Application|Signature: 3>, min_version=2)
getbit = OpType(value='getbit', mode=<Mode.Application|Signature: 3>, min_version=3)
getbyte = OpType(value='getbyte', mode=<Mode.Application|Signature: 3>, min_version=3)
gitxn = OpType(value='gitxn', mode=<Mode.Application: 2>, min_version=6)
gitxna = OpType(value='gitxna', mode=<Mode.Application: 2>, min_version=6)
gitxnas = OpType(value='gitxnas', mode=<Mode.Application: 2>, min_version=6)
gload = OpType(value='gload', mode=<Mode.Application: 2>, min_version=4)
gloads = OpType(value='gloads', mode=<Mode.Application: 2>, min_version=4)
gloadss = OpType(value='gloadss', mode=<Mode.Application: 2>, min_version=6)
global_ = OpType(value='global', mode=<Mode.Application|Signature: 3>, min_version=2)
gt = OpType(value='>', mode=<Mode.Application|Signature: 3>, min_version=2)
gtxn = OpType(value='gtxn', mode=<Mode.Application|Signature: 3>, min_version=2)
gtxna = OpType(value='gtxna', mode=<Mode.Application|Signature: 3>, min_version=2)
gtxnas = OpType(value='gtxnas', mode=<Mode.Application|Signature: 3>, min_version=5)
gtxns = OpType(value='gtxns', mode=<Mode.Application|Signature: 3>, min_version=3)
gtxnsa = OpType(value='gtxnsa', mode=<Mode.Application|Signature: 3>, min_version=3)
gtxnsas = OpType(value='gtxnsas', mode=<Mode.Application|Signature: 3>, min_version=5)
int = OpType(value='int', mode=<Mode.Application|Signature: 3>, min_version=2)
intc = OpType(value='intc', mode=<Mode.Application|Signature: 3>, min_version=2)
intc_0 = OpType(value='intc_0', mode=<Mode.Application|Signature: 3>, min_version=2)
intc_1 = OpType(value='intc_1', mode=<Mode.Application|Signature: 3>, min_version=2)
intc_2 = OpType(value='intc_2', mode=<Mode.Application|Signature: 3>, min_version=2)
intc_3 = OpType(value='intc_3', mode=<Mode.Application|Signature: 3>, min_version=2)
intcblock = OpType(value='intcblock', mode=<Mode.Application|Signature: 3>, min_version=2)
itob = OpType(value='itob', mode=<Mode.Application|Signature: 3>, min_version=2)
itxn = OpType(value='itxn', mode=<Mode.Application: 2>, min_version=5)
itxn_begin = OpType(value='itxn_begin', mode=<Mode.Application: 2>, min_version=5)
itxn_field = OpType(value='itxn_field', mode=<Mode.Application: 2>, min_version=5)
itxn_next = OpType(value='itxn_next', mode=<Mode.Application: 2>, min_version=6)
itxn_submit = OpType(value='itxn_submit', mode=<Mode.Application: 2>, min_version=5)
itxna = OpType(value='itxna', mode=<Mode.Application: 2>, min_version=5)
itxnas = OpType(value='itxnas', mode=<Mode.Application: 2>, min_version=6)
keccak256 = OpType(value='keccak256', mode=<Mode.Application|Signature: 3>, min_version=2)
le = OpType(value='<=', mode=<Mode.Application|Signature: 3>, min_version=2)
len = OpType(value='len', mode=<Mode.Application|Signature: 3>, min_version=2)
load = OpType(value='load', mode=<Mode.Application|Signature: 3>, min_version=2)
loads = OpType(value='loads', mode=<Mode.Application|Signature: 3>, min_version=5)
log = OpType(value='log', mode=<Mode.Application: 2>, min_version=5)
logic_and = OpType(value='&&', mode=<Mode.Application|Signature: 3>, min_version=2)
logic_not = OpType(value='!', mode=<Mode.Application|Signature: 3>, min_version=2)
logic_or = OpType(value='||', mode=<Mode.Application|Signature: 3>, min_version=2)
lt = OpType(value='<', mode=<Mode.Application|Signature: 3>, min_version=2)
method_signature = OpType(value='method', mode=<Mode.Application|Signature: 3>, min_version=2)
min_balance = OpType(value='min_balance', mode=<Mode.Application: 2>, min_version=3)
min_version

Get the minimum version where this op is available.

minus = OpType(value='-', mode=<Mode.Application|Signature: 3>, min_version=2)
mod = OpType(value='%', mode=<Mode.Application|Signature: 3>, min_version=2)
mode

Get the modes where this op is available.

mul = OpType(value='*', mode=<Mode.Application|Signature: 3>, min_version=2)
mulw = OpType(value='mulw', mode=<Mode.Application|Signature: 3>, min_version=2)
neq = OpType(value='!=', mode=<Mode.Application|Signature: 3>, min_version=2)
pop = OpType(value='pop', mode=<Mode.Application|Signature: 3>, min_version=2)
pushbytes = OpType(value='pushbytes', mode=<Mode.Application|Signature: 3>, min_version=3)
pushint = OpType(value='pushint', mode=<Mode.Application|Signature: 3>, min_version=3)
retsub = OpType(value='retsub', mode=<Mode.Application|Signature: 3>, min_version=4)
return_ = OpType(value='return', mode=<Mode.Application|Signature: 3>, min_version=2)
select = OpType(value='select', mode=<Mode.Application|Signature: 3>, min_version=3)
setbit = OpType(value='setbit', mode=<Mode.Application|Signature: 3>, min_version=3)
setbyte = OpType(value='setbyte', mode=<Mode.Application|Signature: 3>, min_version=3)
sha256 = OpType(value='sha256', mode=<Mode.Application|Signature: 3>, min_version=2)
sha512_256 = OpType(value='sha512_256', mode=<Mode.Application|Signature: 3>, min_version=2)
shl = OpType(value='shl', mode=<Mode.Application|Signature: 3>, min_version=4)
shr = OpType(value='shr', mode=<Mode.Application|Signature: 3>, min_version=4)
sqrt = OpType(value='sqrt', mode=<Mode.Application|Signature: 3>, min_version=4)
store = OpType(value='store', mode=<Mode.Application|Signature: 3>, min_version=2)
stores = OpType(value='stores', mode=<Mode.Application|Signature: 3>, min_version=5)
substring = OpType(value='substring', mode=<Mode.Application|Signature: 3>, min_version=2)
substring3 = OpType(value='substring3', mode=<Mode.Application|Signature: 3>, min_version=2)
swap = OpType(value='swap', mode=<Mode.Application|Signature: 3>, min_version=3)
txn = OpType(value='txn', mode=<Mode.Application|Signature: 3>, min_version=2)
txna = OpType(value='txna', mode=<Mode.Application|Signature: 3>, min_version=2)
txnas = OpType(value='txnas', mode=<Mode.Application|Signature: 3>, min_version=5)
uncover = OpType(value='uncover', mode=<Mode.Application|Signature: 3>, min_version=5)
class pyteal.Mode

Bases: enum.Flag

Enum of program running modes.

Application = 2
Signature = 1
class pyteal.TealComponent(expr: Optional[Expr])

Bases: abc.ABC

class Context

Bases: object

class EqualityContext

Bases: contextlib.AbstractContextManager

checkExpr = True
classmethod ignoreExprEquality()
assemble() → str
assignSlot(slot: ScratchSlot, location: int) → None
getSlots() → List[ScratchSlot]
getSubroutines() → List[SubroutineDefinition]
resolveSubroutine(subroutine: SubroutineDefinition, label: str) → None
class pyteal.TealOp(expr: Optional[Expr], op: pyteal.Op, *args)

Bases: pyteal.TealComponent

assemble() → str
assignSlot(slot: ScratchSlot, location: int) → None
getOp() → pyteal.Op
getSlots() → List[ScratchSlot]
getSubroutines() → List[SubroutineDefinition]
resolveSubroutine(subroutine: SubroutineDefinition, label: str) → None
class pyteal.TealLabel(expr: Optional[Expr], label: pyteal.ir.labelref.LabelReference, comment: str = None)

Bases: pyteal.TealComponent

assemble() → str
getLabelRef() → pyteal.ir.labelref.LabelReference
class pyteal.TealBlock(ops: List[pyteal.TealOp])

Bases: abc.ABC

Represents a basic block of TealComponents in a graph.

classmethod FromOp(options: CompileOptions, op: pyteal.TealOp, *args) → Tuple[TealBlock, TealSimpleBlock]

Create a path of blocks from a TealOp and its arguments.

Returns:The starting and ending block of the path that encodes the given TealOp and arguments.
classmethod Iterate(start: pyteal.TealBlock) → Iterator[pyteal.TealBlock]

Perform a depth-first search of the graph of blocks starting with start.

classmethod NormalizeBlocks(start: pyteal.TealBlock) → pyteal.TealBlock

Minimize the number of blocks in the graph of blocks starting with start by combining sequential blocks. This operation does not alter the operations of the graph or the functionality of its underlying program, however it does mutate the input graph.

Returns:The new starting point of the altered graph. May be the same or differant than start.
addIncoming(parent: Optional[pyteal.TealBlock] = None, visited: List[TealBlock] = None) → None

Calculate the parent blocks for this block and its children.

Parameters:
  • parent (optional) – The parent block to this one, if it has one. Defaults to None.
  • visited (optional) – Used internally to remember blocks that have been visited. Set to None.
getOutgoing() → List[pyteal.TealBlock]

Get this block’s children blocks, if any.

isTerminal() → bool

Check if this block ends the program.

replaceOutgoing(oldBlock: pyteal.TealBlock, newBlock: pyteal.TealBlock) → None

Replace one of this block’s child blocks.

validateSlots(slotsInUse: Set[ScratchSlot] = None, visited: Set[Tuple[int, ...]] = None) → List[pyteal.TealCompileError]
validateTree(parent: Optional[pyteal.TealBlock] = None, visited: List[TealBlock] = None) → None

Check that this block and its children have valid parent pointers.

Parameters:
  • parent (optional) – The parent block to this one, if it has one. Defaults to None.
  • visited (optional) – Used internally to remember blocks that have been visited. Set to None.
class pyteal.TealSimpleBlock(ops: List[pyteal.TealOp])

Bases: pyteal.TealBlock

Represents a basic block of TealComponents in a graph that does not contain a branch condition.

getOutgoing() → List[pyteal.TealBlock]

Get this block’s children blocks, if any.

replaceOutgoing(oldBlock: pyteal.TealBlock, newBlock: pyteal.TealBlock) → None

Replace one of this block’s child blocks.

setNextBlock(block: pyteal.TealBlock) → None

Set the block that follows this one.

class pyteal.TealConditionalBlock(ops: List[pyteal.TealOp])

Bases: pyteal.TealBlock

Represents a basic block of TealComponents in a graph ending with a branch condition.

getOutgoing() → List[pyteal.TealBlock]

Get this block’s children blocks, if any.

replaceOutgoing(oldBlock: pyteal.TealBlock, newBlock: pyteal.TealBlock) → None

Replace one of this block’s child blocks.

setFalseBlock(block: pyteal.TealBlock) → None

Set the block that this one should branch to if its condition is false.

setTrueBlock(block: pyteal.TealBlock) → None

Set the block that this one should branch to if its condition is true.

class pyteal.LabelReference(label: str)

Bases: object

addPrefix(prefix: str) → None
getLabel() → str
class pyteal.CompileOptions(*, mode: pyteal.Mode = <Mode.Signature: 1>, version: int = 2)

Bases: object

addLoopBreakBlock(block: pyteal.TealSimpleBlock) → None
addLoopContinueBlock(block: pyteal.TealSimpleBlock) → None
enterLoop() → None
exitLoop() → Tuple[List[pyteal.TealSimpleBlock], List[pyteal.TealSimpleBlock]]
isInLoop() → bool
setSubroutine(subroutine: Optional[pyteal.SubroutineDefinition]) → None
pyteal.compileTeal(ast: pyteal.Expr, mode: pyteal.Mode, *, version: int = 2, assembleConstants: bool = False) → str

Compile a PyTeal expression into TEAL assembly.

Parameters:
  • ast – The PyTeal expression to assemble.
  • mode – The mode of the program to assemble. Must be Signature or Application.
  • version (optional) – The TEAL version used to assemble the program. This will determine which expressions and fields are able to be used in the program and how expressions compile to TEAL opcodes. Defaults to 2 if not included.
  • assembleConstants (optional) – When true, the compiler will produce a program with fully assembled constants, rather than using the pseudo-ops int, byte, and addr. These constants will be assembled in the most space-efficient way, so enabling this may reduce the compiled program’s size. Enabling this option requires a minimum TEAL version of 3. Defaults to false.
Returns:

A TEAL assembly program compiled from the input expression.

Raises:
  • TealInputError – if an operation in ast is not supported by the supplied mode and version.
  • TealInternalError – if an internal error is encounter during compilation.
class pyteal.TealType

Bases: enum.Enum

Teal type enum.

anytype = 2
bytes = 1
none = 3
uint64 = 0
exception pyteal.TealInternalError(message: str)

Bases: Exception

exception pyteal.TealTypeError(actual, expected)

Bases: Exception

exception pyteal.TealInputError(msg: str)

Bases: Exception

exception pyteal.TealCompileError(msg: str, sourceExpr: Optional[Expr])

Bases: Exception

Indices and tables