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.Signature))
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 Operators), 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 2
txn TypeEnum
int pay
==
global GroupSize
int 1
==
&&
txn Receiver
addr ZZAF5ARA4MEC5PVDOP64JM5O5MQST63Q2KOY2FLYFLXXD3PFSNJJBYAFZM
==
&&
txn CloseRemainderTo
global ZeroAddress
==
&&
txn RekeyTo
global ZeroAddress
==
&&
txn Fee
int 1000
<=
&&
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 and 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.Signature))
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.Signature))
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.Signature))
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.Application)
f.write(compiled)
with open('vote_clear_state.teal', 'w') as f:
compiled = compileTeal(clear_state_program(), Mode.Application)
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):
lower8 = (1 << 8) - 1
charList = [
(i >> (8*7)) & lower8,
(i >> (8*6)) & lower8,
(i >> (8*5)) & lower8,
(i >> (8*4)) & lower8,
(i >> (8*3)) & lower8,
(i >> (8*2)) & lower8,
(i >> (8*1)) & lower8,
i & lower8
]
string = ''.join(chr(c) for c in charList)
return string.encode('latin1')
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.Application)
# 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.Application)
# 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.Application)
f.write(compiled)
with open('asset_clear_state.teal', 'w') as f:
compiled = compileTeal(clear_state_program(), Mode.Application)
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.Application)
f.write(compiled)
with open('security_token_clear_state.teal', 'w') as f:
compiled = compileTeal(clear_state_program(), Mode.Application)
f.write(compiled)
Data Types and Constants¶
A PyTeal expression has one of the following two data types:
TealType.uint64
, 64 bit unsigned integerTealType.bytes
, a slice of bytes
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:
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 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 Operators 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 aTealType.bytes
value from aTealType.uint64
valuen
Btoi(b)
: generate aTealType.uint64
value from aTealType.bytes
valueb
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 integers, 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 Operators¶
An arithmetic expression is an expression that results in a TealType.uint64
value.
In PyTeal, arithmetic expressions include integer arithmetics operators and boolean operators.
We overloaded all integer arithmetics operator in Python.
Operator | Overloaded | Semantics | Example |
---|---|---|---|
Lt(a, b) |
< |
1 if a is less than b, 0 otherwise | Int(1) < Int(5) |
Gt(a, b) |
> |
1 if a is greater than b, 0 otherwise | Int(1) > Int(5) |
Le(a, b) |
<= |
1 if a is no greater than b, 0 otherwise | Int(1) <= Int(5) |
Ge(a, b) |
>= |
1 if a is no less than b, 0 otherwise | Int(1) >= Int(5) |
Add(a, b) |
+ |
a + b, error (panic) if overflow | Int(1) + Int(5) |
Minus(a, b) |
- |
a - b, error if underflow | Int(5) - Int(1) |
Mul(a, b) |
* |
a * b, error if overflow | Int(2) * Int(3) |
Div(a, b) |
/ |
a / b, error if devided by zero | Int(3) / Int(2) |
Mod(a, b) |
% |
a % b, modulo operation | Int(7) % Int(3) |
Eq(a, b) |
== |
1 if a equals b, 0 otherwise | Int(7) == Int(7) |
Neq(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, bitwise and operation | Int(1) & Int(3) |
BitwiseOr(a,b) |
| |
a | b, bitwise or operation | Int(2) | Int(5) |
BitwiseXor(a,b) |
^ |
a ^ b, bitwise xor operation | Int(3) ^ Int(7) |
BitwiseNot(a) |
~ |
~a, bitwise complement operation | ~Int(1) |
All these operators takes two TealType.uint64
values.
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 arguements when called as functions:
And(a, b, ...)
Or(a, b, ...)
The associativity and precedence of the overloaded Python arithmatic operators are the same as the original python operators . For example:
Int(1) + Int(2) + Int(3)
is equivalent toAdd(Add(Int(1), Int(2)), Int(3))
Int(1) + Int(2) * Int(3)
is equivalent toAdd(Int(1), Mul(Int(2), Int(3)))
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
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. Below are the PyTeal expressions that refer to transaction fields:
Operator | Type | Notes |
---|---|---|
Txn.sender() |
TealType.bytes |
32 byte address |
Txn.fee() |
TealType.uint64 |
in microAlgos |
Txn.first_valid() |
TealType.uint64 |
round number |
Txn.last_valid() |
TealType.uint64 |
round number |
Txn.note() |
TealType.bytes |
transaction note in bytes |
Txn.lease() |
TealType.bytes |
transaction lease in bytes |
Txn.receiver() |
TealType.bytes |
32 byte address |
Txn.amount() |
TealType.uint64 |
in microAlgos |
Txn.close_remainder_to() |
TealType.bytes |
32 byte address |
Txn.vote_pk() |
TealType.bytes |
32 byte address |
Txn.selection_pk() |
TealType.bytes |
32 byte address |
Txn.vote_first() |
TealType.uint64 |
|
Txn.vote_last() |
TealType.uint64 |
|
Txn.vote_key_dilution() |
TealType.uint64 |
|
Txn.type() |
TealType.bytes |
|
Txn.type_enum() |
TealType.uint64 |
see table below |
Txn.xfer_asset() |
TealType.uint64 |
asset ID |
Txn.asset_amount() |
TealType.uint64 |
value in Asset’s units |
Txn.asset_sender() |
TealType.bytes |
32 byte address, causes clawback of all value if sender is the Clawback |
Txn.asset_receiver() |
TealType.bytes |
32 byte address |
Txn.asset_close_to() |
TealType.bytes |
32 byte address |
Txn.group_index() |
TealType.uint64 |
position of this transaction within a transaction group |
Txn.tx_id() |
TealType.bytes |
the computed ID for this transaction, 32 bytes |
Txn.application_id() |
TealType.uint64 |
|
Txn.on_completion() |
TealType.uint64 |
|
Txn.approval_program() |
TealType.bytes |
|
Txn.clear_state_program() |
TealType.bytes |
|
Txn.rekey_to() |
TealType.bytes |
32 byte address |
Txn.config_asset() |
TealType.uint64 |
|
Txn.config_asset_total() |
TealType.uint64 |
|
Txn.config_asset_decimals() |
TealType.uint64 |
|
Txn.config_asset_default_frozen() |
TealType.uint64 |
|
Txn.config_asset_unit_name() |
TealType.bytes |
|
Txn.config_asset_name() |
TealType.bytes |
|
Txn.config_asset_url() |
TealType.bytes |
|
Txn.config_asset_metadata_hash() |
TealType.bytes |
|
Txn.config_asset_manager() |
TealType.bytes |
32 byte address |
Txn.config_asset_reserve() |
TealType.bytes |
32 byte address |
Txn.config_asset_freeze() |
TealType.bytes |
32 byte address |
Txn.config_asset_clawback() |
TealType.bytes |
32 byte address |
Txn.freeze_asset() |
TealType.uint64 |
|
Txn.freeze_asset_account() |
TealType.bytes |
32 byte address |
Txn.freeze_asset_frozen() |
TealType.uint64 |
|
Txn.application_args |
TealType.bytes[] |
Array of application arguments |
Txn.accounts |
TealType.bytes[] |
Array of additional application accounts |
Transaction Type¶
The Txn.type_enum()
values can be checked using the TxnType
enum:
Value | Numerical Value | Type String | Description |
---|---|---|---|
TxnType.Unknown |
0 |
unkown | 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 |
Tranasction Array Fields¶
Some of the exposed transaction fields are arrays with the type TealType.bytes[]
. These
fields are Txn.application_args
and Txn.accounts
.
The length of these array fields can be found using the .length()
method, and individual
items can be accesses 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
Special case: Txn.accounts
¶
The Txn.accounts
is a special case array. Normal arrays in PyTeal are 0
-indexed, but
this one is 1
-indexed with a special value at index 0
, the sender’s address. That
means if Txn.accounts.length()
is 2, then indexes 0
, 1
, and 2
will
be present. In fact, Txn.accounts[0]
will always evaluate to the sender’s address, even when
Txn.accounts.length()
is 0
.
Atomic Tranfer 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
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
.
Global Parameters¶
Information about the current state of the blockchain can be obtained using the following
Global
expressions:
Operator | Type | Notes |
---|---|---|
Global.min_txn_fee() |
TealType.uint64 |
in microAlgos |
Global.min_balance() |
TealType.uint64 |
in mircoAlgos |
Global.max_txn_life() |
TealType.uint64 |
number of rounds |
Global.zero_address() |
TealType.bytes |
32 byte address of all zero bytes |
Global.group_size() |
TealType.uint64 |
number of txns in this atomic transaction group, at least 1 |
Global.logic_sig_version() |
TealType.uint64 |
the maximum supported TEAL version |
Global.round() |
TealType.uint64 |
the current round number |
Global.latest_timestamp() |
TealType.uint64 |
the latest confirmed block UNIX timestamp |
Global.current_application_id() |
TealType.uint64 |
the ID of the current application executing |
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. All TEAL opcodes except crypto primitives have cost 1. Below is how you express cryptographic primitives in PyTeal:
Operator | Cost | Description |
---|---|---|
Sha256(e) |
7 | SHA-256 hash function, produces 32 bytes |
Keccak256(e) |
26 | Keccak-256 hash funciton, produces 32 bytes |
Sha512_256(e) |
9 | SHA512-256 hash function, produces 32 bytes |
Ed25519Verify(d, s, p) |
1900 | 1 if s is the signature of d signed by p (PK), else 0 |
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 SHA512-256 hash function for creating contract account addresses from TEAL bytecode.
Control Flow¶
PyTeal provides several control flow expressions to chain together multiple expressions and to conditionally evaluate expressions.
Exiting the Program: Return
¶
The Return
expression causes the program to exit immediately. It takes a single argument,
which is the success value that the program should have. For example, Return(Int(0))
causes
the program to immediately fail, and Return(Int(1))
causes the program to immediately
succeed. Since the presence of a Return
statement causes the program to exit, no operations
after it will be executed.
Chaining Expressions: Seq
¶
The Seq
expression can be used to create a sequence of multiple expressions. It takes a
single argument, which is a list of expressions to include in the sequence. 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:
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 evaludated 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
.
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 chians 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.
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 an integer that corresponds to the index of the account in
the Txn.accounts
array.
In order to read or manipulate an account’s local state, that account must be present in the
application call transaction’s 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 for more details.
Writing Local State¶
To write to the local state of an account, use the App.localPut
function. The first argument
is an integers corresponding to 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(Int(0), Bytes("role"), Bytes("admin")) # write a byte slice to Txn.accounts[0], the sender's account
App.localPut(Int(0), Bytes("balance"), Int(10)) # write a uint64 to Txn.accounts[0], the sender's account
App.localPut(Int(1), Bytes("balance"), Int(10)) # write a uint64 to Txn.accounts[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 an integer corresponding to the account to read from and the second argument is the key to read.
For example:
App.localGet(Int(0), Bytes("role")) # read from Txn.accounts[0], the sender's account
App.localGet(Int(0), Bytes("balance")) # read from Txn.accounts[0], the the sender's account
App.localGet(Int(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 an integer corresponding to the account and the second argument is the key to delete.
For example:
App.localDel(Int(0), Bytes("role")) # delete "role" from Txn.accounts[0], the sender's account
App.localDel(Int(0), Bytes("balance")) # delete "balance" from Txn.accounts[0], the the sender's account
App.localDel(Int(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 which application to
read from. The integer 0
is a special case that refers to the current application. The
integer 1
refers to the first element in Txn.ForeignApps,
2
refers to the second element, and so on. Note that the transaction field ForeignApps
is not accessible from TEAL at this time.
Note: In order to read from the global state of another application, that application’s ID must
be included in the transaction’s ForeignApps
array.
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 current global context
# if "status" has not been set, returns "none"
myStatus = App.globalGetEx(Int(0), Bytes("status"))
Seq([
myStatus,
If(myStatus.hasValue(), myStatus.value(), Bytes("none"))
])
# get "status" from the global context of the first app in Txn.ForeignApps
# if "status" has not been set, returns "none"
otherStatus = App.globalGetEx(Int(1), Bytes("status"))
Seq([
otherStatus,
If(otherStatus.hasValue(), otherStatus.value(), Bytes("none"))
])
# get "total supply" from the global context of the first app in Txn.ForeignApps
# if "total supply" has not been set, returns the default value of 0
otherSupply = App.globalGetEx(Int(1), Bytes("total supply"))
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 an integer corresponding to 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
ForeignApps
. This means that you can read from any application that the account has opted
into, not just applications included in ForeignApps
. 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(Int(0), Int(0), Bytes("role"))
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(Int(1), Int(0), Bytes("role"))
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(Int(0), Int(31), Bytes("role"))
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(Int(1), Int(31), Bytes("role"))
Seq([
otherAppOtherAccountRole,
If(otherAppOtherAccountRole.hasValue(), otherAppOtherAccountRole.value(), Bytes("none"))
])
PyTeal Package¶
-
pyteal.
Txn
= <pyteal.TxnObject object>¶ The current transaction being evaluated.
-
pyteal.
Gtxn
= <pyteal.TxnGroup object>¶ The current group of transactions being evaluated.
-
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.
-
type_of
() → pyteal.TealType¶ Get the return type of this expression.
-
-
class
pyteal.
LeafExpr
¶ Bases:
pyteal.Expr
Leaf expression base class.
-
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
(*args)¶ Bases:
pyteal.LeafExpr
An expression that represents a byte string.
-
__init__
(*args) → 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 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.
Err
¶ Bases:
pyteal.LeafExpr
Expression that causes the program to immediately fail when executed.
-
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.
Arg
(index: int)¶ Bases:
pyteal.LeafExpr
An expression to get an argument when running in signature verification mode.
-
__init__
(index: int) → 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 integer index of the argument to get. Must be between 0 and 255 inclusive.
-
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)¶ Bases:
enum.Enum
An enumeration.
-
accounts
= (28, 'Accounts', <TealType.bytes: 1>)¶
-
amount
= (8, 'Amount', <TealType.uint64: 0>)¶
-
application_args
= (26, 'ApplicationArgs', <TealType.bytes: 1>)¶
-
application_id
= (24, 'ApplicationID', <TealType.uint64: 0>)¶
-
approval_program
= (30, 'ApprovalProgram', <TealType.bytes: 1>)¶
-
asset_amount
= (18, 'AssetAmount', <TealType.uint64: 0>)¶
-
asset_close_to
= (21, 'AssetCloseTo', <TealType.bytes: 1>)¶
-
asset_receiver
= (20, 'AssetReceiver', <TealType.bytes: 1>)¶
-
asset_sender
= (19, 'AssetSender', <TealType.bytes: 1>)¶
-
clear_state_program
= (31, 'ClearStateProgram', <TealType.bytes: 1>)¶
-
close_remainder_to
= (9, 'CloseRemainderTo', <TealType.bytes: 1>)¶
-
config_asset
= (33, 'ConfigAsset', <TealType.uint64: 0>)¶
-
config_asset_clawback
= (44, 'ConfigAssetClawback', <TealType.bytes: 1>)¶
-
config_asset_decimals
= (35, 'ConfigAssetDecimals', <TealType.uint64: 0>)¶
-
config_asset_default_frozen
= (36, 'ConfigAssetDefaultFrozen', <TealType.uint64: 0>)¶
-
config_asset_freeze
= (43, 'ConfigAssetFreeze', <TealType.bytes: 1>)¶
-
config_asset_manager
= (41, 'ConfigAssetManager', <TealType.bytes: 1>)¶
-
config_asset_metadata_hash
= (40, 'ConfigAssetMetadataHash', <TealType.bytes: 1>)¶
-
config_asset_name
= (38, 'ConfigAssetName', <TealType.bytes: 1>)¶
-
config_asset_reserve
= (42, 'ConfigAssetReserve', <TealType.bytes: 1>)¶
-
config_asset_total
= (34, 'ConfigAssetTotal', <TealType.uint64: 0>)¶
-
config_asset_unit_name
= (37, 'ConfigAssetUnitName', <TealType.bytes: 1>)¶
-
config_asset_url
= (39, 'ConfigAssetURL', <TealType.bytes: 1>)¶
-
fee
= (1, 'Fee', <TealType.uint64: 0>)¶
-
first_valid
= (2, 'FirstValid', <TealType.uint64: 0>)¶
-
first_valid_time
= (3, 'FirstValidTime', <TealType.uint64: 0>)¶
-
freeze_asset
= (45, 'FreezeAsset', <TealType.uint64: 0>)¶
-
freeze_asset_account
= (46, 'FreezeAssetAccount', <TealType.bytes: 1>)¶
-
freeze_asset_frozen
= (47, 'FreezeAssetFrozen', <TealType.uint64: 0>)¶
-
group_index
= (22, 'GroupIndex', <TealType.uint64: 0>)¶
-
last_valid
= (4, 'LastValid', <TealType.uint64: 0>)¶
-
lease
= (6, 'Lease', <TealType.bytes: 1>)¶
-
note
= (5, 'Note', <TealType.bytes: 1>)¶
-
num_accounts
= (2, 'NumAccounts', <TealType.uint64: 0>)¶
-
num_app_args
= (27, 'NumAppArgs', <TealType.uint64: 0>)¶
-
on_completion
= (25, 'OnCompletion', <TealType.uint64: 0>)¶
-
receiver
= (7, 'Receiver', <TealType.bytes: 1>)¶
-
rekey_to
= (32, 'RekeyTo', <TealType.bytes: 1>)¶
-
selection_pk
= (11, 'SelectionPK', <TealType.bytes: 1>)¶
-
sender
= (0, 'Sender', <TealType.bytes: 1>)¶
-
tx_id
= (23, 'TxID', <TealType.bytes: 1>)¶
-
type
= (15, 'Type', <TealType.bytes: 1>)¶
-
type_enum
= (16, 'TypeEnum', <TealType.uint64: 0>)¶
-
type_of
() → pyteal.TealType¶
-
vote_first
= (12, 'VoteFirst', <TealType.uint64: 0>)¶
-
vote_key_dilution
= (14, 'VoteKeyDilution', <TealType.uint64: 0>)¶
-
vote_last
= (13, 'VoteLast', <TealType.uint64: 0>)¶
-
vote_pk
= (10, 'VotePK', <TealType.bytes: 1>)¶
-
xfer_asset
= (17, 'XferAsset', <TealType.uint64: 0>)¶
-
-
class
pyteal.
TxnExpr
(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
(field: pyteal.TxnField, index: int)¶ 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: int) → pyteal.TxnaExpr¶ Get the value at a given index in this array.
-
length
() → pyteal.TxnExpr¶ Get the length of the array.
-
-
class
pyteal.
TxnObject
(txnType: Callable[[pyteal.TxnField], pyteal.TxnExpr], txnaType: Callable[[pyteal.TxnField, int], pyteal.TxnaExpr])¶ Bases:
object
Represents a transaction and its fields.
-
amount
() → pyteal.TxnExpr¶ Get the amount of the transaction in micro Algos.
Only set when
type_enum()
isTxnType.Payment
.For more information, see https://developer.algorand.org/docs/reference/transactions/#amount
-
application_id
() → pyteal.TxnExpr¶ Get the application ID from the ApplicationCall portion of the current transaction.
Only set when
type_enum()
isTxnType.ApplicationCall
.
-
approval_program
() → pyteal.TxnExpr¶ Get the approval program.
Only set when
type_enum()
isTxnType.ApplicationCall
.
-
asset_amount
() → pyteal.TxnExpr¶ Get the amount of the asset being transferred, measured in the asset’s units.
Only set when
type_enum()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.AssetTransfer
.For more information, see https://developer.algorand.org/docs/reference/transactions/#assetsender
-
clear_state_program
() → pyteal.TxnExpr¶ Get the clear state program.
Only set when
type_enum()
isTxnType.ApplicationCall
.
-
close_remainder_to
() → pyteal.TxnExpr¶ Get the 32 byte address of the CloseRemainderTo field.
Only set when
type_enum()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.AssetConfig
.For more information, see https://developer.algorand.org/docs/reference/transactions/#url
-
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()
isTxnType.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()
isTxnType.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()
isTxnType.AssetFreeze
.For more information, see https://developer.algorand.org/docs/reference/transactions/#assetfrozen
-
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_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
-
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()
isTxnType.ApplicationCall
.
-
receiver
() → pyteal.TxnExpr¶ Get the 32 byte address of the receiver.
Only set when
type_enum()
isTxnType.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()
isTxnType.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
-
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
-
vote_first
() → pyteal.TxnExpr¶ Get the first round that the participation key is valid.
Only set when
type_enum()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.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()
isTxnType.AssetTransfer
.For more information, see https://developer.algorand.org/docs/reference/transactions/#xferasset
-
-
class
pyteal.
GtxnExpr
(txnIndex: int, field: pyteal.TxnField)¶ Bases:
pyteal.TxnExpr
An expression that accesses a transaction field from a transaction in the current group.
-
class
pyteal.
GtxnaExpr
(txnIndex: int, field: pyteal.TxnField, index: int)¶ 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: int) → pyteal.TxnObject¶
-
-
class
pyteal.
Global
(field: pyteal.GlobalField)¶ Bases:
pyteal.LeafExpr
An expression that accesses a global property.
-
classmethod
current_application_id
() → pyteal.Global¶ Get the ID of the current application executing.
Fails if no application is executing.
-
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
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.
-
classmethod
-
class
pyteal.
GlobalField
(id: int, name: str, type: pyteal.TealType)¶ Bases:
enum.Enum
An enumeration.
-
current_app_id
= (8, 'CurrentApplicationID', <TealType.uint64: 0>)¶
-
group_size
= (4, 'GroupSize', <TealType.uint64: 0>)¶
-
latest_timestamp
= (7, 'LatestTimestamp', <TealType.uint64: 0>)¶
-
logic_sig_version
= (5, 'LogicSigVersion', <TealType.uint64: 0>)¶
-
max_txn_life
= (2, 'MaxTxnLife', <TealType.uint64: 0>)¶
-
min_balance
= (1, 'MinBalance', <TealType.uint64: 0>)¶
-
min_txn_fee
= (0, 'MinTxnFee', <TealType.uint64: 0>)¶
-
round
= (6, 'Round', <TealType.uint64: 0>)¶
-
type_of
() → pyteal.TealType¶
-
zero_address
= (3, 'ZeroAddress', <TealType.bytes: 1>)¶
-
-
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 evaluate 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 from which the key should be deleted. Must evaluate to uint64.
- 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 read from. Must evaluate to uint64.
- 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 read from. Must evaluate to uint64.
- app – The ID of the application being checked. Must evaluate to uint64.
- 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 write to. Must evaluate to uint64.
- 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 evaluate to uint64.
- app – The ID of the application being checked. Must evaluate to uint64.
-
type_of
()¶ Get the return type of this expression.
-
classmethod
-
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: 'app_global_del'>, <TealType.none: 3>)¶
-
globalGet
= (<Op.app_global_get: 'app_global_get'>, <TealType.anytype: 2>)¶
-
globalGetEx
= (<Op.app_global_get_ex: 'app_global_get_ex'>, <TealType.none: 3>)¶
-
globalPut
= (<Op.app_global_put: 'app_global_put'>, <TealType.none: 3>)¶
-
localDel
= (<Op.app_local_del: 'app_local_del'>, <TealType.none: 3>)¶
-
localGet
= (<Op.app_local_get: 'app_local_get'>, <TealType.anytype: 2>)¶
-
localGetEx
= (<Op.app_local_get_ex: 'app_local_get_ex'>, <TealType.none: 3>)¶
-
localPut
= (<Op.app_local_put: 'app_local_put'>, <TealType.none: 3>)¶
-
optedIn
= (<Op.app_opted_in: 'app_opted_in'>, <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.
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 evaluate to uint64.
- asset – The ID of the asset to get. Must evaluate to uint64.
-
classmethod
frozen
(account: pyteal.Expr, asset: pyteal.Expr) → pyteal.MaybeValue¶ Check if an asset is frozen for an account.
Parameters: - account – An index into Txn.Accounts that corresponds to the account to check. Must evaluate to uint64.
- asset – The ID of the asset to check. Must evaluate to uint64.
-
classmethod
-
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 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 evaluate to uint64.
-
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 evaluate to uint64.
-
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 evaluate to uint64.
-
classmethod
manager
(asset: pyteal.Expr) → pyteal.MaybeValue¶ Get the manager commitment for an asset.
Parameters: asset – An index into Txn.ForeignAssets that corresponds to the asset to check. Must evaluate to uint64.
-
classmethod
metadataHash
(asset: pyteal.Expr) → pyteal.MaybeValue¶ Get the arbitrary commitment for an asset.
Parameters: asset – An index into Txn.ForeignAssets that corresponds to the asset to check. Must evaluate to uint64.
-
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 evaluate to uint64.
-
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 evaluate to uint64.
-
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 evaluate to uint64.
-
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 evaluate to uint64.
-
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 evaluate to uint64.
-
classmethod
-
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.
-
classmethod
-
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.
-
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.
-
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.
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.
Pop
(arg: pyteal.Expr) → pyteal.UnaryExpr¶ Pop a value from the stack.
-
pyteal.
Return
(arg: pyteal.Expr) → pyteal.UnaryExpr¶ Immediately exit the program with the given success value.
-
pyteal.
Balance
(arg: pyteal.Expr) → pyteal.UnaryExpr¶ Get the balance of a user in micro Algos.
Argument must be an index into Txn.Accounts that corresponds to the account to read from. It must evaluate to uint64.
This operation is only permitted in application mode.
-
class
pyteal.
BinaryExpr
(op: pyteal.Op, inputType: pyteal.TealType, outputType: pyteal.TealType, argLeft: pyteal.Expr, argRight: pyteal.Expr)¶ Bases:
pyteal.Expr
An expression with two arguments.
-
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.
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.
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.
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.
-
class
pyteal.
Ed25519Verify
(data: pyteal.Expr, sig: pyteal.Expr, key: pyteal.Expr)¶ Bases:
pyteal.Expr
An expression to verify ed25519 signatures.
-
__init__
(data: pyteal.Expr, sig: pyteal.Expr, key: pyteal.Expr) → None¶ Verify the ed25519 signature of (“ProgData” || program_hash || data).
Parameters: - data – The data signed by the public. Must evalutes to bytes.
- sig – The proposed 64 byte signature of (“ProgData” || program_hash || data). Must evalute to bytes.
- key – The 32 byte public key that produced the signature. Must evaluate to bytes.
-
type_of
()¶ Get the return type of this expression.
-
-
class
pyteal.
Substring
(string: pyteal.Expr, start: pyteal.Expr, end: pyteal.Expr)¶ Bases:
pyteal.Expr
Take a substring of a byte string.
-
__init__
(string: pyteal.Expr, start: pyteal.Expr, end: pyteal.Expr) → None¶ Create a new Substring expression.
Produces a new byte string consisting of the bytes starting at start up to but not including end.
Parameters: - string – The byte string.
- start – The starting index for the substring.
- end – The ending index for the substring.
-
type_of
()¶ Get the return type of this expression.
-
-
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.
-
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 two arguments.
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 two arguments.
-
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 two arguments.
Example
Concat(Bytes("hello"), Bytes(" "), Bytes("world"))
-
class
pyteal.
If
(cond: pyteal.Expr, thenBranch: pyteal.Expr, elseBranch: pyteal.Expr = None)¶ Bases:
pyteal.Expr
Simple two-way conditional expression.
-
__init__
(cond: pyteal.Expr, thenBranch: pyteal.Expr, 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.
-
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])
-
type_of
()¶ Get the return type of this expression.
-
-
class
pyteal.
Seq
(exprs: List[pyteal.Expr])¶ Bases:
pyteal.Expr
A control flow expression to represent a sequence of expressions.
-
__init__
(exprs: List[pyteal.Expr])¶ 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) ])
-
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.
-
type_of
()¶ Get the return type of this expression.
-
-
class
pyteal.
ScratchSlot
¶ Bases:
object
Represents the allocation of a scratch space slot.
-
load
(type: pyteal.TealType = <TealType.anytype: 2>)¶ 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.
-
slotId
= 0¶
-
store
()¶ Get an expression to store a value in this slot.
-
-
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.
-
type_of
()¶ Get the return type of this expression.
-
-
class
pyteal.
ScratchStore
(slot: pyteal.ScratchSlot)¶ Bases:
pyteal.Expr
Expression to store a value in scratch space.
-
__init__
(slot: pyteal.ScratchSlot)¶ Create a new ScratchStore expression.
Parameters: slot – The slot to store the value in.
-
type_of
()¶ Get the return type of this expression.
-
-
class
pyteal.
MaybeValue
(op: pyteal.Op, type: pyteal.TealType, *, immediate_args: List[Union[int, str]] = None, args: List[pyteal.Expr] = None)¶ Bases:
pyteal.LeafExpr
Represents a get operation returning a value that may not exist.
-
__init__
(op: pyteal.Op, type: pyteal.TealType, *, immediate_args: List[Union[int, str]] = 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.
-
type_of
()¶ Get the return type of this expression.
-
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.
Op
(value: str, mode: pyteal.Mode)¶ Bases:
enum.Enum
Enum of program opcodes.
-
add
= '+'¶
-
addr
= 'addr'¶
-
addw
= 'addw'¶
-
app_global_del
= 'app_global_del'¶
-
app_global_get
= 'app_global_get'¶
-
app_global_get_ex
= 'app_global_get_ex'¶
-
app_global_put
= 'app_global_put'¶
-
app_local_del
= 'app_local_del'¶
-
app_local_get
= 'app_local_get'¶
-
app_local_get_ex
= 'app_local_get_ex'¶
-
app_local_put
= 'app_local_put'¶
-
app_opted_in
= 'app_opted_in'¶
-
arg
= 'arg'¶
-
asset_holding_get
= 'asset_holding_get'¶
-
asset_params_get
= 'asset_params_get'¶
-
b
= 'b'¶
-
balance
= 'balance'¶
-
bitwise_and
= '&'¶
-
bitwise_not
= '~'¶
-
bitwise_or
= '|'¶
-
bitwise_xor
= '^'¶
-
bnz
= 'bnz'¶
-
btoi
= 'btoi'¶
-
byte
= 'byte'¶
-
bz
= 'bz'¶
-
concat
= 'concat'¶
-
div
= '/'¶
-
dup
= 'dup'¶
-
dup2
= 'dup2'¶
-
ed25519verify
= 'ed25519verify'¶
-
eq
= '=='¶
-
err
= 'err'¶
-
ge
= '>='¶
-
global_
= 'global'¶
-
gt
= '>'¶
-
gtxn
= 'gtxn'¶
-
gtxna
= 'gtxna'¶
-
int
= 'int'¶
-
itob
= 'itob'¶
-
keccak256
= 'keccak256'¶
-
le
= '<='¶
-
len
= 'len'¶
-
load
= 'load'¶
-
logic_and
= '&&'¶
-
logic_not
= '!'¶
-
logic_or
= '||'¶
-
lt
= '<'¶
-
minus
= '-'¶
-
mod
= '%'¶
-
mul
= '*'¶
-
mulw
= 'mulw'¶
-
neq
= '!='¶
-
pop
= 'pop'¶
-
return_
= 'return'¶
-
sha256
= 'sha256'¶
-
sha512_256
= 'sha512_256'¶
-
store
= 'store'¶
-
substring
= 'substring'¶
-
substring3
= 'substring3'¶
-
txn
= 'txn'¶
-
txna
= 'txna'¶
-
-
class
pyteal.
TealComponent
¶ Bases:
abc.ABC
-
assemble
() → str¶
-
assignSlot
(slot: ScratchSlot, location: int)¶
-
getSlots
() → List[ScratchSlot]¶
-
-
class
pyteal.
TealOp
(op: pyteal.Op, *args)¶ Bases:
pyteal.TealComponent
-
assemble
() → str¶
-
assignSlot
(slot: ScratchSlot, location: int)¶
-
getOp
() → pyteal.Op¶
-
getSlots
() → List[ScratchSlot]¶
-
-
class
pyteal.
TealLabel
(label: str)¶ Bases:
pyteal.TealComponent
-
assemble
() → str¶
-
-
pyteal.
compileTeal
(ast: pyteal.Expr, mode: pyteal.Mode) → str¶ Compile a PyTeal expression into TEAL assembly.
Parameters: ast – The PyTeal expression to assemble. Returns: A TEAL assembly program compiled from the input expression. Return type: str
-
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)¶ Bases:
Exception
-
pyteal.
execute
(args)¶ Execute in bash, return stdout and stderr in string
Arguments: args: command and arguments to run, e.g. [‘ls’, ‘-l’]