Skip to content

Commit

Permalink
Add ABI support (#264)
Browse files Browse the repository at this point in the history
* ABI Types (#154)

* initial commit to be used for reference and comparison

* Fmt

* move abi to ast

* make tuple return the deocded Tuple

* rename collections, fixed some of the mypy issues

* Fix mypy issues

* remove Literal

* add str method for abi type names

* fix names

* make imports nice

* make imports nice

* make collections generic

* rm param spec

* lie to mypy

* make dynamic array work

* [WIP] Make Add and Mul NaryExprs

* ABI refactor

* Implement decoding

* Make arrays encode to a single value

* Make types mutable

* Proof of concept map implementation

* Remove old comment

* Update Uint16 limit check

Co-authored-by: Giorgio Ciotti <gciotti.dev@gmail.com>

* provide a method to know the type name (#176)

* Refactor array implementation

* Add ComputedType and fix bug in map

* Add more int types and bool support

* Add string method

* Remove files for features that won't make it into this PR

* Remove Array.map 😢

* Make decode more powerful

* Uint bounds checking and tests

* Remove random line

* Bool tests and bugfixes

* Allow uint and bool set to copy another type

* Begin tuple and array tests, improve dynamic tuple encoding, and remove Array.forEach

* Test indexTuple and fix bugs

* Fix field shadowing

* Finish tuple tests and type tests

* Implement static and dynamic array tests

* Finish testing abi types and fix tuple encoding bug

* Add generic param to new instances of arrays

* Address feedback

* Fix tuple decoding issue

* Fix uint64 decoding test

* minor improvement to distinguish abi.Byte and abi.Uint8 (#194)

* Add docstrings to abi.Type

* Respond to feedback

* Respond to feedback & fix bug

* Fix indexTuple bug

* Add docs for TealBlock methods

* ABI Array docstrings and comments (#216)

Co-authored-by: Jason Paulos <jasonpaulos@users.noreply.github.com>
Co-authored-by: Giorgio Ciotti <gciotti.dev@gmail.com>
Co-authored-by: Hang Su <87964331+ahangsu@users.noreply.github.com>

* Merge with master and regenerate `__index__.pyi` (#224)

* Fix build script invocation (#223)

* Regen __init__.pyi

* Reorder CI build steps to change source files before running tests (#225)

Co-authored-by: Michael Diamant <michaeldiamant@users.noreply.github.com>

* Merge #227 into feature/abi (#231)

* Fix build script invocation (#223)

* Bring #225 to master (#227)

* Ignore tests generating TEAL file outputs used for expected comparisons (#228)

* Fix typo in CONTRIBUTING.md (#229)

Co-authored-by: Jason Paulos <jasonpaulos@users.noreply.github.com>

* Make ABI types fully specified (#222)

* Convert Type and Tuple to indexable types

* Convert and combine uint types

* Fix type and unit tests

* Convert Bool

* Fix Tuple getitem

* Convert arrays and array tests

* Fix tuple tests

* [WIP] satisfy mypy

* Refactor ABI types

* Update docs, add Tuple4 and Tuple5, and change type_spec method name

* No longer test on Python 3.6 and 3.7

* No longer test on Python 3.6 and 3.7

* Remove accidentally included file

* Add another literal test case

* Debugging through CI

* blacken

* Remove problematic test case

* Minor test coverage improvements

* Unit test to make sure type_spec_from_annotation always works on all types

* Partially address feedback

* Make uint8 != byte and use typing.Final in a few constructors

* Undo custom set methods

* Fix typo

Co-authored-by: Michael Diamant <michaeldiamant@users.noreply.github.com>

Co-authored-by: Michael Diamant <michaeldiamant@users.noreply.github.com>

* Passing ABI type arguments to Subroutine (#263)

- passing ABI variables into subroutine
- subroutine type annotations with ABI types

* ABI Method Return (#175)

Encode ABI variable and concat with `RETURN_METHOD_SELECTOR` and log it.

* Allow `ComputedType` to be passed to the `set` method on ABI types (#267)

* update minor support for setting ComputedType

* minor tweak

* backwards for 3.8 on subscriptable type

* attempt to test uint set

* minor

* cleanup

* update arrays, tuple to test

* tuple testing

* update documents

* resolving comments

* py3.10 less go

* python typing annotations

* Merge branch 'master' into feature/abi (#284)

* Move to pyteal as pt in ABI tests with concise  prefix (#286)

* ABI Strings (#278)

* Move to pyteal as pt in #278 (#287)

* Merge absolute imports into feature/abi (#288)

* Remove temporary I252 ignore on pyteal.ast.abi (#290)

* Fix abi import (#303)

* Fix abi import

* ignore flake8

* Feature/abi merge master again (#310)

Following major changes:
* Merge in Blackbox testing
* replace `SubroutineDefinition. _arg_types_and_by_refs()` by `SubroutineDefinition._validate()`
* add abi cases to `subroutine_test.py::test_validate()`

* merge conflicts

* merge again

* wip

* pass all tests after resolving conflicts

* Add `set` on address and string, change array init to accept typespec (#289)

* adding set on String and Address types

* Add convenience `make` method for ABI types (#326)

* Add make method for abi types

* Respondn to feedback

* ABI Type subroutine return (#256)

* wtf

* update

* update to f-str

* define void type

* update instantiated computed type returnedType for ABI return in subroutine

* minor

* update stuffs to help infer type annotation of return ABI

* minor

* minor

* minor

* minor

* minor

* try my best to save stuffs

* simplify decorator to single function

* tear it down

* minor

* sheeeesh emacs

* updates

* minor, renaming something

* new design, start over

* updates

* abi fn wrapper for now

* minor

* minor update on subroutine def

* minor fixes

* minor fixes

* changes

* more constraint on void ret

* update comment examples

* import from abi

* update some error msg and comments

* testcases partial

* upgrade testscripts

* Bundle optional refactorings to subroutine.py (#308)

* Bundle optional refactorings to subroutine.py

* Refactor to remove branching

* storing local changes

* pr review partly

* pr review partly

* update test script

* Abi subroutine feature merge (#315)

* resolve conflicts

* lint

* minor reconstruct

* missing imports

* missing requirements from bad merge

* cooperate with typespec n var def change

* update comments

* some comments resolving?

* trim

* update some comments

* bring testcase back

* restriction on output kwarg name

* stop ci! i am reformatting

* simplify name constrain

* resolving comments

* Use deferred subroutine expression for ABI returns (#328)

* Add subroutine deferred expr

* Allow multiple deferred blocks

* Remove error

* flake8

* Make test more realistic

* Add second test

* clean up code and comments

* remove deferred blocks function

* Add coverage for multiple ops in block error

* hack return from abi var

* a hack

* better returned type

* simplify

* add some compiler test

* flake break no way

* PR comment resolve partial

* polishing

Co-authored-by: Michael Diamant <michaeldiamant@users.noreply.github.com>
Co-authored-by: Zeph Grunschlag <tzaffi@users.noreply.github.com>
Co-authored-by: Zeph Grunschlag <zeph@algorand.com>
Co-authored-by: Jason Paulos <jasonpaulos@users.noreply.github.com>

* adding byte type hint to DyanamicArray parent class (#339)

* adding byte type hint to DyanamicArray parent class

* appease mypy

* specify Byte in set method instead of T

* Define level of support provided for ABIReturnSubroutine (#341)

* Testing ABI Functionality via Graviton / Dry-runs + Txn Friendly Graviton Logic Sig Example (#322)

# Blackbox Testing ABI Functionality
This PR brings in dry-run testing of ABI types and subroutines. The space of ABI-Functionality that needs testing is large, and this PR doesn't purport to provide full coverage. However, the basic tools are provided to obtain greater coverage in the future. The following specific ABI use cases are tested:

* abi_sum() which computes the sume of a DynamicArray
* integers and complex integer number (Gassian integers) are built up from basic types and basic operations are validated
* round-trip encoding and decoding of a number of ABI types

# Testing Logic Sigs which interact with their Payment Transaction
#249 introduced examples/signature/factorizer_game.py which includes a family of logic sigs that provide a payout that depends on the solution to an algebra puzzle. With a recent improvement to graviton we can now run blackbox tests on this logic sig family, and gain confidence in its correctness. See tests/integration/pure_logicsig_test.py for how this is done.

* abi_roundtrip_test::test_abi_types_comprehensive() (#355)

* adding sizeof util (#358)

* adding size_of util

* Reference Types (#361)

* adding reference types to ABI types

* Clearer Comment (#364)

* Clearer Comment and link comment to issue #184

* Bug: Graviton's report no longer has last_rows (#365)

* adding deref type to get the underlying value of the reference type (#372)

* `ABI Router` implementation and test (#170)

* init commit

* minor

* minor

* rm decorator

* update ABI router design, seems we are still working on previous design

* minor

* update condition parser here

* skeleton for handler wrapping, need to tweak on subroutine to expose more message

* module

* use subroutine fn wrapper

* update dummy method return class

* unify ast construct way

* minor

* update notes for tasks and todos

* update handler wrapping for bare app call

* minor

* update redirecting args to method registered

* minor

* minor

* update router src

* update program node

* add questions in build prog

* update executing method branch

* minor

* minor

* minor

* hide other methods, set MethodAppArgNumLimit, keyword args on exposed register func, skeleton for arg de-tuple

* minor

* update notes

* update

* add a default for no registered ast gen

* update ast construction to conds

* need some documentations

* move abi-router in abi dir

* minor

* wtf

* update

* update to f-str

* define void type

* update instantiated computed type returnedType for ABI return in subroutine

* minor

* update stuffs to help infer type annotation of return ABI

* minor

* minor

* minor

* minor

* minor

* try my best to save stuffs

* simplify decorator to single function

* tear it down

* minor

* sheeeesh emacs

* update with latest abi impl

* minors

* minor

* updates

* minor, renaming something

* new design, start over

* updates

* abi fn wrapper for now

* minor

* minor update on subroutine def

* minor fixes

* minor fixes

* changes

* more constraint on void ret

* update comment examples

* import from abi

* update some error msg and comments

* testcases partial

* upgrade testscripts

* merging feature/abi to abi-router (#305)

* merging feature/abi

* missed one

* make router use absolute imports

* linter happy?

* Export Router (#306)

* Merge branch 'master' into feature/abi (#284)

* Move to pyteal as pt in ABI tests with concise  prefix (#286)

* ABI Strings (#278)

* Move to pyteal as pt in #278 (#287)

* Merge absolute imports into feature/abi (#288)

* Remove temporary I252 ignore on pyteal.ast.abi (#290)

* Fix abi import (#303)

* Fix abi import

* ignore flake8

* move router to ast

Co-authored-by: Michael Diamant <michaeldiamant@users.noreply.github.com>
Co-authored-by: Jason Paulos <jasonpaulos@users.noreply.github.com>

* fix spacing issue

* Bundle optional refactorings to subroutine.py (#308)

* Bundle optional refactorings to subroutine.py

* Refactor to remove branching

* storing local changes

* pr review partly

* pr review partly

* update test script

* Abi subroutine feature merge (#315)

* resolve conflicts

* lint

* minor reconstruct

* missing imports

* missing requirements from bad merge

* cooperate with typespec n var def change

* update comments

* some comments resolving?

* trim

* update some comments

* bring testcase back

* restriction on output kwarg name

* stop ci! i am reformatting

* squash merge abi subroutine atm, merge again after abi subroutine into feature/abi

* conform to pep8, reconstructing

* update json generator

* simplify name constrain

* resolving comments

* Use deferred subroutine expression for ABI returns (#328)

* Add subroutine deferred expr

* Allow multiple deferred blocks

* Remove error

* flake8

* Make test more realistic

* Add second test

* clean up code and comments

* remove deferred blocks function

* Add coverage for multiple ops in block error

* updating wrap handler

* change how to de-tuple args

* update checkbox

* minor

* bug fixes

* Method sig for router (#340)

* adding method_signature to ABIReturnSubroutine

* minor, renaming

* minor

* simplify

* compiler test adding...

* documentation

* start testcases

* update router testcase

* docstring tweak

* update testcases

* update testcases

* formatting

* branch cond testing

* router contract test

* subroutine branch wrapper bare call case tested

* more testcases to barecall

* minor, need to work on method call wrapper

* half done on method call wrapper

* update on abi method wrapper with return

* detuple testcase

* compiler test need to see csp

* rm redundant type annotation

* more error msg

* renaming

* renaming is_registrable -> is_abi_routable

* reording imports, eliminate anti patterns

* remove anti-pattern

* section it out

* non_empty_power_set -> power_set

* add conflict detection to protect AST from overshadowing

* error message

* shrinked commits on pr review

* add compile_program

* fixup subroutine testcase

* remove method signature specifying, directly infer from ABIReturnSubroutine

* remove method sign field, directly infer from ABIReturnSubroutine

* relaxation of bare app call arg num restriction

* add barecall class, api change following

* rename barecall to OnCompleteAction

* remove outdated comments

* start changing router api

* eliminate contradiction for oc and creation

* remove restriction on cond

* new interface: add bare-calls on init, register method-call more fine-grained

* documentation for new interface from last discussion

* Refactor #170 to reduce visibility and mutation (#362)

* Refactor to use partition

* Designate _oc_under_call_config as private

* hide wrap handler method

* adding comment changes

* pr review partly

* partition into two methods

* hide all these methods

* arc4 compliant CallConfigs classmethod

* arc4 compliant CallConfigs documentation

* disclaimer comments

* update new abi return hash prefix

* review comments partly

* OnCompleteActions -> BareCallActions

* disclaimer change, rename CallConfigs -> MethodConfig

* disclaimer move to docstring

* better naming for naming prefix

* new ast builder

* review comments

* An attempt to add decorator syntax to abi-router (#370)

* an attempt to use decorator

* no return, or we will have python-level issue?

* minor fix

* per pr comment on on-complete-action

* eliminate potential issue

* update call config testcase

* add testcase for on complete action

* per comments

* Add a check in `method_signature` to disallow reference return types (#368)

* new ast builder

* adding check in method_signature to raise error if its attempted to be called on method with reference type as return value

* use type spec instead of str

* adding recursive type checking method and using it in subroutine method signature

* Adding one more test case for extra nesting

* appease the linter

Co-authored-by: Hang Su <hang.su@algorand.com>

* add new compiler tests for router

* fix one test for wrapping bare calls

* comments fixing

* simplified oc-action post_init check

* naming variables

* comments

* comments

* testcase for method config update

* add router method only in clearstate prog

* closeout -> clearstate

* removing is_arc4_compliant

* update add method handler and method interface

* remove arc4_compliant

* Add manual test for 15+ args in abi router (#375)

Co-authored-by: Ben Guidarelli <ben.guidarelli@gmail.com>
Co-authored-by: Michael Diamant <michaeldiamant@users.noreply.github.com>
Co-authored-by: Jason Paulos <jasonpaulos@users.noreply.github.com>
Co-authored-by: Zeph Grunschlag <tzaffi@users.noreply.github.com>
Co-authored-by: Zeph Grunschlag <zeph@algorand.com>

* Adding method_spec to ABIReturnSubroutine (#380)

* adding method_spec to ABIReturnSubroutine

* Txn types (#376)

* Add transaction abi types

* Blackbox testing unifying abi-return-subroutine and subroutine input handling (#374)

* unify subroutine case and abi-returning-subroutine

* reconstruct code on argument prep and call

* an example subroutine taking in abi arguments

* update comment example and explanation

* per pr comment

* Changes to router clear state (#386)

* define reference type spec (#383)

* define reference type spec
Co-authored-by: Jason Paulos <jasonpaulos@users.noreply.github.com>
Co-authored-by: Zeph Grunschlag <tzaffi@users.noreply.github.com>

* Rename decode parameters to abide by PEP8 conventions (#389)

* More abi graviton tests (#391)

* test_conditional_factorial()

* Router return subroutine (#422)

* Adding return value to add_method_call

* Method call itxn (#387)

* adding itxn method to call ABI method

* __str__ formatting (#411)

* standardize str formatting

* Check transaction type arguments (#427)

* Check transaction type arguments

* Rename Transaction.set to be private

* Check `Expr` length when converting to `abi.Address` (#432)

* Fix on previous address length check (#433)

* minor fix

* minor

* per Jason comment

* minor, formatting

* unit -> uint (#434)

* Support declaring compatible PyTeal version in source code (#429)

* Add semantic version dependency

* Add `pragma` to enforce compatible compiler versions

* Raise `TealInternalError` instead of `TealInputError`

* Switch back to `pkg_resources` and convert PEP 440 to semantic version 2.0.0

* Fix linter errors

* Make pep 440 converter private

* Add `Pragma` expression

* Refactor pragma functions from compiler to ast to avoid circular dependencies
* Add `is_valid_compiler_version` check helper for the `Pragma` expression
* Use `TealProgramError` instead of `TealInternalError`

* Test underlying TEAL is unchanged

* Refactor underlying pragma methods to parent directory

* Inherit from `Expr` instead

* Fix unclear docstring

* Document init

Document init

* Add caret compiler version tests

* Ignore unused fixture imports

* Consistently use `start_index` and `end_index` (#436)

* Consistently use start_ and end_index

* format

* allow passing router description to Contract constructor (#448)

* allow passing router description to Contract constructor

* Document new ABI features (#400)

* Initial commit

* Fix abi-docs tests (#402)

* Fix abi-docs Sphinx warnings (#401)

* Extend abi-docs with experimental design language (#403)

* Add type fundamentals section

* Add basic type usage and some docstrings for referenced methods

* Finish documenting set and fix overloaded method docs

* Add docstrings for get and __getitem__

* Add reference type docs

* Add txn type examples

* Fix errors

* Make ComputedValue parameter type covariant

* ComputedValue and subroutine sections

* ...wasn't included in previous commit

* Add bare app call and method registration examples

* Add router e2e example and compilation explanation

* Fix post-merge linter/test failures

* Add calling documentation

* Partially address feedback

* Respond to feedback

* Resolve TODOs

* Add pragma references

* didn't make it into the previous commit

* Fix Bool.__module__

* Mention stack size limit

* More pragma documentation

* Address other feedback

* Warn about reference type limits

* **cannot**

Co-authored-by: Michael Diamant <michaeldiamant@users.noreply.github.com>

* Feature/abi merge master (#457)

* Clarify minimum Python version management docs (#435)

* Foreign prefix on App and Asset arrays (#440)

* replacing foreignapps with applications

* fix assets as well

* Add Execute Method (#444)

* adding execute method to allow omission of begin/submit for common use case

* exec docstring

* update testcase

Co-authored-by: Hang Su <hang.su@algorand.com>

Co-authored-by: Michael Diamant <michaeldiamant@users.noreply.github.com>
Co-authored-by: Ben Guidarelli <ben.guidarelli@gmail.com>
Co-authored-by: Hang Su <hang.su@algorand.com>

* `abi.Bool` improvements (#453)

* abi.Bool improvements

* Don't need Seq anymore

* nor its import

* No black, that was not a tuple

* modify integreation tests

* missed one

* Missed a file

* Rename pyteal/ast/abi/bool.py functions to follow PEP 8 conventions (#459)

* Specify dependency versions (#464)

* Rename pyteal/ast/abi/util.py functions to follow PEP 8 conventions (#460)

* Rename pyteal/ast/abi/tuple.py functions to follow PEP 8 conventions (#461)

* Fix typos in pyteal/ast/abi/util.py (#467)

* Rename encoded_string to demarcate internal usage (#466)

* Rename pyteal/ast/abi method parameters to follow PEP 8 conventions (#468)

Co-authored-by: Ben Guidarelli <ben.guidarelli@gmail.com>
Co-authored-by: Jason Paulos <jasonpaulos@users.noreply.github.com>
Co-authored-by: Giorgio Ciotti <gciotti.dev@gmail.com>
Co-authored-by: Hang Su <87964331+ahangsu@users.noreply.github.com>
Co-authored-by: Hang Su <hang.su@algorand.com>
Co-authored-by: Zeph Grunschlag <tzaffi@users.noreply.github.com>
Co-authored-by: Zeph Grunschlag <zeph@algorand.com>
Co-authored-by: Jacob Daitzman <jdtzmn@gmail.com>
  • Loading branch information
9 people committed Jul 22, 2022
1 parent d51857b commit 82dbe2e
Show file tree
Hide file tree
Showing 155 changed files with 27,655 additions and 601 deletions.
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ignore =

per-file-ignores =
pyteal/compiler/optimizer/__init__.py: F401
examples/application/abi/algobank.py: F403, F405
examples/application/asset.py: F403, F405
examples/application/opup.py: F403, F405
examples/application/security_token.py: F403, F405
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Install python dependencies
run: make setup-development
- name: Build and Test
run: make build-and-test
run: make lint-and-test

run-integration-tests:
runs-on: ubuntu-20.04
Expand Down Expand Up @@ -63,8 +63,8 @@ jobs:
run: make sandbox-dev-up
- name: Install python dependencies
run: make setup-development
- name: Build, Unit Tests and Integration Tests
run: make all-tests
- name: Integration Tests Only
run: make test-integration
- name: Stop running images
run: make sandbox-dev-stop

Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ celerybeat-schedule
*.sage.py

# Environments
_env
.env
.venv
env/
Expand Down Expand Up @@ -138,3 +139,6 @@ dmypy.json

# mac OS
.DS_Store

# asdf
.tool-versions
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ black:
flake8:
flake8 $(ALLPY)

MYPY = pyteal scripts
MYPY = pyteal scripts tests
mypy:
mypy --show-error-codes $(MYPY)

Expand All @@ -54,9 +54,9 @@ test-unit:
pytest -n $(NUM_PROCS) --durations=10 -sv pyteal tests/unit --ignore tests/unit/blackbox_test.py --ignore tests/unit/user_guide_test.py
pytest -n 1 -sv tests/unit/blackbox_test.py tests/unit/user_guide_test.py

build-and-test: check-generate-init lint test-unit
lint-and-test: check-generate-init lint test-unit

# ---- Integration Test (algod required) ---- #
# ---- Integration Tests (algod required) ---- #

sandbox-dev-up:
docker-compose up -d algod
Expand All @@ -69,7 +69,7 @@ integration-run:

test-integration: integration-run

all-tests: build-and-test test-integration
all-tests: lint-and-test test-integration

# ---- Local Github Actions Simulation via `act` ---- #
# assumes act is installed, e.g. via `brew install act`
Expand Down
917 changes: 917 additions & 0 deletions docs/abi.rst

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,19 @@ PyTeal Package
:annotation: = <pyteal.TxnObject object>

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

If a transaction group was submitted most recently, then this will be the last transaction in that group.

.. data:: Gitxn
:annotation: = <pyteal.InnerTxnGroup object>

The most recently submitted inner transaction group. This is an instance of :any:`InnerTxnGroup`.

If a single transaction was submitted most recently, then this will be a group of size 1.

.. automodule:: pyteal.abi
:members:
:undoc-members:
:imported-members:
:special-members: __getitem__
:show-inheritance:
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ PyTeal **hasn't been security audited**. Use it at your own risk.
versions
compiler_optimization
opup
abi

.. toctree::
:maxdepth: 3
Expand Down
36 changes: 28 additions & 8 deletions docs/versions.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.. _versions:

TEAL Versions
Versions
=============

Each version of PyTeal compiles contracts for a specific version of TEAL. Newer versions of TEAL
Expand All @@ -18,14 +18,34 @@ TEAL Version PyTeal Version
6 >= 0.10.0
============ ==============

.. _version pragmas:

Version Pragmas
----------------

When writing a PyTeal smart contract, it's important to target a specific AVM version and to compile
with a single PyTeal version. This will ensure your compiled program remains consistent and has the
exact same behavior no matter when you compile it.

The :any:`pragma` function can be used to assert that the current PyTeal version matches a constraint
of your choosing. This can help strengthen the dependency your source code has on the PyTeal package
version you used when writing it.

If you are writing code for others to consume, or if your codebase has different PyTeal version
dependencies in different places, the :any:`Pragma` expression can be used to apply a pragma
constraint to only a section of the AST.

PyTeal v0.5.4 and Below
-----------------------

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

**WARNING:** before updating PyTeal to a version with generates TEAL v2 contracts and fixing the
programs to use the global function :any:`compileTeal` rather the class method :code:`.teal()`, make
sure your program abides by the TEAL safety guidelines `<https://developer.algorand.org/docs/reference/teal/guidelines/>`_.
Changing a v1 TEAL program to a v2 TEAL program without any code changes is insecure because v2
TEAL programs allow rekeying. Specifically, you must add a check that the :code:`RekeyTo` property
of any transaction is set to the zero address when updating an older PyTeal program from v0.5.4 and
below.
.. warning::
If you are updating from a v1 TEAL program, make
sure your program abides by the `TEAL safety guidelines <https://developer.algorand.org/docs/reference/teal/guidelines/>`_.
Changing a v1 TEAL program to a v2 TEAL program without any code changes is insecure because v2
TEAL programs allow rekeying. Specifically, you must add a check that the :code:`RekeyTo` property
of any transaction is set to the zero address when updating an older PyTeal program from v0.5.4 and
below.
Empty file.
54 changes: 54 additions & 0 deletions examples/application/abi/algobank.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "AlgoBank",
"methods": [
{
"name": "deposit",
"args": [
{
"type": "pay",
"name": "payment"
},
{
"type": "account",
"name": "sender"
}
],
"returns": {
"type": "void"
},
"desc": "This method receives a payment from an account opted into this app and records it in their local state. The caller may opt into this app during this call."
},
{
"name": "getBalance",
"args": [
{
"type": "account",
"name": "user"
}
],
"returns": {
"type": "uint64"
},
"desc": "Lookup the balance of a user held by this app."
},
{
"name": "withdraw",
"args": [
{
"type": "uint64",
"name": "amount"
},
{
"type": "account",
"name": "recipient"
}
],
"returns": {
"type": "void"
},
"desc": "Withdraw an amount of Algos held by this app. The sender of this method call will be the source of the Algos, and the destination will be the `recipient` argument. This may or may not be the same as the sender's address. This method will fail if the amount of Algos requested to be withdrawn exceeds the amount of Algos held by this app for the sender. The Algos will be transferred to the recipient using an inner transaction whose fee is set to 0, meaning the caller's transaction must include a surplus fee to cover the inner transaction."
}
],
"desc": null,
"networks": {}
}
113 changes: 113 additions & 0 deletions examples/application/abi/algobank.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# This example is provided for informational purposes only and has not been audited for security.
from pyteal import *
import json


@Subroutine(TealType.none)
def assert_sender_is_creator() -> Expr:
return Assert(Txn.sender() == Global.creator_address())


# move any balance that the user has into the "lost" amount when they close out or clear state
transfer_balance_to_lost = App.globalPut(
Bytes("lost"),
App.globalGet(Bytes("lost")) + App.localGet(Txn.sender(), Bytes("balance")),
)

router = Router(
name="AlgoBank",
bare_calls=BareCallActions(
# approve a creation no-op call
no_op=OnCompleteAction(action=Approve(), call_config=CallConfig.CREATE),
# approve opt-in calls during normal usage, and during creation as a convenience for the creator
opt_in=OnCompleteAction(action=Approve(), call_config=CallConfig.ALL),
# move any balance that the user has into the "lost" amount when they close out or clear state
close_out=OnCompleteAction(
action=transfer_balance_to_lost, call_config=CallConfig.CALL
),
clear_state=OnCompleteAction(
action=transfer_balance_to_lost, call_config=CallConfig.CALL
),
# only the creator can update or delete the app
update_application=OnCompleteAction(
action=assert_sender_is_creator, call_config=CallConfig.CALL
),
delete_application=OnCompleteAction(
action=assert_sender_is_creator, call_config=CallConfig.CALL
),
),
)


@router.method(no_op=CallConfig.CALL, opt_in=CallConfig.CALL)
def deposit(payment: abi.PaymentTransaction, sender: abi.Account) -> Expr:
"""This method receives a payment from an account opted into this app and records it in
their local state.
The caller may opt into this app during this call.
"""
return Seq(
Assert(payment.get().sender() == sender.address()),
Assert(payment.get().receiver() == Global.current_application_address()),
App.localPut(
sender.address(),
Bytes("balance"),
App.localGet(sender.address(), Bytes("balance")) + payment.get().amount(),
),
)


@router.method
def getBalance(user: abi.Account, *, output: abi.Uint64) -> Expr:
"""Lookup the balance of a user held by this app."""
return output.set(App.localGet(user.address(), Bytes("balance")))


@router.method
def withdraw(amount: abi.Uint64, recipient: abi.Account) -> Expr:
"""Withdraw an amount of Algos held by this app.
The sender of this method call will be the source of the Algos, and the destination will be
the `recipient` argument. This may or may not be the same as the sender's address.
This method will fail if the amount of Algos requested to be withdrawn exceeds the amount of
Algos held by this app for the sender.
The Algos will be transferred to the recipient using an inner transaction whose fee is set
to 0, meaning the caller's transaction must include a surplus fee to cover the inner
transaction.
"""
return Seq(
# if amount is larger than App.localGet(Txn.sender(), Bytes("balance")), the subtraction
# will underflow and fail this method call
App.localPut(
Txn.sender(),
Bytes("balance"),
App.localGet(Txn.sender(), Bytes("balance")) - amount.get(),
),
InnerTxnBuilder.Begin(),
InnerTxnBuilder.SetFields(
{
TxnField.type_enum: TxnType.Payment,
TxnField.receiver: recipient.address(),
TxnField.amount: amount.get(),
TxnField.fee: Int(0),
}
),
InnerTxnBuilder.Submit(),
)


approval_program, clear_state_program, contract = router.compile_program(
version=6, optimize=OptimizeOptions(scratch_slots=True)
)

if __name__ == "__main__":
with open("algobank_approval.teal", "w") as f:
f.write(approval_program)

with open("algobank_clear_state.teal", "w") as f:
f.write(clear_state_program)

with open("algobank.json", "w") as f:
f.write(json.dumps(contract.dictify(), indent=4))

0 comments on commit 82dbe2e

Please sign in to comment.