Skip to content

Commit 9a6a854

Browse files
authored
ABI Method Return (#175)
Encode ABI variable and concat with `RETURN_METHOD_SELECTOR` and log it.
1 parent 217b678 commit 9a6a854

File tree

4 files changed

+79
-0
lines changed

4 files changed

+79
-0
lines changed

pyteal/ast/abi/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from .array_static import StaticArrayTypeSpec, StaticArray
3030
from .array_dynamic import DynamicArrayTypeSpec, DynamicArray
3131
from .util import type_spec_from_annotation
32+
from .method_return import MethodReturn
3233

3334
__all__ = [
3435
"TypeSpec",
@@ -65,4 +66,5 @@
6566
"DynamicArrayTypeSpec",
6667
"DynamicArray",
6768
"type_spec_from_annotation",
69+
"MethodReturn",
6870
]

pyteal/ast/abi/method_return.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from typing import TYPE_CHECKING, Tuple
2+
from . import BaseType
3+
from ...types import TealType
4+
from ...errors import TealInputError
5+
from .. import Expr, Log, Concat, Bytes
6+
from ...ir import TealBlock, TealSimpleBlock, Op
7+
from ...config import RETURN_METHOD_SELECTOR
8+
9+
if TYPE_CHECKING:
10+
from ...compiler import CompileOptions
11+
12+
13+
class MethodReturn(Expr):
14+
def __init__(self, arg: BaseType):
15+
super().__init__()
16+
if not isinstance(arg, BaseType):
17+
raise TealInputError(f"Expecting an ABI type argument but get {arg}")
18+
self.arg = arg
19+
20+
def __teal__(self, options: "CompileOptions") -> Tuple[TealBlock, TealSimpleBlock]:
21+
if options.version < Op.log.min_version:
22+
raise TealInputError(
23+
f"current version {options.version} is lower than log's min version {Op.log.min_version}"
24+
)
25+
return Log(
26+
Concat(Bytes("base16", RETURN_METHOD_SELECTOR), self.arg.encode())
27+
).__teal__(options)
28+
29+
def __str__(self) -> str:
30+
return f"(MethodReturn {self.arg.type_spec()})"
31+
32+
def type_of(self) -> TealType:
33+
return TealType.none
34+
35+
def has_return(self) -> bool:
36+
return False
37+
38+
39+
MethodReturn.__module__ = "pyteal"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import pytest
2+
3+
from . import *
4+
from .. import Int, Bytes
5+
from ...types import TealType
6+
from ...errors import TealInputError
7+
8+
9+
POSITIVE_CASES = [
10+
Uint16(),
11+
Uint32(),
12+
StaticArray(BoolTypeSpec(), 12),
13+
]
14+
15+
16+
@pytest.mark.parametrize("case", POSITIVE_CASES)
17+
def test_method_return(case):
18+
m_ret = MethodReturn(case)
19+
assert m_ret.type_of() == TealType.none
20+
assert not m_ret.has_return()
21+
assert str(m_ret) == f"(MethodReturn {case.type_spec()})"
22+
23+
24+
NEGATIVE_CASES = [
25+
Int(0),
26+
Bytes("aaaaaaa"),
27+
Uint16,
28+
Uint32,
29+
]
30+
31+
32+
@pytest.mark.parametrize("case", NEGATIVE_CASES)
33+
def test_method_return_error(case):
34+
with pytest.raises(TealInputError):
35+
MethodReturn(case)

pyteal/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33

44
# Number of scratch space slots available.
55
NUM_SLOTS = 256
6+
7+
# Method return selector in base16
8+
RETURN_METHOD_SELECTOR = "0x151F7C75"

0 commit comments

Comments
 (0)