Examples¶
The examples directory in the repository includes several applications written in Tealish.
A Tealish port of the auction contract from the Algorand docs is reproduced below.
See also Usage for links to public code of projects using Tealish.
Auction Demo¶
#pragma version 6
# This code is Tealish port of acution demo.
# It contains minimal code changes. Variable names, and order of assignments are preserved.
# Original Code Reference: https://github.com/algorand/auction-demo
# Algorand Developer Portal Auction Demo: https://developer.algorand.org/docs/get-started/dapps/pyteal/#the-smart-contract
const bytes SELLER_KEY = "seller"
const bytes NFT_ID_KEY = "nft_id"
const bytes START_TIME_KEY = "start"
const bytes END_TIME_KEY = "end"
const bytes RESERVE_AMOUNT_KEY = "reserve_amount"
const bytes MIN_BID_INCREMENT_KEY = "min_bid_inc"
const bytes NUM_BIDS_KEY = "num_bids"
const bytes LEAD_BID_AMOUNT_KEY = "bid_amount"
const bytes LEAD_BID_ACCOUNT_KEY = "bid_account"
if Txn.ApplicationID == 0:
jump on_create
end
switch Txn.OnCompletion:
NoOp: on_call
DeleteApplication: on_delete
OptIn: fail
CloseOut: fail
UpdateApplication: fail
end
block fail:
# Reject
exit(0)
end
block on_create:
int start_time = btoi(Txn.ApplicationArgs[2])
int end_time = btoi(Txn.ApplicationArgs[3])
# Fix: Accounts should be passed with Accounts instead of Application Args.
# app_global_put(SELLER_KEY, Txn.ApplicationArgs[0])
app_global_put(SELLER_KEY, Txn.Accounts[1])
app_global_put(NFT_ID_KEY, btoi(Txn.ApplicationArgs[1]))
app_global_put(START_TIME_KEY, start_time)
app_global_put(END_TIME_KEY, end_time)
app_global_put(RESERVE_AMOUNT_KEY, btoi(Txn.ApplicationArgs[4]))
app_global_put(MIN_BID_INCREMENT_KEY, btoi(Txn.ApplicationArgs[5]))
app_global_put(LEAD_BID_ACCOUNT_KEY, Global.ZeroAddress)
assert((Global.LatestTimestamp < start_time) && (start_time < end_time))
# Approve
exit(1)
end
block on_call:
switch Txn.ApplicationArgs[0]:
"setup": on_setup
"bid": on_bid
end
end
block on_setup:
assert(Global.LatestTimestamp < app_global_get(START_TIME_KEY))
# opt into NFT asset -- because you can't opt in if you're already opted in, this is what
# we'll use to make sure the contract has been set up
inner_txn:
TypeEnum: Axfer
XferAsset: app_global_get(NFT_ID_KEY)
AssetReceiver: Global.CurrentApplicationAddress
end
# Note: The default fee amount of the inner transaction is the minimum transaction fee.
# It is possible to set it to 0 thanks to fee pooling.
exit(1)
end
block on_bid:
int txn_index = Txn.GroupIndex - 1
int is_opted_in
int ntf_balance
is_opted_in, ntf_balance = asset_holding_get(AssetBalance, Global.CurrentApplicationAddress, app_global_get(NFT_ID_KEY))
# the auction has been set up
assert(is_opted_in)
assert(ntf_balance > 0)
# the auction has started
assert(app_global_get(START_TIME_KEY) <= Global.LatestTimestamp)
# the auction has not ended
assert(Global.LatestTimestamp < app_global_get(END_TIME_KEY))
# the actual bid payment is before the app call
assert(Gtxn[txn_index].TypeEnum == Pay)
assert(Gtxn[txn_index].Sender == Txn.Sender)
assert(Gtxn[txn_index].Receiver == Global.CurrentApplicationAddress)
assert(Gtxn[txn_index].Amount >= Global.MinTxnFee)
if Gtxn[txn_index].Amount >= (app_global_get(LEAD_BID_AMOUNT_KEY) + app_global_get(MIN_BID_INCREMENT_KEY)):
if app_global_get(LEAD_BID_ACCOUNT_KEY) != Global.ZeroAddress:
repay_previous_lead_bidder(app_global_get(LEAD_BID_ACCOUNT_KEY), app_global_get(LEAD_BID_AMOUNT_KEY))
end
app_global_put(LEAD_BID_AMOUNT_KEY, Gtxn[txn_index].Amount)
app_global_put(LEAD_BID_ACCOUNT_KEY, Gtxn[txn_index].Sender)
app_global_put(NUM_BIDS_KEY, (app_global_get(NUM_BIDS_KEY) + 1))
# Approve
exit(1)
end
# Reject
exit(0)
end
block on_delete:
if Global.LatestTimestamp < app_global_get(START_TIME_KEY):
# the auction has not yet started, it's ok to delete
# sender must either be the seller or the auction creator
assert((Txn.Sender == app_global_get(SELLER_KEY)) || (Txn.Sender == Global.CreatorAddress))
# if the auction contract account has opted into the nft, close it out
close_nft_to(app_global_get(NFT_ID_KEY), app_global_get(SELLER_KEY))
# if the auction contract still has funds, send them all to the seller
close_account_to(app_global_get(SELLER_KEY))
exit(1)
end
if app_global_get(END_TIME_KEY) <= Global.LatestTimestamp:
# the auction has ended, pay out assets
if app_global_get(LEAD_BID_ACCOUNT_KEY) != Global.ZeroAddress:
if app_global_get(LEAD_BID_AMOUNT_KEY) >= app_global_get(RESERVE_AMOUNT_KEY):
# the auction was successful: send lead bid account the nft
close_nft_to(app_global_get(NFT_ID_KEY), app_global_get(LEAD_BID_ACCOUNT_KEY))
else:
# the auction was not successful because the reserve was not met: return
# the nft to the seller and repay the lead bidder
close_nft_to(app_global_get(NFT_ID_KEY), app_global_get(SELLER_KEY))
repay_previous_lead_bidder(app_global_get(LEAD_BID_ACCOUNT_KEY), app_global_get(LEAD_BID_AMOUNT_KEY))
end
else:
# the auction was not successful because no bids were placed: return the nft to the seller
close_nft_to(app_global_get(NFT_ID_KEY), app_global_get(SELLER_KEY))
end
# send remaining funds to the seller
close_account_to(app_global_get(SELLER_KEY))
exit(1)
end
exit(0)
end
func close_nft_to(asset_id: int, account: bytes):
int is_opted_in
is_opted_in, _ = asset_holding_get(AssetBalance, Global.CurrentApplicationAddress, asset_id)
if is_opted_in:
inner_txn:
TypeEnum: Axfer
XferAsset: asset_id
AssetCloseTo: account
end
end
return
end
func repay_previous_lead_bidder(prev_lead_bidder: bytes, prev_lead_bid_amount: int):
inner_txn:
TypeEnum: Pay
Amount: prev_lead_bid_amount - Global.MinTxnFee
Receiver: prev_lead_bidder
end
return
end
func close_account_to(account: bytes):
if balance(Global.CurrentApplicationAddress) != 0:
inner_txn:
TypeEnum: Pay
CloseRemainderTo: account
end
end
return
end