diff --git a/py/main.py b/py/dryrun.py similarity index 82% rename from py/main.py rename to py/dryrun.py index 956e164..8914d17 100644 --- a/py/main.py +++ b/py/dryrun.py @@ -4,7 +4,7 @@ AtomicTransactionComposer, TransactionWithSigner, ) -from algosdk.future import transaction +from algosdk import transaction from util import ( create_app, create_asa, @@ -13,7 +13,7 @@ get_contract, ) from beaker import sandbox -from beaker.client.logic_error import LogicException +import os def main(): @@ -21,7 +21,7 @@ def main(): algod_client = sandbox.clients.get_algod_client() acct = sandbox.kmd.get_accounts().pop() - approval_program, approval_bin, approval_map = get_approval_program(algod_client) + _, approval_bin, _ = get_approval_program(algod_client) _, clear_bin, _ = get_clear_program(algod_client) contract = get_contract() @@ -62,10 +62,7 @@ def main(): try: atc.execute(algod_client, 4) except Exception as e: - le = LogicException(e, approval_program, approval_map) - print( - f"A Logic Exception was encountered: '{le.msg[:40]}...'\n\t{le.trace()}\n" - ) + print(f"A Logic Exception was encountered: '{e}\n") perform_dryrun(atc, algod_client) return @@ -90,10 +87,7 @@ def main(): try: atc.execute(algod_client, 4) except Exception as e: - le = LogicException(e, approval_program, approval_map) - print( - f"A Logic Exception was encountered: '{le.msg[:55]}...'\n\t{le.trace()}\n" - ) + print(f"A Logic Exception was encountered: '{e}\n") perform_dryrun(atc, algod_client) return @@ -111,10 +105,7 @@ def main(): try: atc.execute(algod_client, 4) except Exception as e: - le = LogicException(e, approval_program, approval_map) - print( - f"A Logic Exception was encountered: '{le.msg[:50]}...'\n\t{le.trace()}\n" - ) + print(f"A Logic Exception was encountered: '{e}\n") perform_dryrun(atc, algod_client) return @@ -125,7 +116,8 @@ def perform_dryrun(atc: AtomicTransactionComposer, client: algod.AlgodClient): dryrun_result = DryrunResponse(client.dryrun(drr)) for txn in dryrun_result.txns: if txn.app_call_rejected(): - print(txn.app_trace(StackPrinterConfig(max_value_width=0))) + width = round(os.get_terminal_size().columns / 3) + print(txn.app_trace(StackPrinterConfig(max_value_width=width))) if __name__ == "__main__": diff --git a/py/requirements.txt b/py/requirements.txt new file mode 100644 index 0000000..f6cf019 --- /dev/null +++ b/py/requirements.txt @@ -0,0 +1,10 @@ +beaker-pyteal==0.5.4 +cffi==1.15.1 +docstring-parser==0.14.1 +msgpack==1.0.4 +py-algorand-sdk @ git+https://github.com/algorand/py-algorand-sdk@develop +pycparser==2.21 +pycryptodomex==3.17 +PyNaCl==1.5.0 +pyteal==0.22.0 +semantic-version==2.10.0 diff --git a/py/simulate.py b/py/simulate.py new file mode 100644 index 0000000..9c46452 --- /dev/null +++ b/py/simulate.py @@ -0,0 +1,135 @@ +from algosdk.v2client import algod +from algosdk.dryrun_results import DryrunResponse, StackPrinterConfig +from algosdk.atomic_transaction_composer import ( + AtomicTransactionComposer, + TransactionWithSigner, +) +from algosdk import transaction +from util import ( + create_app, + create_asa, + get_approval_program, + get_clear_program, + get_contract, +) +from beaker import sandbox +import os +import json + + +def main(): + # setup + algod_client = sandbox.clients.get_algod_client() + acct = sandbox.kmd.get_accounts().pop() + + _, approval_bin, _ = get_approval_program(algod_client) + _, clear_bin, _ = get_clear_program(algod_client) + + contract = get_contract() + + app_id, app_addr = create_app( + algod_client, + acct.address, + acct.private_key, + approval_bin, + clear_bin, + transaction.StateSchema(1, 0), + transaction.StateSchema(0, 0), + ) + + asa_id = create_asa( + algod_client, acct.address, acct.private_key, "tmp_asset", "tmp", 10000, 0 + ) + + sp = algod_client.suggested_params() + + # TODO: Need to cover fees for the inner transaction (uncomment these lines) + # sp.flat_fee = True # Tell the SDK we know exactly what our fee should be + # sp.fee = 2000 # Cover 2 transaction (outer + inner) + + # Create transaction to bootstrap application + atc = AtomicTransactionComposer() + atc.add_method_call( + app_id, + contract.get_method_by_name("bootstrap"), + acct.address, + sp, + signer=acct.signer, + # TODO: the asset id should be passed + method_args=[0], + # method_args=[asa_id], + ) + + try: + atc.execute(algod_client, 4) + except Exception as e: + perform_simulate(atc, algod_client) + return + + # Create group transaction to send asset and call method + atc = AtomicTransactionComposer() + atc.add_method_call( + app_id, + contract.get_method_by_name("transfer"), + acct.address, + sp, + signer=acct.signer, + method_args=[ + TransactionWithSigner( + # TODO: make this not fail + txn=transaction.AssetTransferTxn(acct.address, sp, app_addr, 9, asa_id), + # txn=transaction.AssetTransferTxn(acct.address, sp, app_addr, 10, asa_id), + signer=acct.signer, + ), + asa_id, + ], + ) + try: + atc.execute(algod_client, 4) + except Exception as e: + perform_simulate(atc, algod_client) + return + + # Create group transaction to send asset and call method + # See TODO in contracts/application.py + atc = AtomicTransactionComposer() + atc.add_method_call( + app_id, + contract.get_method_by_name("withdraw"), + acct.address, + sp, + signer=acct.signer, + method_args=[asa_id], + ) + try: + atc.execute(algod_client, 4) + except Exception as e: + perform_simulate(atc, algod_client) + return + + +def perform_simulate(atc: AtomicTransactionComposer, client: algod.AlgodClient): + r = atc.simulate(client) + print(f"Failure Message: {r.failure_message}") + print(f"Simulation Transaction Results:") + + for g in r.simulate_response["txn-groups"]: + for i, t in enumerate(g["txn-results"]): + print(f" Transaction {i}:") + for k, v in t["txn-result"].items(): + print(f" {k}: {v}") + + failed_at_msg = f"Failed at: gtxn index {r.failed_at[0]}" + if len(r.failed_at) > 1: + failed_at_msg += ( + f", inner tnx index {r.failed_at[-1]} at depth level {len(r.failed_at) - 1}" + ) + + print(failed_at_msg) + print(f"ABI Return Values:") + for res in r.abi_results: + print(f" {res.tx_id}: {res.return_value}") + + +if __name__ == "__main__": + main() diff --git a/py/util.py b/py/util.py index 325b520..9f9bf8b 100644 --- a/py/util.py +++ b/py/util.py @@ -1,6 +1,6 @@ from algosdk.v2client import algod from algosdk.kmd import KMDClient -from algosdk.future import transaction +from algosdk import transaction from algosdk.source_map import SourceMap from algosdk import abi import base64