-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5d901c9
commit 68bdee3
Showing
24 changed files
with
1,430 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
name: Pull Request validation | ||
|
||
on: [pull_request] | ||
|
||
jobs: | ||
pr-check: | ||
name: Check Python | ||
uses: ./.github/workflows/check-python.yaml | ||
|
||
pr-build: | ||
name: Build and Test Python | ||
needs: pr-check | ||
uses: ./.github/workflows/build-python.yaml |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import imp | ||
import logging | ||
import os | ||
import sys | ||
from collections.abc import Generator | ||
from contextlib import contextmanager | ||
from pathlib import Path | ||
|
||
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(levelname)-10s: %(message)s") | ||
logger = logging.getLogger(__name__) | ||
root_path = Path(__file__).parent | ||
|
||
|
||
@contextmanager | ||
def cwd(path: Path) -> Generator[None, None, None]: | ||
old_pwd = os.getcwd() | ||
os.chdir(path) | ||
try: | ||
yield | ||
finally: | ||
os.chdir(old_pwd) | ||
|
||
|
||
def main(action: str) -> None: | ||
match action: | ||
case "build": | ||
example_dirs = filter(lambda file: file.is_dir() and "__" not in file.name, root_path.glob("*")) | ||
for example in example_dirs: | ||
logger.info(f"Building example {example.name}") | ||
with cwd(root_path): | ||
evaluated_file = imp.load_source(example.name, f"./{example.name}/{example.name}.py") | ||
app = evaluated_file.app | ||
logger.info(f" Building app {app.name}") | ||
appspec = app.build() | ||
logger.info(f" Writing {example.name}/application.json") | ||
(example / "application.json").write_text(appspec.to_json()) | ||
|
||
|
||
if __name__ == "__main__": | ||
if len(sys.argv) > 1: | ||
main(sys.argv[1]) | ||
else: | ||
main("build") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import logging | ||
|
||
from .helloworld import helloworld | ||
from .lifecycle import lifecycle | ||
from .state import state | ||
from .voting import voting | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
# define example contracts to build | ||
contracts = [helloworld.app, lifecycle.app, state.app, voting.app] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import uuid | ||
|
||
import algokit_utils | ||
import pytest | ||
from algosdk.v2client.algod import AlgodClient | ||
from algosdk.v2client.indexer import IndexerClient | ||
|
||
|
||
@pytest.fixture(scope="session") | ||
def algod_client() -> AlgodClient: | ||
return algokit_utils.get_algod_client(algokit_utils.get_default_localnet_config("algod")) | ||
|
||
|
||
@pytest.fixture(scope="session") | ||
def indexer_client() -> IndexerClient: | ||
return algokit_utils.get_indexer_client(algokit_utils.get_default_localnet_config("indexer")) | ||
|
||
|
||
@pytest.fixture() | ||
def new_account(algod_client: AlgodClient) -> algokit_utils.Account: | ||
unique_name = str(uuid.uuid4()).replace("-", "") | ||
return algokit_utils.get_account(algod_client, unique_name) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import beaker | ||
import pyteal as pt | ||
from algokit_utils import DELETABLE_TEMPLATE_NAME, UPDATABLE_TEMPLATE_NAME | ||
|
||
|
||
def deploy_time_immutability_control(app: beaker.Application) -> None: | ||
@app.update(authorize=beaker.Authorize.only_creator(), bare=True) | ||
def update() -> pt.Expr: | ||
return pt.Assert( | ||
pt.Tmpl.Int(UPDATABLE_TEMPLATE_NAME), | ||
comment="Check app is updatable", | ||
) | ||
|
||
|
||
def deploy_time_permanence_control(app: beaker.Application) -> None: | ||
@app.delete(authorize=beaker.Authorize.only_creator(), bare=True) | ||
def delete() -> pt.Expr: | ||
return pt.Assert( | ||
pt.Tmpl.Int(DELETABLE_TEMPLATE_NAME), | ||
comment="Check app is deletable", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from algokit_client_generator.writer import generate_client | ||
|
||
__all__ = ["generate_client"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import beaker | ||
import pyteal as pt | ||
|
||
from examples.deployment_standard import ( | ||
deploy_time_immutability_control, | ||
deploy_time_permanence_control, | ||
) | ||
|
||
app = beaker.Application("HelloWorldApp").apply(deploy_time_immutability_control).apply(deploy_time_permanence_control) | ||
|
||
|
||
@app.external | ||
def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr: | ||
"""Returns Hello, {name}""" | ||
return output.set(pt.Concat(pt.Bytes("Hello, "), name.get())) | ||
|
||
|
||
@app.external | ||
def hello_world_check(name: pt.abi.String) -> pt.Expr: | ||
"""Asserts {name} is "World" """ | ||
return pt.Assert(name.get() == pt.Bytes("World")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import pytest | ||
from algokit_utils import OnUpdate, get_localnet_default_account | ||
from algosdk.atomic_transaction_composer import AccountTransactionSigner | ||
from algosdk.v2client.algod import AlgodClient | ||
from algosdk.v2client.indexer import IndexerClient | ||
|
||
from examples.helloworld.client_generated import HelloWorldAppClient | ||
|
||
|
||
@pytest.fixture(scope="session") | ||
def helloworld_client(algod_client: AlgodClient, indexer_client: IndexerClient) -> HelloWorldAppClient: | ||
client = HelloWorldAppClient( | ||
algod_client=algod_client, | ||
indexer_client=indexer_client, | ||
creator=get_localnet_default_account(algod_client), | ||
) | ||
client.deploy(allow_delete=True, allow_update=True, on_update=OnUpdate.UpdateApp) | ||
return client | ||
|
||
|
||
def test_hello(helloworld_client: HelloWorldAppClient) -> None: | ||
response = helloworld_client.hello(name="World") | ||
|
||
assert response.return_value == "Hello, World" | ||
|
||
|
||
def test_hello_check_args(helloworld_client: HelloWorldAppClient) -> None: | ||
response = helloworld_client.hello_world_check(name="World") | ||
|
||
assert response.return_value is None | ||
|
||
|
||
def test_lifecycle(algod_client: AlgodClient) -> None: | ||
account = get_localnet_default_account(algod_client) | ||
signer = AccountTransactionSigner(account.private_key) | ||
|
||
helloworld_client = HelloWorldAppClient( | ||
algod_client=algod_client, signer=signer, template_values={"UPDATABLE": 1, "DELETABLE": 1} | ||
) | ||
|
||
assert helloworld_client.create() | ||
assert helloworld_client.update() | ||
|
||
response = helloworld_client.hello(name="World") | ||
|
||
assert response.return_value == "Hello, World" | ||
|
||
assert helloworld_client.delete() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from algokit_client_generator.writer import generate_client | ||
|
||
__all__ = ["generate_client"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import dataclasses | ||
from typing import cast | ||
|
||
import beaker | ||
import pyteal as pt | ||
from beaker.lib.iter import Iterate | ||
from beaker.lib.strings import Itoa | ||
from pyteal.ast import CallConfig, MethodConfig | ||
|
||
from examples.deployment_standard import ( | ||
deploy_time_immutability_control, | ||
) | ||
|
||
|
||
@dataclasses.dataclass | ||
class LifeCycleData: | ||
greeting = beaker.GlobalStateValue(stack_type=pt.TealType.bytes) | ||
times = beaker.GlobalStateValue(stack_type=pt.TealType.uint64) | ||
|
||
|
||
app = beaker.Application("LifeCycleApp", state=LifeCycleData()).apply(deploy_time_immutability_control) | ||
|
||
|
||
@app.external | ||
def hello(name: pt.abi.String, *, output: pt.abi.String) -> pt.Expr: | ||
return pt.Seq( | ||
(buff := pt.ScratchVar()).store(pt.Bytes("")), | ||
Iterate( | ||
buff.store( | ||
pt.Concat(buff.load(), app.state.greeting.get(), pt.Bytes(", "), name.get(), pt.Bytes("\n")) | ||
), # result += greeting, name\n | ||
cast(pt.Int, app.state.times.get()), | ||
), | ||
output.set(buff.load()), | ||
) | ||
|
||
|
||
@app.external(name="hello") | ||
def hello_no_arg(*, output: pt.abi.String) -> pt.Expr: | ||
return pt.Seq( | ||
(buff := pt.ScratchVar()).store(pt.Bytes("")), | ||
Iterate( | ||
buff.store( | ||
pt.Concat(buff.load(), app.state.greeting.get(), pt.Bytes(", mystery person\n")) | ||
), # result += greeting, mystery person\n | ||
cast(pt.Int, app.state.times.get()), | ||
), | ||
output.set(buff.load()), | ||
) | ||
|
||
|
||
@app.external(bare=True, method_config=MethodConfig(no_op=CallConfig.CREATE, opt_in=CallConfig.CREATE)) | ||
def bare_create() -> pt.Expr: | ||
"""Bare create method""" | ||
return pt.Seq(app.state.greeting.set(pt.Bytes("Hello")), app.state.times.set(pt.Int(1)), pt.Approve()) | ||
|
||
|
||
@app.create(name="create") | ||
def create_1arg(greeting: pt.abi.String, *, output: pt.abi.String) -> pt.Expr: | ||
"""ABI create method with 1 argument""" | ||
return pt.Seq( | ||
app.state.greeting.set(greeting.get()), | ||
app.state.times.set(pt.Int(1)), | ||
output.set(pt.Concat(greeting.get(), pt.Bytes("_"), Itoa(app.state.times.get()))), | ||
) | ||
|
||
|
||
@app.create(name="create") | ||
def create_2arg(greeting: pt.abi.String, times: pt.abi.Uint32) -> pt.Expr: | ||
"""ABI create method with 2 arguments""" | ||
return pt.Seq(app.state.greeting.set(greeting.get()), app.state.times.set(times.get()), pt.Approve()) | ||
|
||
|
||
@app.clear_state() | ||
def clear() -> pt.Expr: | ||
return pt.Approve() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import pytest | ||
from algokit_utils import ( | ||
Account, | ||
get_localnet_default_account, | ||
) | ||
from algosdk.atomic_transaction_composer import AccountTransactionSigner | ||
from algosdk.v2client.algod import AlgodClient | ||
from algosdk.v2client.indexer import IndexerClient | ||
|
||
from examples.lifecycle.client_generated import ( | ||
CreateStringArgs, | ||
CreateVoidArgs, | ||
DeployCreate_CreateStringArgs, | ||
DeployCreate_CreateVoidArgs, | ||
LifeCycleAppClient, | ||
) | ||
|
||
|
||
@pytest.fixture(scope="session") | ||
def lifecycle_client(algod_client: AlgodClient, indexer_client: IndexerClient) -> LifeCycleAppClient: | ||
account = get_localnet_default_account(algod_client) | ||
signer = AccountTransactionSigner(account.private_key) | ||
|
||
return LifeCycleAppClient(algod_client=algod_client, signer=signer, template_values={"UPDATABLE": 1}) | ||
|
||
|
||
def test_create_bare(lifecycle_client: LifeCycleAppClient) -> None: | ||
create_response = lifecycle_client.create(args=None) | ||
assert create_response | ||
response = lifecycle_client.hello_1_args(name="Bare") | ||
|
||
assert response.return_value == "Hello, Bare\n" | ||
|
||
|
||
def test_create_1arg(lifecycle_client: LifeCycleAppClient) -> None: | ||
create_response = lifecycle_client.create(args=CreateStringArgs(greeting="Greetings")) | ||
assert create_response.return_value == "Greetings_1" | ||
response = lifecycle_client.hello_1_args(name="1 Arg") | ||
|
||
assert response.return_value == "Greetings, 1 Arg\n" | ||
|
||
|
||
def test_create_2arg(lifecycle_client: LifeCycleAppClient) -> None: | ||
create_response = lifecycle_client.create(args=CreateVoidArgs(greeting="Greetings", times=2)) | ||
assert create_response.return_value is None | ||
response = lifecycle_client.hello_1_args(name="2 Arg") | ||
|
||
assert response.return_value == "Greetings, 2 Arg\nGreetings, 2 Arg\n" | ||
|
||
|
||
@pytest.fixture() | ||
def deploy_lifecycle_client( | ||
algod_client: AlgodClient, indexer_client: IndexerClient, new_account: Account | ||
) -> LifeCycleAppClient: | ||
return LifeCycleAppClient( | ||
algod_client=algod_client, | ||
indexer_client=indexer_client, | ||
creator=new_account, | ||
) | ||
|
||
|
||
def test_deploy_bare(deploy_lifecycle_client: LifeCycleAppClient) -> None: | ||
deploy_lifecycle_client.deploy(allow_update=True, create_args=None) | ||
assert deploy_lifecycle_client.app_client.app_id | ||
|
||
response = deploy_lifecycle_client.hello_1_args(name="Deploy Bare") | ||
|
||
assert response.return_value == "Hello, Deploy Bare\n" | ||
|
||
|
||
def test_deploy_create_1arg(deploy_lifecycle_client: LifeCycleAppClient) -> None: | ||
deploy_lifecycle_client.deploy( | ||
allow_update=True, | ||
create_args=DeployCreate_CreateStringArgs(args=CreateStringArgs(greeting="Deploy Greetings")), | ||
) | ||
assert deploy_lifecycle_client.app_client.app_id | ||
|
||
response = deploy_lifecycle_client.hello_1_args(name="1 Arg") | ||
|
||
assert response.return_value == "Deploy Greetings, 1 Arg\n" | ||
|
||
|
||
def test_deploy_create_2arg(deploy_lifecycle_client: LifeCycleAppClient) -> None: | ||
deploy_lifecycle_client.deploy( | ||
allow_update=True, | ||
create_args=DeployCreate_CreateVoidArgs( | ||
args=CreateVoidArgs(greeting="Deploy Greetings", times=2), | ||
), | ||
) | ||
assert deploy_lifecycle_client.app_client.app_id | ||
|
||
response = deploy_lifecycle_client.hello_1_args(name="2 Arg") | ||
|
||
assert response.return_value == "Deploy Greetings, 2 Arg\nDeploy Greetings, 2 Arg\n" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from algokit_client_generator.writer import generate_client | ||
|
||
__all__ = ["generate_client"] |
Oops, something went wrong.
68bdee3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverage Report