diff --git a/examples/sizes.txt b/examples/sizes.txt index 498182f6d1..dcafe6b972 100644 --- a/examples/sizes.txt +++ b/examples/sizes.txt @@ -46,6 +46,7 @@ inheritance/Parent 89 89 0 89 0 inner_transactions 1264 1193 71 1193 0 inner_transactions/ArrayAccess 212 195 17 195 0 + inner_transactions/CreateAndTransfer 135 123 12 123 0 inner_transactions/FieldTuple 504 462 42 462 0 inner_transactions/Greeter 321 302 19 302 0 inner_transactions/itxn_loop 191 184 7 184 0 diff --git a/src/puya/compile.py b/src/puya/compile.py index cc42e1685b..0e99e6a8f6 100644 --- a/src/puya/compile.py +++ b/src/puya/compile.py @@ -38,8 +38,10 @@ from puya.teal.main import mir_to_teal from puya.utils import determine_out_dir, make_path_relative_to_cwd -MAX_SUPPORTED_ALGOPY_VERSION = version.parse("1.0.1") -MIN_SUPPORTED_ALGOPY_VERSION = version.parse(f"{MAX_SUPPORTED_ALGOPY_VERSION.major}.0.0") +# this should contain the lowest version number that this compiler does NOT support +# i.e. the next minor version after what is defined in stubs/pyproject.toml:tool.poetry.version +MAX_SUPPORTED_ALGOPY_VERSION_EX = version.parse("1.1.0") +MIN_SUPPORTED_ALGOPY_VERSION = version.parse(f"{MAX_SUPPORTED_ALGOPY_VERSION_EX.major}.0.0") logger = log.get_logger(__name__) @@ -248,10 +250,10 @@ def _check_algopy_version(site_packages: Path) -> None: algopy_version = version.parse(algopy.version) logger.debug(f"Found algopy: {algopy_version}") - if not (MIN_SUPPORTED_ALGOPY_VERSION <= algopy_version <= MAX_SUPPORTED_ALGOPY_VERSION): + if not (MIN_SUPPORTED_ALGOPY_VERSION <= algopy_version < MAX_SUPPORTED_ALGOPY_VERSION_EX): raise CodeError( f"algopy version {algopy_version} is outside the supported range:" - f" >={MIN_SUPPORTED_ALGOPY_VERSION}, <={MAX_SUPPORTED_ALGOPY_VERSION}" + f" >={MIN_SUPPORTED_ALGOPY_VERSION}, <{MAX_SUPPORTED_ALGOPY_VERSION_EX}" ) diff --git a/stubs/README.md b/stubs/README.md index 465b6b9c45..a52e97b9ad 100644 --- a/stubs/README.md +++ b/stubs/README.md @@ -17,3 +17,73 @@ from algopy import Contract ``` For more details on using this API and the puyapy compiler see https://algorandfoundation.github.io/puya/ + +## Versioning + +The Algorand Python API follows [semver](https://semver.org/) principles, however since the compiler is very closely +coupled with the stubs definition, it's worth noting the interplay. + +### Major +An increase in the major version should only occur if existing contracts would fail to type-check +after the update. + +Some examples of situations that might cause this: +- Breaking changes to the signature of an existing function, such as a new parameter being added + to an existing + method and no default value is provided. +- Something has been renamed, or moved such that the import path has changed (excluding moving + between private modules, indicated with a leading underscore). +- Something has been removed. + +The first two examples would necessitate changes in the compiler itself as well, which should +also be considered breaking changes, thus there would be a coinciding new major version of the +compiler. + +The third example may not necessitate a change to the compiler, although it probably would be +likely there is one to remove the supporting code, but either way, since it will also change +the behaviour in terms of what version range of the stubs is supported, should also result in a +new major version of the compiler. + +However, vice versa is not necessarily true: a new major version of the compiler may not require +a new major version of the stubs. For example: +- Any breaking change to the compiler that has no changes in the stubs. +- The default value of a parameter has changed. This changes the meaning of existing code that + does not supply a default, thus requiring a major version bump of the compiler, but no + existing contracts will fail to compile. + +### Minor +When new functionality is added, the minor version should be bumped. + +Example situations: +- A new high level API has been added. +- A new parameter has been added to an existing method but a default value has been provided. +- A new TEAL/AVM version has been released with new low-level op-codes that should be exposed. + +In each of these cases, there should be zero impact on whether existing contracts will compile +or not. They all would also require a new compiler version to be released. Although the existing +compiler version could continue to work with new stubs version, provided none of the new +functionality is used, for simplicity the compiler should be updated to require the new stubs +version as a minimum. + +### Patch +When a bug in the stubs themselves is fixed, or a non-functional change is made (such as +changes to docstrings / documentation), the patch version should be bumped. + +Examples: +- Docstrings added/removed/updated. +- Type parameters that were incorrectly specified are fixed + ([concrete example](https://github.com/algorandfoundation/puya/issues/191)). +- Adding something that was unintentionally omitted from the stubs, but is otherwise supported by + the current compiler. + Generally in these cases, the code would compile if a `# type: ignore[]` was added + ([concrete example](https://github.com/algorandfoundation/puya/issues/200)). + +In each of these cases, the new stubs should functional correctly when paired with the current +release of the compiler. + +The second example is a slight break from semver principles, since this is not backwards +compatible, as existing contracts may fail to compile. However, those contracts should not have +compiled in the first place. The minimum version of stubs supported by the compiler should be +increased to this new patch release, however this will only take effect on the next release of the +compiler itself. The current compiler release would detect the new stubs version as supported +though, and so users can update to that new version of the stubs once it is released. diff --git a/stubs/algopy-stubs/itxn.pyi b/stubs/algopy-stubs/itxn.pyi index 153846ddf5..af14e120b2 100644 --- a/stubs/algopy-stubs/itxn.pyi +++ b/stubs/algopy-stubs/itxn.pyi @@ -114,6 +114,7 @@ class InnerTransaction(_InnerTransaction[InnerTransactionResult]): ## asset transfer xfer_asset: Asset | UInt64 | int = ..., asset_amount: UInt64 | int = ..., + asset_sender: Account | str = ..., asset_receiver: Account | str = ..., asset_close_to: Account | str = ..., ## asset freeze @@ -172,6 +173,7 @@ class InnerTransaction(_InnerTransaction[InnerTransactionResult]): ## asset transfer xfer_asset: Asset | UInt64 | int = ..., asset_amount: UInt64 | int = ..., + asset_sender: Account | str = ..., asset_receiver: Account | str = ..., asset_close_to: Account | str = ..., ## asset freeze @@ -316,6 +318,7 @@ class AssetTransfer(_InnerTransaction[AssetTransferInnerTransaction]): xfer_asset: Asset | UInt64 | int, asset_receiver: Account | str, asset_amount: UInt64 | int = ..., + asset_sender: Account | str = ..., asset_close_to: Account | str = ..., sender: Account | str = ..., fee: UInt64 | int = ..., @@ -327,6 +330,7 @@ class AssetTransfer(_InnerTransaction[AssetTransferInnerTransaction]): *, xfer_asset: Asset | UInt64 | int = ..., asset_amount: UInt64 | int = ..., + asset_sender: Account | str = ..., asset_receiver: Account | str = ..., asset_close_to: Account | str = ..., sender: Account | str = ..., diff --git a/stubs/pyproject.toml b/stubs/pyproject.toml index 3dd7786f26..fc06d8a3ae 100644 --- a/stubs/pyproject.toml +++ b/stubs/pyproject.toml @@ -1,8 +1,9 @@ [tool.poetry] name = "algorand-python" # this version represents the version of the stub API's and should follow semver semantics -# when updating this value also update src/compile.py:MAX_SUPPORTED_ALGOPY_VERSION -version = "1.0.1" +# when updating this value also update src/compile.py:MAX_SUPPORTED_ALGOPY_VERSION_EX if it is a major/minor change +# also see stubs/README.md#versioning +version = "1.0.2" description = "API for writing Algorand Python Smart contracts" authors = ["Algorand Foundation "] readme = "README.md" diff --git a/test_cases/inner_transactions/asset_transfer.py b/test_cases/inner_transactions/asset_transfer.py new file mode 100644 index 0000000000..06621695e3 --- /dev/null +++ b/test_cases/inner_transactions/asset_transfer.py @@ -0,0 +1,35 @@ +from algopy import ( + ARC4Contract, + Global, + arc4, + itxn, + op, +) + + +class CreateAndTransferContract(ARC4Contract): + @arc4.abimethod() + def create_and_transfer(self) -> None: + # create + new_asset = ( + itxn.AssetConfig( + total=1000, + asset_name="test", + unit_name="TST", + decimals=0, + manager=op.Global.current_application_address, + clawback=op.Global.current_application_address, + fee=0, + ) + .submit() + .created_asset + ) + + # transfer + itxn.AssetTransfer( + asset_sender=new_asset.creator, + asset_receiver=Global.current_application_address, + asset_amount=1000, + xfer_asset=new_asset, + fee=0, + ).submit() diff --git a/test_cases/inner_transactions/out/CreateAndTransferContract.approval.mir b/test_cases/inner_transactions/out/CreateAndTransferContract.approval.mir new file mode 100644 index 0000000000..cdfac5eac2 --- /dev/null +++ b/test_cases/inner_transactions/out/CreateAndTransferContract.approval.mir @@ -0,0 +1,108 @@ +// Op // Op Description Stack (out) X stack Source code Source line + +#pragma version 10 + +// test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program() -> uint64: +main_block@0: + txn NumAppArgs // {txn} class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: store tmp%0#0 to l-stack (no copy) tmp%0#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: load tmp%0#0 from l-stack (no copy) tmp%0#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + bz main_bare_routing@5 // class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // Implicit fall through to main_abi_routing@1 // class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + +main_abi_routing@1: + txna ApplicationArgs 0 // {txna} class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: store tmp%1#0 to l-stack (no copy) tmp%1#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + method "create_and_transfer()void" // tmp%1#0,method<"create_and_transfer()void"> class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + swap // load tmp%1#0 from l-stack (no copy) method<"create_and_transfer()void">,tmp%1#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + match main_create_and_transfer_route@2 // class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + err // reject transaction // class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + +main_create_and_transfer_route@2: + txn OnCompletion // {txn} arc4.abimethod() inner_transactions/asset_transfer.py:11 + // virtual: store tmp%2#0 to l-stack (no copy) tmp%2#0 arc4.abimethod() inner_transactions/asset_transfer.py:11 + // virtual: load tmp%2#0 from l-stack (no copy) tmp%2#0 arc4.abimethod() inner_transactions/asset_transfer.py:11 + ! // {!} arc4.abimethod() inner_transactions/asset_transfer.py:11 + // virtual: store tmp%3#0 to l-stack (no copy) tmp%3#0 arc4.abimethod() inner_transactions/asset_transfer.py:11 + // virtual: load tmp%3#0 from l-stack (no copy) tmp%3#0 arc4.abimethod() inner_transactions/asset_transfer.py:11 + assert // OnCompletion is NoOp // arc4.abimethod() inner_transactions/asset_transfer.py:11 + txn ApplicationID // {txn} arc4.abimethod() inner_transactions/asset_transfer.py:11 + // virtual: store tmp%4#0 to l-stack (no copy) tmp%4#0 arc4.abimethod() inner_transactions/asset_transfer.py:11 + // virtual: load tmp%4#0 from l-stack (no copy) tmp%4#0 arc4.abimethod() inner_transactions/asset_transfer.py:11 + assert // is not creating // arc4.abimethod() inner_transactions/asset_transfer.py:11 + callsub create_and_transfer // arc4.abimethod() inner_transactions/asset_transfer.py:11 + int 1 // 1 arc4.abimethod() inner_transactions/asset_transfer.py:11 + return // arc4.abimethod() inner_transactions/asset_transfer.py:11 + +main_bare_routing@5: + txn OnCompletion // {txn} class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: store tmp%5#0 to l-stack (no copy) tmp%5#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: load tmp%5#0 from l-stack (no copy) tmp%5#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + ! // {!} class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: store not%tmp%5#0 to l-stack (no copy) not%tmp%5#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: load not%tmp%5#0 from l-stack (no copy) not%tmp%5#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + assert // reject transaction // class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + txn ApplicationID // {txn} class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: store tmp%6#0 to l-stack (no copy) tmp%6#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: load tmp%6#0 from l-stack (no copy) tmp%6#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + ! // {!} class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: store tmp%7#0 to l-stack (no copy) tmp%7#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + // virtual: load tmp%7#0 from l-stack (no copy) tmp%7#0 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + assert // is creating // class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + int 1 // 1 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + return // class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + + +// test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() -> void: +create_and_transfer: + proto 0 0 // @arc4.abimethod()\ndef create_and_transfer(self) -> None: inner_transactions/asset_transfer.py:11-12 + +create_and_transfer_block@0: + itxn_begin // itxn.AssetConfig(\ntotal=1000,\nasset_name="test",\nunit_name="TST",\ndecimals=0,\nmanager=op.Glo... inner_transactions/asset_transfer.py:15-24 + global CurrentApplicationAddress // {global} op.Global.current_application_address inner_transactions/asset_transfer.py:20 + // virtual: store inner_txn_params%0%%param_ConfigAssetManager_idx_0#0 to l-stack (no copy) inner_txn_params%0%%param_ConfigAssetManager_idx_0#0 op.Global.current_application_address inner_transactions/asset_transfer.py:20 + global CurrentApplicationAddress // inner_txn_params%0%%param_ConfigAssetManager_idx_0#0,{global} op.Global.current_application_address inner_transactions/asset_transfer.py:21 + // virtual: store inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0 to l-stack (no copy) inner_txn_params%0%%param_ConfigAssetManager_idx_0#0,inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0 op.Global.current_application_address inner_transactions/asset_transfer.py:21 + int 0 // inner_txn_params%0%%param_ConfigAssetManager_idx_0#0,inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0,0 0 inner_transactions/asset_transfer.py:22 + itxn_field Fee // inner_txn_params%0%%param_ConfigAssetManager_idx_0#0,inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0 + // virtual: load inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0 from l-stack (no copy) inner_txn_params%0%%param_ConfigAssetManager_idx_0#0,inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0 + itxn_field ConfigAssetClawback // inner_txn_params%0%%param_ConfigAssetManager_idx_0#0 + // virtual: load inner_txn_params%0%%param_ConfigAssetManager_idx_0#0 from l-stack (no copy) inner_txn_params%0%%param_ConfigAssetManager_idx_0#0 + itxn_field ConfigAssetManager // + int 0 // 0 0 inner_transactions/asset_transfer.py:19 + itxn_field ConfigAssetDecimals // + byte "TST" // "TST" "TST" inner_transactions/asset_transfer.py:18 + itxn_field ConfigAssetUnitName // + byte "test" // "test" "test" inner_transactions/asset_transfer.py:17 + itxn_field ConfigAssetName // + int 1000 // 1000 1000 inner_transactions/asset_transfer.py:16 + itxn_field ConfigAssetTotal // + int acfg // acfg itxn.AssetConfig inner_transactions/asset_transfer.py:15 + itxn_field TypeEnum // + itxn_submit // itxn.AssetConfig(\ntotal=1000,\nasset_name="test",\nunit_name="TST",\ndecimals=0,\nmanager=op.Glo... inner_transactions/asset_transfer.py:15-24 + itxn CreatedAssetID // {itxn} itxn.AssetConfig(\ntotal=1000,\nasset_name="test",\nunit_name="TST",\ndecimals=0,\nmanager=op.Glo... inner_transactions/asset_transfer.py:15-25 + // virtual: store new_asset#0 to l-stack (no copy) new_asset#0 # create\nnew_asset = (\nitxn.AssetConfig(\ntotal=1000,\nasset_name="test",\nunit_name="TST",\nde... inner_transactions/asset_transfer.py:13-26 + itxn_begin // new_asset#0 # transfer\nitxn.AssetTransfer(\nasset_sender=new_asset.creator,\nasset_receiver=Global.current_a... inner_transactions/asset_transfer.py:28-35 + dup // load new_asset#0 from l-stack (copy) new_asset#0,new_asset#0 new_asset.creator inner_transactions/asset_transfer.py:30 + asset_params_get AssetCreator // new_asset#0,{asset_params_get}.0,{asset_params_get}.1 new_asset.creator inner_transactions/asset_transfer.py:30 + swap // store check%0#0 to l-stack (no copy) new_asset#0,check%0#0,{asset_params_get}.0 new_asset.creator inner_transactions/asset_transfer.py:30 + cover 2 // store value%0#0 to l-stack (no copy) value%0#0,new_asset#0,check%0#0 new_asset.creator inner_transactions/asset_transfer.py:30 + // virtual: load check%0#0 from l-stack (no copy) value%0#0,new_asset#0,check%0#0 new_asset.creator inner_transactions/asset_transfer.py:30 + assert // asset exists // value%0#0,new_asset#0 new_asset.creator inner_transactions/asset_transfer.py:30 + global CurrentApplicationAddress // value%0#0,new_asset#0,{global} Global.current_application_address inner_transactions/asset_transfer.py:31 + // virtual: store inner_txn_params%1%%param_AssetReceiver_idx_0#0 to l-stack (no copy) value%0#0,new_asset#0,inner_txn_params%1%%param_AssetReceiver_idx_0#0 Global.current_application_address inner_transactions/asset_transfer.py:31 + int 0 // value%0#0,new_asset#0,inner_txn_params%1%%param_AssetReceiver_idx_0#0,0 0 inner_transactions/asset_transfer.py:34 + itxn_field Fee // value%0#0,new_asset#0,inner_txn_params%1%%param_AssetReceiver_idx_0#0 + swap // load new_asset#0 from l-stack (no copy) value%0#0,inner_txn_params%1%%param_AssetReceiver_idx_0#0,new_asset#0 + itxn_field XferAsset // value%0#0,inner_txn_params%1%%param_AssetReceiver_idx_0#0 + int 1000 // value%0#0,inner_txn_params%1%%param_AssetReceiver_idx_0#0,1000 1000 inner_transactions/asset_transfer.py:32 + itxn_field AssetAmount // value%0#0,inner_txn_params%1%%param_AssetReceiver_idx_0#0 + // virtual: load inner_txn_params%1%%param_AssetReceiver_idx_0#0 from l-stack (no copy) value%0#0,inner_txn_params%1%%param_AssetReceiver_idx_0#0 + itxn_field AssetReceiver // value%0#0 + // virtual: load value%0#0 from l-stack (no copy) value%0#0 + itxn_field AssetSender // + int axfer // axfer # transfer\nitxn.AssetTransfer inner_transactions/asset_transfer.py:28-29 + itxn_field TypeEnum // + itxn_submit // # transfer\nitxn.AssetTransfer(\nasset_sender=new_asset.creator,\nasset_receiver=Global.current_a... inner_transactions/asset_transfer.py:28-35 + retsub // + diff --git a/test_cases/inner_transactions/out/CreateAndTransferContract.approval.teal b/test_cases/inner_transactions/out/CreateAndTransferContract.approval.teal new file mode 100644 index 0000000000..ee0887bb5c --- /dev/null +++ b/test_cases/inner_transactions/out/CreateAndTransferContract.approval.teal @@ -0,0 +1,160 @@ +#pragma version 10 + +test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program: + // inner_transactions/asset_transfer.py:10 + // class CreateAndTransferContract(ARC4Contract): + txn NumAppArgs + bz main_bare_routing@5 + method "create_and_transfer()void" + txna ApplicationArgs 0 + match main_create_and_transfer_route@2 + err // reject transaction + +main_create_and_transfer_route@2: + // inner_transactions/asset_transfer.py:11 + // @arc4.abimethod() + txn OnCompletion + ! + assert // OnCompletion is NoOp + txn ApplicationID + assert // is not creating + callsub create_and_transfer + int 1 + return + +main_bare_routing@5: + // inner_transactions/asset_transfer.py:10 + // class CreateAndTransferContract(ARC4Contract): + txn OnCompletion + ! + assert // reject transaction + txn ApplicationID + ! + assert // is creating + int 1 + return + + +// test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() -> void: +create_and_transfer: + // inner_transactions/asset_transfer.py:11-12 + // @arc4.abimethod() + // def create_and_transfer(self) -> None: + proto 0 0 + // inner_transactions/asset_transfer.py:15-24 + // itxn.AssetConfig( + // total=1000, + // asset_name="test", + // unit_name="TST", + // decimals=0, + // manager=op.Global.current_application_address, + // clawback=op.Global.current_application_address, + // fee=0, + // ) + // .submit() + itxn_begin + // inner_transactions/asset_transfer.py:20 + // manager=op.Global.current_application_address, + global CurrentApplicationAddress + // inner_transactions/asset_transfer.py:21 + // clawback=op.Global.current_application_address, + dup + // inner_transactions/asset_transfer.py:22 + // fee=0, + int 0 + itxn_field Fee + itxn_field ConfigAssetClawback + itxn_field ConfigAssetManager + // inner_transactions/asset_transfer.py:19 + // decimals=0, + int 0 + itxn_field ConfigAssetDecimals + // inner_transactions/asset_transfer.py:18 + // unit_name="TST", + byte "TST" + itxn_field ConfigAssetUnitName + // inner_transactions/asset_transfer.py:17 + // asset_name="test", + byte "test" + itxn_field ConfigAssetName + // inner_transactions/asset_transfer.py:16 + // total=1000, + int 1000 + itxn_field ConfigAssetTotal + // inner_transactions/asset_transfer.py:15 + // itxn.AssetConfig( + int acfg + itxn_field TypeEnum + // inner_transactions/asset_transfer.py:15-24 + // itxn.AssetConfig( + // total=1000, + // asset_name="test", + // unit_name="TST", + // decimals=0, + // manager=op.Global.current_application_address, + // clawback=op.Global.current_application_address, + // fee=0, + // ) + // .submit() + itxn_submit + // inner_transactions/asset_transfer.py:15-25 + // itxn.AssetConfig( + // total=1000, + // asset_name="test", + // unit_name="TST", + // decimals=0, + // manager=op.Global.current_application_address, + // clawback=op.Global.current_application_address, + // fee=0, + // ) + // .submit() + // .created_asset + itxn CreatedAssetID + // inner_transactions/asset_transfer.py:28-35 + // # transfer + // itxn.AssetTransfer( + // asset_sender=new_asset.creator, + // asset_receiver=Global.current_application_address, + // asset_amount=1000, + // xfer_asset=new_asset, + // fee=0, + // ).submit() + itxn_begin + // inner_transactions/asset_transfer.py:30 + // asset_sender=new_asset.creator, + dup + asset_params_get AssetCreator + swap + cover 2 + assert // asset exists + // inner_transactions/asset_transfer.py:31 + // asset_receiver=Global.current_application_address, + global CurrentApplicationAddress + // inner_transactions/asset_transfer.py:34 + // fee=0, + int 0 + itxn_field Fee + swap + itxn_field XferAsset + // inner_transactions/asset_transfer.py:32 + // asset_amount=1000, + int 1000 + itxn_field AssetAmount + itxn_field AssetReceiver + itxn_field AssetSender + // inner_transactions/asset_transfer.py:28-29 + // # transfer + // itxn.AssetTransfer( + int axfer + itxn_field TypeEnum + // inner_transactions/asset_transfer.py:28-35 + // # transfer + // itxn.AssetTransfer( + // asset_sender=new_asset.creator, + // asset_receiver=Global.current_application_address, + // asset_amount=1000, + // xfer_asset=new_asset, + // fee=0, + // ).submit() + itxn_submit + retsub diff --git a/test_cases/inner_transactions/out/CreateAndTransferContract.arc32.json b/test_cases/inner_transactions/out/CreateAndTransferContract.arc32.json new file mode 100644 index 0000000000..429c052f44 --- /dev/null +++ b/test_cases/inner_transactions/out/CreateAndTransferContract.arc32.json @@ -0,0 +1,49 @@ +{ + "hints": { + "create_and_transfer()void": { + "call_config": { + "no_op": "CALL" + } + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgp0ZXN0X2Nhc2VzLmlubmVyX3RyYW5zYWN0aW9ucy5hc3NldF90cmFuc2Zlci5DcmVhdGVBbmRUcmFuc2ZlckNvbnRyYWN0LmFwcHJvdmFsX3Byb2dyYW06CiAgICAvLyBpbm5lcl90cmFuc2FjdGlvbnMvYXNzZXRfdHJhbnNmZXIucHk6MTAKICAgIC8vIGNsYXNzIENyZWF0ZUFuZFRyYW5zZmVyQ29udHJhY3QoQVJDNENvbnRyYWN0KToKICAgIHR4biBOdW1BcHBBcmdzCiAgICBieiBtYWluX2JhcmVfcm91dGluZ0A1CiAgICBtZXRob2QgImNyZWF0ZV9hbmRfdHJhbnNmZXIoKXZvaWQiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBtYWluX2NyZWF0ZV9hbmRfdHJhbnNmZXJfcm91dGVAMgogICAgZXJyIC8vIHJlamVjdCB0cmFuc2FjdGlvbgoKbWFpbl9jcmVhdGVfYW5kX3RyYW5zZmVyX3JvdXRlQDI6CiAgICAvLyBpbm5lcl90cmFuc2FjdGlvbnMvYXNzZXRfdHJhbnNmZXIucHk6MTEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICBjYWxsc3ViIGNyZWF0ZV9hbmRfdHJhbnNmZXIKICAgIGludCAxCiAgICByZXR1cm4KCm1haW5fYmFyZV9yb3V0aW5nQDU6CiAgICAvLyBpbm5lcl90cmFuc2FjdGlvbnMvYXNzZXRfdHJhbnNmZXIucHk6MTAKICAgIC8vIGNsYXNzIENyZWF0ZUFuZFRyYW5zZmVyQ29udHJhY3QoQVJDNENvbnRyYWN0KToKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyByZWplY3QgdHJhbnNhY3Rpb24KICAgIHR4biBBcHBsaWNhdGlvbklECiAgICAhCiAgICBhc3NlcnQgLy8gaXMgY3JlYXRpbmcKICAgIGludCAxCiAgICByZXR1cm4KCgovLyB0ZXN0X2Nhc2VzLmlubmVyX3RyYW5zYWN0aW9ucy5hc3NldF90cmFuc2Zlci5DcmVhdGVBbmRUcmFuc2ZlckNvbnRyYWN0LmNyZWF0ZV9hbmRfdHJhbnNmZXIoKSAtPiB2b2lkOgpjcmVhdGVfYW5kX3RyYW5zZmVyOgogICAgLy8gaW5uZXJfdHJhbnNhY3Rpb25zL2Fzc2V0X3RyYW5zZmVyLnB5OjExLTEyCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gZGVmIGNyZWF0ZV9hbmRfdHJhbnNmZXIoc2VsZikgLT4gTm9uZToKICAgIHByb3RvIDAgMAogICAgLy8gaW5uZXJfdHJhbnNhY3Rpb25zL2Fzc2V0X3RyYW5zZmVyLnB5OjE1LTI0CiAgICAvLyBpdHhuLkFzc2V0Q29uZmlnKAogICAgLy8gICAgIHRvdGFsPTEwMDAsCiAgICAvLyAgICAgYXNzZXRfbmFtZT0idGVzdCIsCiAgICAvLyAgICAgdW5pdF9uYW1lPSJUU1QiLAogICAgLy8gICAgIGRlY2ltYWxzPTAsCiAgICAvLyAgICAgbWFuYWdlcj1vcC5HbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgIGNsYXdiYWNrPW9wLkdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgZmVlPTAsCiAgICAvLyApCiAgICAvLyAuc3VibWl0KCkKICAgIGl0eG5fYmVnaW4KICAgIC8vIGlubmVyX3RyYW5zYWN0aW9ucy9hc3NldF90cmFuc2Zlci5weToyMAogICAgLy8gbWFuYWdlcj1vcC5HbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgIC8vIGlubmVyX3RyYW5zYWN0aW9ucy9hc3NldF90cmFuc2Zlci5weToyMQogICAgLy8gY2xhd2JhY2s9b3AuR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIGR1cAogICAgLy8gaW5uZXJfdHJhbnNhY3Rpb25zL2Fzc2V0X3RyYW5zZmVyLnB5OjIyCiAgICAvLyBmZWU9MCwKICAgIGludCAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgaXR4bl9maWVsZCBDb25maWdBc3NldENsYXdiYWNrCiAgICBpdHhuX2ZpZWxkIENvbmZpZ0Fzc2V0TWFuYWdlcgogICAgLy8gaW5uZXJfdHJhbnNhY3Rpb25zL2Fzc2V0X3RyYW5zZmVyLnB5OjE5CiAgICAvLyBkZWNpbWFscz0wLAogICAgaW50IDAKICAgIGl0eG5fZmllbGQgQ29uZmlnQXNzZXREZWNpbWFscwogICAgLy8gaW5uZXJfdHJhbnNhY3Rpb25zL2Fzc2V0X3RyYW5zZmVyLnB5OjE4CiAgICAvLyB1bml0X25hbWU9IlRTVCIsCiAgICBieXRlICJUU1QiCiAgICBpdHhuX2ZpZWxkIENvbmZpZ0Fzc2V0VW5pdE5hbWUKICAgIC8vIGlubmVyX3RyYW5zYWN0aW9ucy9hc3NldF90cmFuc2Zlci5weToxNwogICAgLy8gYXNzZXRfbmFtZT0idGVzdCIsCiAgICBieXRlICJ0ZXN0IgogICAgaXR4bl9maWVsZCBDb25maWdBc3NldE5hbWUKICAgIC8vIGlubmVyX3RyYW5zYWN0aW9ucy9hc3NldF90cmFuc2Zlci5weToxNgogICAgLy8gdG90YWw9MTAwMCwKICAgIGludCAxMDAwCiAgICBpdHhuX2ZpZWxkIENvbmZpZ0Fzc2V0VG90YWwKICAgIC8vIGlubmVyX3RyYW5zYWN0aW9ucy9hc3NldF90cmFuc2Zlci5weToxNQogICAgLy8gaXR4bi5Bc3NldENvbmZpZygKICAgIGludCBhY2ZnCiAgICBpdHhuX2ZpZWxkIFR5cGVFbnVtCiAgICAvLyBpbm5lcl90cmFuc2FjdGlvbnMvYXNzZXRfdHJhbnNmZXIucHk6MTUtMjQKICAgIC8vIGl0eG4uQXNzZXRDb25maWcoCiAgICAvLyAgICAgdG90YWw9MTAwMCwKICAgIC8vICAgICBhc3NldF9uYW1lPSJ0ZXN0IiwKICAgIC8vICAgICB1bml0X25hbWU9IlRTVCIsCiAgICAvLyAgICAgZGVjaW1hbHM9MCwKICAgIC8vICAgICBtYW5hZ2VyPW9wLkdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgY2xhd2JhY2s9b3AuR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBmZWU9MCwKICAgIC8vICkKICAgIC8vIC5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIC8vIGlubmVyX3RyYW5zYWN0aW9ucy9hc3NldF90cmFuc2Zlci5weToxNS0yNQogICAgLy8gaXR4bi5Bc3NldENvbmZpZygKICAgIC8vICAgICB0b3RhbD0xMDAwLAogICAgLy8gICAgIGFzc2V0X25hbWU9InRlc3QiLAogICAgLy8gICAgIHVuaXRfbmFtZT0iVFNUIiwKICAgIC8vICAgICBkZWNpbWFscz0wLAogICAgLy8gICAgIG1hbmFnZXI9b3AuR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBjbGF3YmFjaz1vcC5HbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgIGZlZT0wLAogICAgLy8gKQogICAgLy8gLnN1Ym1pdCgpCiAgICAvLyAuY3JlYXRlZF9hc3NldAogICAgaXR4biBDcmVhdGVkQXNzZXRJRAogICAgLy8gaW5uZXJfdHJhbnNhY3Rpb25zL2Fzc2V0X3RyYW5zZmVyLnB5OjI4LTM1CiAgICAvLyAjIHRyYW5zZmVyCiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICAvLyAgICAgYXNzZXRfc2VuZGVyPW5ld19hc3NldC5jcmVhdG9yLAogICAgLy8gICAgIGFzc2V0X3JlY2VpdmVyPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgYXNzZXRfYW1vdW50PTEwMDAsCiAgICAvLyAgICAgeGZlcl9hc3NldD1uZXdfYXNzZXQsCiAgICAvLyAgICAgZmVlPTAsCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBpbm5lcl90cmFuc2FjdGlvbnMvYXNzZXRfdHJhbnNmZXIucHk6MzAKICAgIC8vIGFzc2V0X3NlbmRlcj1uZXdfYXNzZXQuY3JlYXRvciwKICAgIGR1cAogICAgYXNzZXRfcGFyYW1zX2dldCBBc3NldENyZWF0b3IKICAgIHN3YXAKICAgIGNvdmVyIDIKICAgIGFzc2VydCAvLyBhc3NldCBleGlzdHMKICAgIC8vIGlubmVyX3RyYW5zYWN0aW9ucy9hc3NldF90cmFuc2Zlci5weTozMQogICAgLy8gYXNzZXRfcmVjZWl2ZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCiAgICAvLyBpbm5lcl90cmFuc2FjdGlvbnMvYXNzZXRfdHJhbnNmZXIucHk6MzQKICAgIC8vIGZlZT0wLAogICAgaW50IDAKICAgIGl0eG5fZmllbGQgRmVlCiAgICBzd2FwCiAgICBpdHhuX2ZpZWxkIFhmZXJBc3NldAogICAgLy8gaW5uZXJfdHJhbnNhY3Rpb25zL2Fzc2V0X3RyYW5zZmVyLnB5OjMyCiAgICAvLyBhc3NldF9hbW91bnQ9MTAwMCwKICAgIGludCAxMDAwCiAgICBpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CiAgICBpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKICAgIGl0eG5fZmllbGQgQXNzZXRTZW5kZXIKICAgIC8vIGlubmVyX3RyYW5zYWN0aW9ucy9hc3NldF90cmFuc2Zlci5weToyOC0yOQogICAgLy8gIyB0cmFuc2ZlcgogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgaW50IGF4ZmVyCiAgICBpdHhuX2ZpZWxkIFR5cGVFbnVtCiAgICAvLyBpbm5lcl90cmFuc2FjdGlvbnMvYXNzZXRfdHJhbnNmZXIucHk6MjgtMzUKICAgIC8vICMgdHJhbnNmZXIKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICAgICBhc3NldF9zZW5kZXI9bmV3X2Fzc2V0LmNyZWF0b3IsCiAgICAvLyAgICAgYXNzZXRfcmVjZWl2ZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBhc3NldF9hbW91bnQ9MTAwMCwKICAgIC8vICAgICB4ZmVyX2Fzc2V0PW5ld19hc3NldCwKICAgIC8vICAgICBmZWU9MCwKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fc3VibWl0CiAgICByZXRzdWIK", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgp0ZXN0X2Nhc2VzLmlubmVyX3RyYW5zYWN0aW9ucy5hc3NldF90cmFuc2Zlci5DcmVhdGVBbmRUcmFuc2ZlckNvbnRyYWN0LmNsZWFyX3N0YXRlX3Byb2dyYW06CiAgICAvLyBpbm5lcl90cmFuc2FjdGlvbnMvYXNzZXRfdHJhbnNmZXIucHk6MTAKICAgIC8vIGNsYXNzIENyZWF0ZUFuZFRyYW5zZmVyQ29udHJhY3QoQVJDNENvbnRyYWN0KToKICAgIGludCAxCiAgICByZXR1cm4K" + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "schema": { + "global": { + "declared": {}, + "reserved": {} + }, + "local": { + "declared": {}, + "reserved": {} + } + }, + "contract": { + "name": "CreateAndTransferContract", + "methods": [ + { + "name": "create_and_transfer", + "args": [], + "returns": { + "type": "void" + } + } + ], + "networks": {} + }, + "bare_call_config": { + "no_op": "CREATE" + } +} \ No newline at end of file diff --git a/test_cases/inner_transactions/out/CreateAndTransferContract.clear.mir b/test_cases/inner_transactions/out/CreateAndTransferContract.clear.mir new file mode 100644 index 0000000000..62cf7c7e7c --- /dev/null +++ b/test_cases/inner_transactions/out/CreateAndTransferContract.clear.mir @@ -0,0 +1,9 @@ +// Op // Stack (out) Source code Source line + +#pragma version 10 + +// test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program() -> uint64: +main_block@0: + int 1 // 1 class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + return // class CreateAndTransferContract(ARC4Contract): inner_transactions/asset_transfer.py:10 + diff --git a/test_cases/inner_transactions/out/CreateAndTransferContract.clear.teal b/test_cases/inner_transactions/out/CreateAndTransferContract.clear.teal new file mode 100644 index 0000000000..3d8eb0eacd --- /dev/null +++ b/test_cases/inner_transactions/out/CreateAndTransferContract.clear.teal @@ -0,0 +1,7 @@ +#pragma version 10 + +test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program: + // inner_transactions/asset_transfer.py:10 + // class CreateAndTransferContract(ARC4Contract): + int 1 + return diff --git a/test_cases/inner_transactions/out/CreateAndTransferContract.destructured.ir b/test_cases/inner_transactions/out/CreateAndTransferContract.destructured.ir new file mode 100644 index 0000000000..43b41f8419 --- /dev/null +++ b/test_cases/inner_transactions/out/CreateAndTransferContract.destructured.ir @@ -0,0 +1,58 @@ +contract test_cases.inner_transactions.asset_transfer.CreateAndTransferContract: + program approval: + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program() -> bool: + block@0: // L10 + let tmp%0#0: bool = (txn NumAppArgs) + goto tmp%0#0 ? block@1 : block@5 + block@1: // abi_routing_L10 + let tmp%1#0: bytes = (txna ApplicationArgs 0) + switch tmp%1#0 {method "create_and_transfer()void" => block@2, * => fail // reject transaction} + block@2: // create_and_transfer_route_L11 + let tmp%2#0: uint64 = (txn OnCompletion) + let tmp%3#0: bool = (! tmp%2#0) + (assert tmp%3#0) // OnCompletion is NoOp + let tmp%4#0: bool = (txn ApplicationID) + (assert tmp%4#0) // is not creating + test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() + return 1u + block@5: // bare_routing_L10 + let tmp%5#0: uint64 = (txn OnCompletion) + let not%tmp%5#0: bool = (! tmp%5#0) + (assert not%tmp%5#0) // reject transaction + let tmp%6#0: bool = (txn ApplicationID) + let tmp%7#0: bool = (! tmp%6#0) + (assert tmp%7#0) // is creating + return 1u + + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() -> void: + block@0: // L11 + itxn_begin + let inner_txn_params%0%%param_ConfigAssetManager_idx_0#0: bytes = (global CurrentApplicationAddress) + let inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0: bytes = (global CurrentApplicationAddress) + ((itxn_field Fee) 0u) + ((itxn_field ConfigAssetClawback) inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0) + ((itxn_field ConfigAssetManager) inner_txn_params%0%%param_ConfigAssetManager_idx_0#0) + ((itxn_field ConfigAssetDecimals) 0u) + ((itxn_field ConfigAssetUnitName) "TST") + ((itxn_field ConfigAssetName) "test") + ((itxn_field ConfigAssetTotal) 1000u) + ((itxn_field TypeEnum) acfg) + itxn_submit + let new_asset#0: uint64 = (itxn CreatedAssetID) + itxn_begin + let (value%0#0: bytes, check%0#0: bool) = ((asset_params_get AssetCreator) new_asset#0) + (assert check%0#0) // asset exists + let inner_txn_params%1%%param_AssetReceiver_idx_0#0: bytes = (global CurrentApplicationAddress) + ((itxn_field Fee) 0u) + ((itxn_field XferAsset) new_asset#0) + ((itxn_field AssetAmount) 1000u) + ((itxn_field AssetReceiver) inner_txn_params%1%%param_AssetReceiver_idx_0#0) + ((itxn_field AssetSender) value%0#0) + ((itxn_field TypeEnum) axfer) + itxn_submit + return + + program clear-state: + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program() -> bool: + block@0: // L10 + return 1u \ No newline at end of file diff --git a/test_cases/inner_transactions/out/CreateAndTransferContract.ssa.ir b/test_cases/inner_transactions/out/CreateAndTransferContract.ssa.ir new file mode 100644 index 0000000000..71c411aba1 --- /dev/null +++ b/test_cases/inner_transactions/out/CreateAndTransferContract.ssa.ir @@ -0,0 +1,183 @@ +contract test_cases.inner_transactions.asset_transfer.CreateAndTransferContract: + program approval: + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program() -> bool: + block@0: // L10 + let tmp%0#0: bool = (txn NumAppArgs) + goto tmp%0#0 ? block@1 : block@5 + block@1: // abi_routing_L10 + let tmp%1#0: bytes = (txna ApplicationArgs 0) + switch tmp%1#0 {method "create_and_transfer()void" => block@2, * => block@3} + block@2: // create_and_transfer_route_L11 + let tmp%2#0: uint64 = (txn OnCompletion) + let tmp%3#0: bool = (== tmp%2#0 NoOp) + (assert tmp%3#0) // OnCompletion is NoOp + let tmp%4#0: bool = (txn ApplicationID) + (assert tmp%4#0) // is not creating + test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() + return 1u + block@3: // switch_case_default_L10 + goto block@4 + block@4: // switch_case_next_L10 + fail // reject transaction + block@5: // bare_routing_L10 + let tmp%5#0: uint64 = (txn OnCompletion) + switch tmp%5#0 {0u => block@6, * => block@7} + block@6: // create_L10 + let tmp%6#0: bool = (txn ApplicationID) + let tmp%7#0: bool = (! tmp%6#0) + (assert tmp%7#0) // is creating + return 1u + block@7: // reject_bare_on_completion_L10 + fail // reject transaction + + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() -> void: + block@0: // L11 + itxn_begin + let inner_txn_params%0#0: itxn_field_set = itxn_field_set(0) + let inner_txn_params%0%%param_TypeEnum_idx_0#0: uint64 = acfg + let inner_txn_params%0%%TypeEnum_length#0: uint64 = 1u + let inner_txn_params%0%%param_ConfigAssetTotal_idx_0#0: uint64 = 1000u + let inner_txn_params%0%%ConfigAssetTotal_length#0: uint64 = 1u + let inner_txn_params%0%%param_ConfigAssetName_idx_0#0: bytes = "test" + let inner_txn_params%0%%ConfigAssetName_length#0: uint64 = 1u + let inner_txn_params%0%%param_ConfigAssetUnitName_idx_0#0: bytes = "TST" + let inner_txn_params%0%%ConfigAssetUnitName_length#0: uint64 = 1u + let inner_txn_params%0%%param_ConfigAssetDecimals_idx_0#0: uint64 = 0u + let inner_txn_params%0%%ConfigAssetDecimals_length#0: uint64 = 1u + let inner_txn_params%0%%param_ConfigAssetManager_idx_0#0: bytes = (global CurrentApplicationAddress) + let inner_txn_params%0%%ConfigAssetManager_length#0: uint64 = 1u + let inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0: bytes = (global CurrentApplicationAddress) + let inner_txn_params%0%%ConfigAssetClawback_length#0: uint64 = 1u + let inner_txn_params%0%%param_Fee_idx_0#0: uint64 = 0u + let inner_txn_params%0%%Fee_length#0: uint64 = 1u + let inner_txn_params%0%%Sender_length#0: uint64 = 0u + let inner_txn_params%0%%Note_length#0: uint64 = 0u + let inner_txn_params%0%%Receiver_length#0: uint64 = 0u + let inner_txn_params%0%%Amount_length#0: uint64 = 0u + let inner_txn_params%0%%CloseRemainderTo_length#0: uint64 = 0u + let inner_txn_params%0%%VotePK_length#0: uint64 = 0u + let inner_txn_params%0%%SelectionPK_length#0: uint64 = 0u + let inner_txn_params%0%%VoteFirst_length#0: uint64 = 0u + let inner_txn_params%0%%VoteLast_length#0: uint64 = 0u + let inner_txn_params%0%%VoteKeyDilution_length#0: uint64 = 0u + let inner_txn_params%0%%Type_length#0: uint64 = 0u + let inner_txn_params%0%%XferAsset_length#0: uint64 = 0u + let inner_txn_params%0%%AssetAmount_length#0: uint64 = 0u + let inner_txn_params%0%%AssetSender_length#0: uint64 = 0u + let inner_txn_params%0%%AssetReceiver_length#0: uint64 = 0u + let inner_txn_params%0%%AssetCloseTo_length#0: uint64 = 0u + let inner_txn_params%0%%ApplicationID_length#0: uint64 = 0u + let inner_txn_params%0%%OnCompletion_length#0: uint64 = 0u + let inner_txn_params%0%%ApprovalProgram_length#0: uint64 = 0u + let inner_txn_params%0%%ClearStateProgram_length#0: uint64 = 0u + let inner_txn_params%0%%RekeyTo_length#0: uint64 = 0u + let inner_txn_params%0%%ConfigAsset_length#0: uint64 = 0u + let inner_txn_params%0%%ConfigAssetDefaultFrozen_length#0: uint64 = 0u + let inner_txn_params%0%%ConfigAssetURL_length#0: uint64 = 0u + let inner_txn_params%0%%ConfigAssetMetadataHash_length#0: uint64 = 0u + let inner_txn_params%0%%ConfigAssetReserve_length#0: uint64 = 0u + let inner_txn_params%0%%ConfigAssetFreeze_length#0: uint64 = 0u + let inner_txn_params%0%%FreezeAsset_length#0: uint64 = 0u + let inner_txn_params%0%%FreezeAssetAccount_length#0: uint64 = 0u + let inner_txn_params%0%%FreezeAssetFrozen_length#0: uint64 = 0u + let inner_txn_params%0%%GlobalNumUint_length#0: uint64 = 0u + let inner_txn_params%0%%GlobalNumByteSlice_length#0: uint64 = 0u + let inner_txn_params%0%%LocalNumUint_length#0: uint64 = 0u + let inner_txn_params%0%%LocalNumByteSlice_length#0: uint64 = 0u + let inner_txn_params%0%%ExtraProgramPages_length#0: uint64 = 0u + let inner_txn_params%0%%Nonparticipation_length#0: uint64 = 0u + let inner_txn_params%0%%StateProofPK_length#0: uint64 = 0u + let inner_txn_params%0%%ApplicationArgs_length#0: uint64 = 0u + let inner_txn_params%0%%Accounts_length#0: uint64 = 0u + let inner_txn_params%0%%Assets_length#0: uint64 = 0u + let inner_txn_params%0%%Applications_length#0: uint64 = 0u + let inner_txn_params%0%%ApprovalProgramPages_length#0: uint64 = 0u + let inner_txn_params%0%%ClearStateProgramPages_length#0: uint64 = 0u + ((itxn_field Fee) inner_txn_params%0%%param_Fee_idx_0#0) + ((itxn_field ConfigAssetClawback) inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0) + ((itxn_field ConfigAssetManager) inner_txn_params%0%%param_ConfigAssetManager_idx_0#0) + ((itxn_field ConfigAssetDecimals) inner_txn_params%0%%param_ConfigAssetDecimals_idx_0#0) + ((itxn_field ConfigAssetUnitName) inner_txn_params%0%%param_ConfigAssetUnitName_idx_0#0) + ((itxn_field ConfigAssetName) inner_txn_params%0%%param_ConfigAssetName_idx_0#0) + ((itxn_field ConfigAssetTotal) inner_txn_params%0%%param_ConfigAssetTotal_idx_0#0) + ((itxn_field TypeEnum) inner_txn_params%0%%param_TypeEnum_idx_0#0) + goto block@1 + block@1: // next_txn_L15 + itxn_submit + let new_asset#0: uint64 = itxn[itxn_group_idx(0)].CreatedAssetID + itxn_begin + let inner_txn_params%1#0: itxn_field_set = itxn_field_set(1) + let inner_txn_params%1%%param_TypeEnum_idx_0#0: uint64 = axfer + let inner_txn_params%1%%TypeEnum_length#0: uint64 = 1u + let (value%0#0: bytes, check%0#0: bool) = ((asset_params_get AssetCreator) new_asset#0) + (assert check%0#0) // asset exists + let inner_txn_params%1%%param_AssetSender_idx_0#0: bytes = value%0#0 + let inner_txn_params%1%%AssetSender_length#0: uint64 = 1u + let inner_txn_params%1%%param_AssetReceiver_idx_0#0: bytes = (global CurrentApplicationAddress) + let inner_txn_params%1%%AssetReceiver_length#0: uint64 = 1u + let inner_txn_params%1%%param_AssetAmount_idx_0#0: uint64 = 1000u + let inner_txn_params%1%%AssetAmount_length#0: uint64 = 1u + let inner_txn_params%1%%param_XferAsset_idx_0#0: uint64 = new_asset#0 + let inner_txn_params%1%%XferAsset_length#0: uint64 = 1u + let inner_txn_params%1%%param_Fee_idx_0#0: uint64 = 0u + let inner_txn_params%1%%Fee_length#0: uint64 = 1u + let inner_txn_params%1%%Sender_length#0: uint64 = 0u + let inner_txn_params%1%%Note_length#0: uint64 = 0u + let inner_txn_params%1%%Receiver_length#0: uint64 = 0u + let inner_txn_params%1%%Amount_length#0: uint64 = 0u + let inner_txn_params%1%%CloseRemainderTo_length#0: uint64 = 0u + let inner_txn_params%1%%VotePK_length#0: uint64 = 0u + let inner_txn_params%1%%SelectionPK_length#0: uint64 = 0u + let inner_txn_params%1%%VoteFirst_length#0: uint64 = 0u + let inner_txn_params%1%%VoteLast_length#0: uint64 = 0u + let inner_txn_params%1%%VoteKeyDilution_length#0: uint64 = 0u + let inner_txn_params%1%%Type_length#0: uint64 = 0u + let inner_txn_params%1%%AssetCloseTo_length#0: uint64 = 0u + let inner_txn_params%1%%ApplicationID_length#0: uint64 = 0u + let inner_txn_params%1%%OnCompletion_length#0: uint64 = 0u + let inner_txn_params%1%%ApprovalProgram_length#0: uint64 = 0u + let inner_txn_params%1%%ClearStateProgram_length#0: uint64 = 0u + let inner_txn_params%1%%RekeyTo_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAsset_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetTotal_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetDecimals_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetDefaultFrozen_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetUnitName_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetName_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetURL_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetMetadataHash_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetManager_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetReserve_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetFreeze_length#0: uint64 = 0u + let inner_txn_params%1%%ConfigAssetClawback_length#0: uint64 = 0u + let inner_txn_params%1%%FreezeAsset_length#0: uint64 = 0u + let inner_txn_params%1%%FreezeAssetAccount_length#0: uint64 = 0u + let inner_txn_params%1%%FreezeAssetFrozen_length#0: uint64 = 0u + let inner_txn_params%1%%GlobalNumUint_length#0: uint64 = 0u + let inner_txn_params%1%%GlobalNumByteSlice_length#0: uint64 = 0u + let inner_txn_params%1%%LocalNumUint_length#0: uint64 = 0u + let inner_txn_params%1%%LocalNumByteSlice_length#0: uint64 = 0u + let inner_txn_params%1%%ExtraProgramPages_length#0: uint64 = 0u + let inner_txn_params%1%%Nonparticipation_length#0: uint64 = 0u + let inner_txn_params%1%%StateProofPK_length#0: uint64 = 0u + let inner_txn_params%1%%ApplicationArgs_length#0: uint64 = 0u + let inner_txn_params%1%%Accounts_length#0: uint64 = 0u + let inner_txn_params%1%%Assets_length#0: uint64 = 0u + let inner_txn_params%1%%Applications_length#0: uint64 = 0u + let inner_txn_params%1%%ApprovalProgramPages_length#0: uint64 = 0u + let inner_txn_params%1%%ClearStateProgramPages_length#0: uint64 = 0u + ((itxn_field Fee) inner_txn_params%1%%param_Fee_idx_0#0) + ((itxn_field XferAsset) inner_txn_params%1%%param_XferAsset_idx_0#0) + ((itxn_field AssetAmount) inner_txn_params%1%%param_AssetAmount_idx_0#0) + ((itxn_field AssetReceiver) inner_txn_params%1%%param_AssetReceiver_idx_0#0) + ((itxn_field AssetSender) inner_txn_params%1%%param_AssetSender_idx_0#0) + ((itxn_field TypeEnum) inner_txn_params%1%%param_TypeEnum_idx_0#0) + goto block@2 + block@2: // next_txn_L28 + itxn_submit + return + + program clear-state: + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program() -> bool: + block@0: // L10 + return 1u \ No newline at end of file diff --git a/test_cases/inner_transactions/out/CreateAndTransferContract.ssa.opt_pass_1.ir b/test_cases/inner_transactions/out/CreateAndTransferContract.ssa.opt_pass_1.ir new file mode 100644 index 0000000000..43b41f8419 --- /dev/null +++ b/test_cases/inner_transactions/out/CreateAndTransferContract.ssa.opt_pass_1.ir @@ -0,0 +1,58 @@ +contract test_cases.inner_transactions.asset_transfer.CreateAndTransferContract: + program approval: + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program() -> bool: + block@0: // L10 + let tmp%0#0: bool = (txn NumAppArgs) + goto tmp%0#0 ? block@1 : block@5 + block@1: // abi_routing_L10 + let tmp%1#0: bytes = (txna ApplicationArgs 0) + switch tmp%1#0 {method "create_and_transfer()void" => block@2, * => fail // reject transaction} + block@2: // create_and_transfer_route_L11 + let tmp%2#0: uint64 = (txn OnCompletion) + let tmp%3#0: bool = (! tmp%2#0) + (assert tmp%3#0) // OnCompletion is NoOp + let tmp%4#0: bool = (txn ApplicationID) + (assert tmp%4#0) // is not creating + test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() + return 1u + block@5: // bare_routing_L10 + let tmp%5#0: uint64 = (txn OnCompletion) + let not%tmp%5#0: bool = (! tmp%5#0) + (assert not%tmp%5#0) // reject transaction + let tmp%6#0: bool = (txn ApplicationID) + let tmp%7#0: bool = (! tmp%6#0) + (assert tmp%7#0) // is creating + return 1u + + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() -> void: + block@0: // L11 + itxn_begin + let inner_txn_params%0%%param_ConfigAssetManager_idx_0#0: bytes = (global CurrentApplicationAddress) + let inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0: bytes = (global CurrentApplicationAddress) + ((itxn_field Fee) 0u) + ((itxn_field ConfigAssetClawback) inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0) + ((itxn_field ConfigAssetManager) inner_txn_params%0%%param_ConfigAssetManager_idx_0#0) + ((itxn_field ConfigAssetDecimals) 0u) + ((itxn_field ConfigAssetUnitName) "TST") + ((itxn_field ConfigAssetName) "test") + ((itxn_field ConfigAssetTotal) 1000u) + ((itxn_field TypeEnum) acfg) + itxn_submit + let new_asset#0: uint64 = (itxn CreatedAssetID) + itxn_begin + let (value%0#0: bytes, check%0#0: bool) = ((asset_params_get AssetCreator) new_asset#0) + (assert check%0#0) // asset exists + let inner_txn_params%1%%param_AssetReceiver_idx_0#0: bytes = (global CurrentApplicationAddress) + ((itxn_field Fee) 0u) + ((itxn_field XferAsset) new_asset#0) + ((itxn_field AssetAmount) 1000u) + ((itxn_field AssetReceiver) inner_txn_params%1%%param_AssetReceiver_idx_0#0) + ((itxn_field AssetSender) value%0#0) + ((itxn_field TypeEnum) axfer) + itxn_submit + return + + program clear-state: + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program() -> bool: + block@0: // L10 + return 1u \ No newline at end of file diff --git a/test_cases/inner_transactions/out/asset_transfer.awst b/test_cases/inner_transactions/out/asset_transfer.awst new file mode 100644 index 0000000000..b55b1a16ea --- /dev/null +++ b/test_cases/inner_transactions/out/asset_transfer.awst @@ -0,0 +1,8 @@ +contract CreateAndTransferContract +{ + abimethod create_and_transfer(): None + { + new_asset: algopy.Asset = submit_txn(create_inner_transaction(TypeEnum=acfg, ConfigAssetTotal=1000u, ConfigAssetName='test', ConfigAssetUnitName='TST', ConfigAssetDecimals=0u, ConfigAssetManager=global(), ConfigAssetClawback=global(), Fee=0u)).CreatedAssetID + submit_txn(create_inner_transaction(TypeEnum=axfer, AssetSender=checked_maybe(asset_params_get(new_asset)), AssetReceiver=global(), AssetAmount=1000u, XferAsset=new_asset, Fee=0u)) + } +} \ No newline at end of file diff --git a/test_cases/inner_transactions/out/client_CreateAndTransferContract.py b/test_cases/inner_transactions/out/client_CreateAndTransferContract.py new file mode 100644 index 0000000000..377162dbae --- /dev/null +++ b/test_cases/inner_transactions/out/client_CreateAndTransferContract.py @@ -0,0 +1,13 @@ +# This file is auto-generated, do not modify +# flake8: noqa +# fmt: off +import typing + +import algopy + + +class CreateAndTransferContract(algopy.arc4.ARC4Client, typing.Protocol): + @algopy.arc4.abimethod + def create_and_transfer( + self, + ) -> None: ... diff --git a/test_cases/inner_transactions/out_O2/CreateAndTransferContract.approval.teal b/test_cases/inner_transactions/out_O2/CreateAndTransferContract.approval.teal new file mode 100644 index 0000000000..86e47ff48c --- /dev/null +++ b/test_cases/inner_transactions/out_O2/CreateAndTransferContract.approval.teal @@ -0,0 +1,72 @@ +#pragma version 10 + +test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program: + txn NumAppArgs + bz main_bare_routing@5 + method "create_and_transfer()void" + txna ApplicationArgs 0 + match main_create_and_transfer_route@2 + err // reject transaction + +main_create_and_transfer_route@2: + txn OnCompletion + ! + assert // OnCompletion is NoOp + txn ApplicationID + assert // is not creating + callsub create_and_transfer + int 1 + return + +main_bare_routing@5: + txn OnCompletion + ! + assert // reject transaction + txn ApplicationID + ! + assert // is creating + int 1 + return + + +// test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() -> void: +create_and_transfer: + proto 0 0 + itxn_begin + global CurrentApplicationAddress + dup + int 0 + itxn_field Fee + itxn_field ConfigAssetClawback + itxn_field ConfigAssetManager + int 0 + itxn_field ConfigAssetDecimals + byte "TST" + itxn_field ConfigAssetUnitName + byte "test" + itxn_field ConfigAssetName + int 1000 + itxn_field ConfigAssetTotal + int acfg + itxn_field TypeEnum + itxn_submit + itxn CreatedAssetID + itxn_begin + dup + asset_params_get AssetCreator + swap + cover 2 + assert // asset exists + global CurrentApplicationAddress + int 0 + itxn_field Fee + swap + itxn_field XferAsset + int 1000 + itxn_field AssetAmount + itxn_field AssetReceiver + itxn_field AssetSender + int axfer + itxn_field TypeEnum + itxn_submit + retsub diff --git a/test_cases/inner_transactions/out_O2/CreateAndTransferContract.clear.teal b/test_cases/inner_transactions/out_O2/CreateAndTransferContract.clear.teal new file mode 100644 index 0000000000..bc1674f7b6 --- /dev/null +++ b/test_cases/inner_transactions/out_O2/CreateAndTransferContract.clear.teal @@ -0,0 +1,5 @@ +#pragma version 10 + +test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program: + int 1 + return diff --git a/test_cases/inner_transactions/out_O2/CreateAndTransferContract.destructured.ir b/test_cases/inner_transactions/out_O2/CreateAndTransferContract.destructured.ir new file mode 100644 index 0000000000..43b41f8419 --- /dev/null +++ b/test_cases/inner_transactions/out_O2/CreateAndTransferContract.destructured.ir @@ -0,0 +1,58 @@ +contract test_cases.inner_transactions.asset_transfer.CreateAndTransferContract: + program approval: + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program() -> bool: + block@0: // L10 + let tmp%0#0: bool = (txn NumAppArgs) + goto tmp%0#0 ? block@1 : block@5 + block@1: // abi_routing_L10 + let tmp%1#0: bytes = (txna ApplicationArgs 0) + switch tmp%1#0 {method "create_and_transfer()void" => block@2, * => fail // reject transaction} + block@2: // create_and_transfer_route_L11 + let tmp%2#0: uint64 = (txn OnCompletion) + let tmp%3#0: bool = (! tmp%2#0) + (assert tmp%3#0) // OnCompletion is NoOp + let tmp%4#0: bool = (txn ApplicationID) + (assert tmp%4#0) // is not creating + test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() + return 1u + block@5: // bare_routing_L10 + let tmp%5#0: uint64 = (txn OnCompletion) + let not%tmp%5#0: bool = (! tmp%5#0) + (assert not%tmp%5#0) // reject transaction + let tmp%6#0: bool = (txn ApplicationID) + let tmp%7#0: bool = (! tmp%6#0) + (assert tmp%7#0) // is creating + return 1u + + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() -> void: + block@0: // L11 + itxn_begin + let inner_txn_params%0%%param_ConfigAssetManager_idx_0#0: bytes = (global CurrentApplicationAddress) + let inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0: bytes = (global CurrentApplicationAddress) + ((itxn_field Fee) 0u) + ((itxn_field ConfigAssetClawback) inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0) + ((itxn_field ConfigAssetManager) inner_txn_params%0%%param_ConfigAssetManager_idx_0#0) + ((itxn_field ConfigAssetDecimals) 0u) + ((itxn_field ConfigAssetUnitName) "TST") + ((itxn_field ConfigAssetName) "test") + ((itxn_field ConfigAssetTotal) 1000u) + ((itxn_field TypeEnum) acfg) + itxn_submit + let new_asset#0: uint64 = (itxn CreatedAssetID) + itxn_begin + let (value%0#0: bytes, check%0#0: bool) = ((asset_params_get AssetCreator) new_asset#0) + (assert check%0#0) // asset exists + let inner_txn_params%1%%param_AssetReceiver_idx_0#0: bytes = (global CurrentApplicationAddress) + ((itxn_field Fee) 0u) + ((itxn_field XferAsset) new_asset#0) + ((itxn_field AssetAmount) 1000u) + ((itxn_field AssetReceiver) inner_txn_params%1%%param_AssetReceiver_idx_0#0) + ((itxn_field AssetSender) value%0#0) + ((itxn_field TypeEnum) axfer) + itxn_submit + return + + program clear-state: + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program() -> bool: + block@0: // L10 + return 1u \ No newline at end of file diff --git a/test_cases/inner_transactions/out_unoptimized/CreateAndTransferContract.approval.teal b/test_cases/inner_transactions/out_unoptimized/CreateAndTransferContract.approval.teal new file mode 100644 index 0000000000..676d6f58b6 --- /dev/null +++ b/test_cases/inner_transactions/out_unoptimized/CreateAndTransferContract.approval.teal @@ -0,0 +1,180 @@ +#pragma version 10 + +test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program: + // inner_transactions/asset_transfer.py:10 + // class CreateAndTransferContract(ARC4Contract): + txn NumAppArgs + bz main_bare_routing@5 + txna ApplicationArgs 0 + method "create_and_transfer()void" + swap + match main_create_and_transfer_route@2 + b main_switch_case_default@3 + +main_create_and_transfer_route@2: + // inner_transactions/asset_transfer.py:11 + // @arc4.abimethod() + txn OnCompletion + int NoOp + == + assert // OnCompletion is NoOp + txn ApplicationID + assert // is not creating + callsub create_and_transfer + int 1 + return + +main_switch_case_default@3: + // inner_transactions/asset_transfer.py:10 + // class CreateAndTransferContract(ARC4Contract): + err // reject transaction + +main_bare_routing@5: + // inner_transactions/asset_transfer.py:10 + // class CreateAndTransferContract(ARC4Contract): + txn OnCompletion + int 0 + swap + match main_create@6 + b main_reject_bare_on_completion@7 + +main_create@6: + // inner_transactions/asset_transfer.py:10 + // class CreateAndTransferContract(ARC4Contract): + txn ApplicationID + ! + assert // is creating + int 1 + return + +main_reject_bare_on_completion@7: + // inner_transactions/asset_transfer.py:10 + // class CreateAndTransferContract(ARC4Contract): + err // reject transaction + + +// test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() -> void: +create_and_transfer: + // inner_transactions/asset_transfer.py:11-12 + // @arc4.abimethod() + // def create_and_transfer(self) -> None: + proto 0 0 + // inner_transactions/asset_transfer.py:15-24 + // itxn.AssetConfig( + // total=1000, + // asset_name="test", + // unit_name="TST", + // decimals=0, + // manager=op.Global.current_application_address, + // clawback=op.Global.current_application_address, + // fee=0, + // ) + // .submit() + itxn_begin + // inner_transactions/asset_transfer.py:20 + // manager=op.Global.current_application_address, + global CurrentApplicationAddress + // inner_transactions/asset_transfer.py:21 + // clawback=op.Global.current_application_address, + global CurrentApplicationAddress + // inner_transactions/asset_transfer.py:22 + // fee=0, + int 0 + itxn_field Fee + itxn_field ConfigAssetClawback + itxn_field ConfigAssetManager + // inner_transactions/asset_transfer.py:19 + // decimals=0, + int 0 + itxn_field ConfigAssetDecimals + // inner_transactions/asset_transfer.py:18 + // unit_name="TST", + byte "TST" + itxn_field ConfigAssetUnitName + // inner_transactions/asset_transfer.py:17 + // asset_name="test", + byte "test" + itxn_field ConfigAssetName + // inner_transactions/asset_transfer.py:16 + // total=1000, + int 1000 + itxn_field ConfigAssetTotal + // inner_transactions/asset_transfer.py:15 + // itxn.AssetConfig( + int acfg + itxn_field TypeEnum + // inner_transactions/asset_transfer.py:15-24 + // itxn.AssetConfig( + // total=1000, + // asset_name="test", + // unit_name="TST", + // decimals=0, + // manager=op.Global.current_application_address, + // clawback=op.Global.current_application_address, + // fee=0, + // ) + // .submit() + itxn_submit + // inner_transactions/asset_transfer.py:15-25 + // itxn.AssetConfig( + // total=1000, + // asset_name="test", + // unit_name="TST", + // decimals=0, + // manager=op.Global.current_application_address, + // clawback=op.Global.current_application_address, + // fee=0, + // ) + // .submit() + // .created_asset + itxn CreatedAssetID + // inner_transactions/asset_transfer.py:28-35 + // # transfer + // itxn.AssetTransfer( + // asset_sender=new_asset.creator, + // asset_receiver=Global.current_application_address, + // asset_amount=1000, + // xfer_asset=new_asset, + // fee=0, + // ).submit() + itxn_begin + // inner_transactions/asset_transfer.py:30 + // asset_sender=new_asset.creator, + dup + asset_params_get AssetCreator + assert // asset exists + swap + // inner_transactions/asset_transfer.py:31 + // asset_receiver=Global.current_application_address, + global CurrentApplicationAddress + // inner_transactions/asset_transfer.py:13-14 + // # create + // new_asset = ( + swap + // inner_transactions/asset_transfer.py:34 + // fee=0, + int 0 + itxn_field Fee + itxn_field XferAsset + // inner_transactions/asset_transfer.py:32 + // asset_amount=1000, + int 1000 + itxn_field AssetAmount + itxn_field AssetReceiver + itxn_field AssetSender + // inner_transactions/asset_transfer.py:28-29 + // # transfer + // itxn.AssetTransfer( + int axfer + itxn_field TypeEnum + // inner_transactions/asset_transfer.py:28-35 + // # transfer + // itxn.AssetTransfer( + // asset_sender=new_asset.creator, + // asset_receiver=Global.current_application_address, + // asset_amount=1000, + // xfer_asset=new_asset, + // fee=0, + // ).submit() + itxn_submit + retsub diff --git a/test_cases/inner_transactions/out_unoptimized/CreateAndTransferContract.clear.teal b/test_cases/inner_transactions/out_unoptimized/CreateAndTransferContract.clear.teal new file mode 100644 index 0000000000..3d8eb0eacd --- /dev/null +++ b/test_cases/inner_transactions/out_unoptimized/CreateAndTransferContract.clear.teal @@ -0,0 +1,7 @@ +#pragma version 10 + +test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program: + // inner_transactions/asset_transfer.py:10 + // class CreateAndTransferContract(ARC4Contract): + int 1 + return diff --git a/test_cases/inner_transactions/out_unoptimized/CreateAndTransferContract.destructured.ir b/test_cases/inner_transactions/out_unoptimized/CreateAndTransferContract.destructured.ir new file mode 100644 index 0000000000..fee98f347e --- /dev/null +++ b/test_cases/inner_transactions/out_unoptimized/CreateAndTransferContract.destructured.ir @@ -0,0 +1,70 @@ +contract test_cases.inner_transactions.asset_transfer.CreateAndTransferContract: + program approval: + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program() -> bool: + block@0: // L10 + let tmp%0#0: bool = (txn NumAppArgs) + goto tmp%0#0 ? block@1 : block@5 + block@1: // abi_routing_L10 + let tmp%1#0: bytes = (txna ApplicationArgs 0) + switch tmp%1#0 {method "create_and_transfer()void" => block@2, * => block@3} + block@2: // create_and_transfer_route_L11 + let tmp%2#0: uint64 = (txn OnCompletion) + let tmp%3#0: bool = (== tmp%2#0 NoOp) + (assert tmp%3#0) // OnCompletion is NoOp + let tmp%4#0: bool = (txn ApplicationID) + (assert tmp%4#0) // is not creating + test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() + return 1u + block@3: // switch_case_default_L10 + goto block@4 + block@4: // switch_case_next_L10 + fail // reject transaction + block@5: // bare_routing_L10 + let tmp%5#0: uint64 = (txn OnCompletion) + switch tmp%5#0 {0u => block@6, * => block@7} + block@6: // create_L10 + let tmp%6#0: bool = (txn ApplicationID) + let tmp%7#0: bool = (! tmp%6#0) + (assert tmp%7#0) // is creating + return 1u + block@7: // reject_bare_on_completion_L10 + fail // reject transaction + + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer() -> void: + block@0: // L11 + itxn_begin + let inner_txn_params%0%%param_ConfigAssetManager_idx_0#0: bytes = (global CurrentApplicationAddress) + let inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0: bytes = (global CurrentApplicationAddress) + ((itxn_field Fee) 0u) + ((itxn_field ConfigAssetClawback) inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0) + ((itxn_field ConfigAssetManager) inner_txn_params%0%%param_ConfigAssetManager_idx_0#0) + ((itxn_field ConfigAssetDecimals) 0u) + ((itxn_field ConfigAssetUnitName) "TST") + ((itxn_field ConfigAssetName) "test") + ((itxn_field ConfigAssetTotal) 1000u) + ((itxn_field TypeEnum) acfg) + goto block@1 + block@1: // next_txn_L15 + itxn_submit + let new_asset#0: uint64 = (itxn CreatedAssetID) + itxn_begin + let (value%0#0: bytes, check%0#0: bool) = ((asset_params_get AssetCreator) new_asset#0) + (assert check%0#0) // asset exists + let inner_txn_params%1%%param_AssetSender_idx_0#0: bytes = value%0#0 + let inner_txn_params%1%%param_AssetReceiver_idx_0#0: bytes = (global CurrentApplicationAddress) + let inner_txn_params%1%%param_XferAsset_idx_0#0: uint64 = new_asset#0 + ((itxn_field Fee) 0u) + ((itxn_field XferAsset) inner_txn_params%1%%param_XferAsset_idx_0#0) + ((itxn_field AssetAmount) 1000u) + ((itxn_field AssetReceiver) inner_txn_params%1%%param_AssetReceiver_idx_0#0) + ((itxn_field AssetSender) inner_txn_params%1%%param_AssetSender_idx_0#0) + ((itxn_field TypeEnum) axfer) + goto block@2 + block@2: // next_txn_L28 + itxn_submit + return + + program clear-state: + subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program() -> bool: + block@0: // L10 + return 1u \ No newline at end of file diff --git a/test_cases/inner_transactions/puya.log b/test_cases/inner_transactions/puya.log index e1500f4e54..9e73a416ef 100644 --- a/test_cases/inner_transactions/puya.log +++ b/test_cases/inner_transactions/puya.log @@ -336,6 +336,32 @@ debug: Sealing block@None: // switch_case_next_L20 debug: Sealing block@None: // after_if_else_L20 debug: Sealing block@0: // L20 debug: Terminated block@0: // L20 +debug: Sealing block@0: // L11 +debug: Terminated block@0: // L11 +debug: Sealing block@1: // next_txn_L15 +debug: Terminated block@1: // next_txn_L15 +debug: Sealing block@2: // next_txn_L28 +debug: Terminated block@2: // next_txn_L28 +debug: Sealing block@0: // L10 +debug: Terminated block@0: // L10 +debug: Sealing block@None: // abi_routing_L10 +debug: Sealing block@None: // bare_routing_L10 +debug: Terminated block@1: // abi_routing_L10 +debug: Sealing block@None: // switch_case_default_L10 +debug: Sealing block@None: // create_and_transfer_route_L11 +debug: Terminated block@2: // create_and_transfer_route_L11 +debug: Terminated block@3: // switch_case_default_L10 +debug: Sealing block@4: // switch_case_next_L10 +debug: Terminated block@4: // switch_case_next_L10 +debug: Terminated block@5: // bare_routing_L10 +debug: Sealing block@None: // reject_bare_on_completion_L10 +debug: Sealing block@None: // create_L10 +debug: Terminated block@6: // create_L10 +debug: Terminated block@7: // reject_bare_on_completion_L10 +debug: Sealing block@None: // switch_case_next_L10 +debug: Sealing block@None: // after_if_else_L10 +debug: Sealing block@0: // L10 +debug: Terminated block@0: // L10 debug: Sealing block@0: // L10 debug: Terminated block@0: // L10 debug: Sealing block@1: // next_txn_L14 @@ -1494,6 +1520,230 @@ debug: Sequentializing parallel copies in test_cases.inner_transactions.array_ac debug: Sequentializing parallel copies in test_cases.inner_transactions.array_access.ArrayAccessContract.clear_state_program debug: Performing post-SSA optimizations debug: Output IR to inner_transactions/out/ArrayAccessContract.destructured.ir +debug: Output IR to inner_transactions/out/CreateAndTransferContract.ssa.ir +info: Optimizing test_cases.inner_transactions.asset_transfer.CreateAndTransferContract at level 1 +debug: Begin optimization pass 1/100 +debug: Optimizing subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program +debug: Splitting parallel copies prior to optimization +debug: Optimizer: Constant Replacer +debug: Optimizer: Copy Propagation +debug: Optimizer: Intrinsic Simplifier +debug: Simplified (== tmp%2#0 NoOp) to (! tmp%2#0) +debug: Optimizer: Remove Unused Variables +debug: Optimizer: Inner Txn Field Replacer +debug: Optimizer: Simplify Control Ops +debug: inlining the default target of a switch/goto nth +debug: adding block@1: // abi_routing_L10 as a predecessor of block@4: // switch_case_next_L10 due to inlining of block@3: // switch_case_default_L10 +debug: simplified terminator of block@1: // abi_routing_L10 from switch tmp%1#0 {method "create_and_transfer()void" => block@2, * => block@3} to switch tmp%1#0 {method "create_and_transfer()void" => block@2, * => block@4} +debug: simplifying a switch with constants into goto nth +debug: simplified terminator of block@5: // bare_routing_L10 from switch tmp%5#0 {0u => block@6, * => block@7} to goto_nth [block@6][tmp%5#0] else goto block@7 +debug: inlining the default target of a switch/goto nth +debug: simplified terminator of block@1: // abi_routing_L10 from switch tmp%1#0 {method "create_and_transfer()void" => block@2, * => block@4} to switch tmp%1#0 {method "create_and_transfer()void" => block@2, * => fail // reject transaction} +debug: simplifying a goto nth with two targets into a conditional branch +debug: simplified terminator of block@5: // bare_routing_L10 from goto_nth [block@6][tmp%5#0] else goto block@7 to goto tmp%5#0 ? block@7 : block@6 +debug: inlining condition branch to err block into an assert false +debug: simplified terminator of block@5: // bare_routing_L10 from goto tmp%5#0 ? block@7 : block@6 to goto block@6 +debug: Optimizer: Remove Linear Jump +debug: Merged linear block@4: // switch_case_next_L10 into block@3: // switch_case_default_L10 +debug: Merged linear block@6: // create_L10 into block@5: // bare_routing_L10 +debug: Optimizer: Remove Empty Blocks +debug: Optimizer: Remove Unreachable Blocks +debug: Removing unreachable blocks: block@3: // switch_case_default_L10, block@7: // reject_bare_on_completion_L10 +debug: Optimizer: Repeated Expression Elimination +debug: Optimizing subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer +debug: Splitting parallel copies prior to optimization +debug: Optimizer: Constant Replacer +debug: Optimizer: Copy Propagation +debug: Found equivalence set: value%0#0, inner_txn_params%1%%param_AssetSender_idx_0#0 +debug: Replacing {inner_txn_params%1%%param_AssetSender_idx_0#0} with value%0#0 made 1 modifications +debug: Found equivalence set: new_asset#0, inner_txn_params%1%%param_XferAsset_idx_0#0 +debug: Replacing {inner_txn_params%1%%param_XferAsset_idx_0#0} with new_asset#0 made 1 modifications +debug: Optimizer: Intrinsic Simplifier +debug: Optimizer: Remove Unused Variables +debug: Removing unused variable inner_txn_params%0#0 +debug: Removing unused variable inner_txn_params%0%%param_TypeEnum_idx_0#0 +debug: Removing unused variable inner_txn_params%0%%TypeEnum_length#0 +debug: Removing unused variable inner_txn_params%0%%param_ConfigAssetTotal_idx_0#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetTotal_length#0 +debug: Removing unused variable inner_txn_params%0%%param_ConfigAssetName_idx_0#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetName_length#0 +debug: Removing unused variable inner_txn_params%0%%param_ConfigAssetUnitName_idx_0#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetUnitName_length#0 +debug: Removing unused variable inner_txn_params%0%%param_ConfigAssetDecimals_idx_0#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetDecimals_length#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetManager_length#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetClawback_length#0 +debug: Removing unused variable inner_txn_params%0%%param_Fee_idx_0#0 +debug: Removing unused variable inner_txn_params%0%%Fee_length#0 +debug: Removing unused variable inner_txn_params%0%%Sender_length#0 +debug: Removing unused variable inner_txn_params%0%%Note_length#0 +debug: Removing unused variable inner_txn_params%0%%Receiver_length#0 +debug: Removing unused variable inner_txn_params%0%%Amount_length#0 +debug: Removing unused variable inner_txn_params%0%%CloseRemainderTo_length#0 +debug: Removing unused variable inner_txn_params%0%%VotePK_length#0 +debug: Removing unused variable inner_txn_params%0%%SelectionPK_length#0 +debug: Removing unused variable inner_txn_params%0%%VoteFirst_length#0 +debug: Removing unused variable inner_txn_params%0%%VoteLast_length#0 +debug: Removing unused variable inner_txn_params%0%%VoteKeyDilution_length#0 +debug: Removing unused variable inner_txn_params%0%%Type_length#0 +debug: Removing unused variable inner_txn_params%0%%XferAsset_length#0 +debug: Removing unused variable inner_txn_params%0%%AssetAmount_length#0 +debug: Removing unused variable inner_txn_params%0%%AssetSender_length#0 +debug: Removing unused variable inner_txn_params%0%%AssetReceiver_length#0 +debug: Removing unused variable inner_txn_params%0%%AssetCloseTo_length#0 +debug: Removing unused variable inner_txn_params%0%%ApplicationID_length#0 +debug: Removing unused variable inner_txn_params%0%%OnCompletion_length#0 +debug: Removing unused variable inner_txn_params%0%%ApprovalProgram_length#0 +debug: Removing unused variable inner_txn_params%0%%ClearStateProgram_length#0 +debug: Removing unused variable inner_txn_params%0%%RekeyTo_length#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAsset_length#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetDefaultFrozen_length#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetURL_length#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetMetadataHash_length#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetReserve_length#0 +debug: Removing unused variable inner_txn_params%0%%ConfigAssetFreeze_length#0 +debug: Removing unused variable inner_txn_params%0%%FreezeAsset_length#0 +debug: Removing unused variable inner_txn_params%0%%FreezeAssetAccount_length#0 +debug: Removing unused variable inner_txn_params%0%%FreezeAssetFrozen_length#0 +debug: Removing unused variable inner_txn_params%0%%GlobalNumUint_length#0 +debug: Removing unused variable inner_txn_params%0%%GlobalNumByteSlice_length#0 +debug: Removing unused variable inner_txn_params%0%%LocalNumUint_length#0 +debug: Removing unused variable inner_txn_params%0%%LocalNumByteSlice_length#0 +debug: Removing unused variable inner_txn_params%0%%ExtraProgramPages_length#0 +debug: Removing unused variable inner_txn_params%0%%Nonparticipation_length#0 +debug: Removing unused variable inner_txn_params%0%%StateProofPK_length#0 +debug: Removing unused variable inner_txn_params%0%%ApplicationArgs_length#0 +debug: Removing unused variable inner_txn_params%0%%Accounts_length#0 +debug: Removing unused variable inner_txn_params%0%%Assets_length#0 +debug: Removing unused variable inner_txn_params%0%%Applications_length#0 +debug: Removing unused variable inner_txn_params%0%%ApprovalProgramPages_length#0 +debug: Removing unused variable inner_txn_params%0%%ClearStateProgramPages_length#0 +debug: Removing unused variable inner_txn_params%1#0 +debug: Removing unused variable inner_txn_params%1%%param_TypeEnum_idx_0#0 +debug: Removing unused variable inner_txn_params%1%%TypeEnum_length#0 +debug: Removing unused variable inner_txn_params%1%%AssetSender_length#0 +debug: Removing unused variable inner_txn_params%1%%AssetReceiver_length#0 +debug: Removing unused variable inner_txn_params%1%%param_AssetAmount_idx_0#0 +debug: Removing unused variable inner_txn_params%1%%AssetAmount_length#0 +debug: Removing unused variable inner_txn_params%1%%XferAsset_length#0 +debug: Removing unused variable inner_txn_params%1%%param_Fee_idx_0#0 +debug: Removing unused variable inner_txn_params%1%%Fee_length#0 +debug: Removing unused variable inner_txn_params%1%%Sender_length#0 +debug: Removing unused variable inner_txn_params%1%%Note_length#0 +debug: Removing unused variable inner_txn_params%1%%Receiver_length#0 +debug: Removing unused variable inner_txn_params%1%%Amount_length#0 +debug: Removing unused variable inner_txn_params%1%%CloseRemainderTo_length#0 +debug: Removing unused variable inner_txn_params%1%%VotePK_length#0 +debug: Removing unused variable inner_txn_params%1%%SelectionPK_length#0 +debug: Removing unused variable inner_txn_params%1%%VoteFirst_length#0 +debug: Removing unused variable inner_txn_params%1%%VoteLast_length#0 +debug: Removing unused variable inner_txn_params%1%%VoteKeyDilution_length#0 +debug: Removing unused variable inner_txn_params%1%%Type_length#0 +debug: Removing unused variable inner_txn_params%1%%AssetCloseTo_length#0 +debug: Removing unused variable inner_txn_params%1%%ApplicationID_length#0 +debug: Removing unused variable inner_txn_params%1%%OnCompletion_length#0 +debug: Removing unused variable inner_txn_params%1%%ApprovalProgram_length#0 +debug: Removing unused variable inner_txn_params%1%%ClearStateProgram_length#0 +debug: Removing unused variable inner_txn_params%1%%RekeyTo_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAsset_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetTotal_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetDecimals_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetDefaultFrozen_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetUnitName_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetName_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetURL_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetMetadataHash_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetManager_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetReserve_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetFreeze_length#0 +debug: Removing unused variable inner_txn_params%1%%ConfigAssetClawback_length#0 +debug: Removing unused variable inner_txn_params%1%%FreezeAsset_length#0 +debug: Removing unused variable inner_txn_params%1%%FreezeAssetAccount_length#0 +debug: Removing unused variable inner_txn_params%1%%FreezeAssetFrozen_length#0 +debug: Removing unused variable inner_txn_params%1%%GlobalNumUint_length#0 +debug: Removing unused variable inner_txn_params%1%%GlobalNumByteSlice_length#0 +debug: Removing unused variable inner_txn_params%1%%LocalNumUint_length#0 +debug: Removing unused variable inner_txn_params%1%%LocalNumByteSlice_length#0 +debug: Removing unused variable inner_txn_params%1%%ExtraProgramPages_length#0 +debug: Removing unused variable inner_txn_params%1%%Nonparticipation_length#0 +debug: Removing unused variable inner_txn_params%1%%StateProofPK_length#0 +debug: Removing unused variable inner_txn_params%1%%ApplicationArgs_length#0 +debug: Removing unused variable inner_txn_params%1%%Accounts_length#0 +debug: Removing unused variable inner_txn_params%1%%Assets_length#0 +debug: Removing unused variable inner_txn_params%1%%Applications_length#0 +debug: Removing unused variable inner_txn_params%1%%ApprovalProgramPages_length#0 +debug: Removing unused variable inner_txn_params%1%%ClearStateProgramPages_length#0 +debug: Optimizer: Inner Txn Field Replacer +debug: Optimizer: Simplify Control Ops +debug: Optimizer: Remove Linear Jump +debug: Replaced predecessor block@1: // next_txn_L15 with block@0: // L11 in block@2: // next_txn_L28 +debug: Merged linear block@1: // next_txn_L15 into block@0: // L11 +debug: Merged linear block@2: // next_txn_L28 into block@0: // L11 +debug: Optimizer: Remove Empty Blocks +debug: Optimizer: Remove Unreachable Blocks +debug: Optimizer: Repeated Expression Elimination +debug: Optimizing subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program +debug: Splitting parallel copies prior to optimization +debug: Optimizer: Constant Replacer +debug: Optimizer: Copy Propagation +debug: Optimizer: Intrinsic Simplifier +debug: Optimizer: Remove Unused Variables +debug: Optimizer: Inner Txn Field Replacer +debug: Optimizer: Simplify Control Ops +debug: Optimizer: Remove Linear Jump +debug: Optimizer: Remove Empty Blocks +debug: Optimizer: Remove Unreachable Blocks +debug: Optimizer: Repeated Expression Elimination +debug: Output IR to inner_transactions/out/CreateAndTransferContract.ssa.opt_pass_1.ir +debug: Begin optimization pass 2/100 +debug: Optimizing subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program +debug: Optimizer: Constant Replacer +debug: Optimizer: Copy Propagation +debug: Optimizer: Intrinsic Simplifier +debug: Optimizer: Remove Unused Variables +debug: Optimizer: Inner Txn Field Replacer +debug: Optimizer: Simplify Control Ops +debug: Optimizer: Remove Linear Jump +debug: Optimizer: Remove Empty Blocks +debug: Optimizer: Remove Unreachable Blocks +debug: Optimizer: Repeated Expression Elimination +debug: Optimizing subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer +debug: Optimizer: Constant Replacer +debug: Optimizer: Copy Propagation +debug: Optimizer: Intrinsic Simplifier +debug: Optimizer: Remove Unused Variables +debug: Optimizer: Inner Txn Field Replacer +debug: Optimizer: Simplify Control Ops +debug: Optimizer: Remove Linear Jump +debug: Optimizer: Remove Empty Blocks +debug: Optimizer: Remove Unreachable Blocks +debug: Optimizer: Repeated Expression Elimination +debug: Optimizing subroutine test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program +debug: Optimizer: Constant Replacer +debug: Optimizer: Copy Propagation +debug: Optimizer: Intrinsic Simplifier +debug: Optimizer: Remove Unused Variables +debug: Optimizer: Inner Txn Field Replacer +debug: Optimizer: Simplify Control Ops +debug: Optimizer: Remove Linear Jump +debug: Optimizer: Remove Empty Blocks +debug: Optimizer: Remove Unreachable Blocks +debug: Optimizer: Repeated Expression Elimination +debug: No optimizations performed in pass 2, ending loop +debug: Removing Phis from test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program +debug: Removing Phis from test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer +debug: Removing Phis from test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program +debug: Coalescing local variables in test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program using strategy RootOperandGrouping +debug: Coalescing resulted in 0 replacement/s +debug: Coalescing local variables in test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer using strategy RootOperandGrouping +debug: Coalescing resulted in 0 replacement/s +debug: Coalescing local variables in test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program using strategy RootOperandGrouping +debug: Coalescing resulted in 0 replacement/s +debug: Sequentializing parallel copies in test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program +debug: Sequentializing parallel copies in test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.create_and_transfer +debug: Sequentializing parallel copies in test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.clear_state_program +debug: Performing post-SSA optimizations +debug: Output IR to inner_transactions/out/CreateAndTransferContract.destructured.ir debug: Output IR to inner_transactions/out/Greeter.ssa.ir info: Optimizing test_cases.inner_transactions.c2c.Greeter at level 1 debug: Begin optimization pass 1/100 @@ -6268,6 +6518,39 @@ debug: Replaced test_branching_array_call_else_body@7.ops[28]: 'load tmp%11#0' w debug: Found 4 edge set/s for test_cases.inner_transactions.array_access.ArrayAccessContract.test_branching_array_call debug: test_cases.inner_transactions.array_access.ArrayAccessContract.test_branching_array_call f-stack entry: [] debug: test_cases.inner_transactions.array_access.ArrayAccessContract.test_branching_array_call f-stack on first store: ['tmp%0#0'] +debug: Inserted main_block@0.ops[1]: 'store tmp%0#0 to l-stack (copy)' +debug: Replaced main_block@0.ops[3]: 'load tmp%0#0' with 'load tmp%0#0 from l-stack (no copy)' +debug: Inserted main_abi_routing@1.ops[1]: 'store tmp%1#0 to l-stack (copy)' +debug: Replaced main_abi_routing@1.ops[4]: 'load tmp%1#0' with 'load tmp%1#0 from l-stack (no copy)' +debug: Inserted main_create_and_transfer_route@2.ops[1]: 'store tmp%2#0 to l-stack (copy)' +debug: Replaced main_create_and_transfer_route@2.ops[3]: 'load tmp%2#0' with 'load tmp%2#0 from l-stack (no copy)' +debug: Inserted main_create_and_transfer_route@2.ops[5]: 'store tmp%3#0 to l-stack (copy)' +debug: Replaced main_create_and_transfer_route@2.ops[7]: 'load tmp%3#0' with 'load tmp%3#0 from l-stack (no copy)' +debug: Inserted main_create_and_transfer_route@2.ops[10]: 'store tmp%4#0 to l-stack (copy)' +debug: Replaced main_create_and_transfer_route@2.ops[12]: 'load tmp%4#0' with 'load tmp%4#0 from l-stack (no copy)' +debug: Inserted main_bare_routing@5.ops[1]: 'store tmp%5#0 to l-stack (copy)' +debug: Replaced main_bare_routing@5.ops[3]: 'load tmp%5#0' with 'load tmp%5#0 from l-stack (no copy)' +debug: Inserted main_bare_routing@5.ops[5]: 'store not%tmp%5#0 to l-stack (copy)' +debug: Replaced main_bare_routing@5.ops[7]: 'load not%tmp%5#0' with 'load not%tmp%5#0 from l-stack (no copy)' +debug: Inserted main_bare_routing@5.ops[10]: 'store tmp%6#0 to l-stack (copy)' +debug: Replaced main_bare_routing@5.ops[12]: 'load tmp%6#0' with 'load tmp%6#0 from l-stack (no copy)' +debug: Inserted main_bare_routing@5.ops[14]: 'store tmp%7#0 to l-stack (copy)' +debug: Replaced main_bare_routing@5.ops[16]: 'load tmp%7#0' with 'load tmp%7#0 from l-stack (no copy)' +debug: Found 2 edge set/s for test_cases.inner_transactions.asset_transfer.CreateAndTransferContract.approval_program +debug: Inserted create_and_transfer_block@0.ops[23]: 'store new_asset#0 to l-stack (copy)' +debug: Replaced create_and_transfer_block@0.ops[26]: 'load new_asset#0' with 'load new_asset#0 from l-stack (no copy)' +debug: Inserted create_and_transfer_block@0.ops[28]: 'store check%0#0 to l-stack (copy)' +debug: Replaced create_and_transfer_block@0.ops[31]: 'load check%0#0' with 'load check%0#0 from l-stack (no copy)' +debug: Inserted create_and_transfer_block@0.ops[4]: 'store inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0 to l-stack (copy)' +debug: Replaced create_and_transfer_block@0.ops[8]: 'load inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0' with 'load inner_txn_params%0%%param_ConfigAssetClawback_idx_0#0 from l-stack (no copy)' +debug: Inserted create_and_transfer_block@0.ops[2]: 'store inner_txn_params%0%%param_ConfigAssetManager_idx_0#0 to l-stack (copy)' +debug: Replaced create_and_transfer_block@0.ops[11]: 'load inner_txn_params%0%%param_ConfigAssetManager_idx_0#0' with 'load inner_txn_params%0%%param_ConfigAssetManager_idx_0#0 from l-stack (no copy)' +debug: Inserted create_and_transfer_block@0.ops[36]: 'store inner_txn_params%1%%param_AssetReceiver_idx_0#0 to l-stack (copy)' +debug: Replaced create_and_transfer_block@0.ops[44]: 'load inner_txn_params%1%%param_AssetReceiver_idx_0#0' with 'load inner_txn_params%1%%param_AssetReceiver_idx_0#0 from l-stack (no copy)' +debug: Inserted create_and_transfer_block@0.ops[29]: 'store new_asset#0 to l-stack (copy)' +debug: Replaced create_and_transfer_block@0.ops[41]: 'load new_asset#0' with 'load new_asset#0 from l-stack (no copy)' +debug: Inserted create_and_transfer_block@0.ops[33]: 'store value%0#0 to l-stack (copy)' +debug: Replaced create_and_transfer_block@0.ops[48]: 'load value%0#0' with 'load value%0#0 from l-stack (no copy)' debug: Inserted main_block@0.ops[1]: 'store app_id%0#0 to l-stack (copy)' debug: Replaced main_block@0.ops[3]: 'load app_id%0#0' with 'load app_id%0#0 from l-stack (no copy)' debug: Inserted main_entrypoint@2.ops[1]: 'store tmp%0#0 to l-stack (copy)' @@ -6678,6 +6961,10 @@ info: Writing inner_transactions/out/ArrayAccessContract.approval.teal info: Writing inner_transactions/out/ArrayAccessContract.clear.teal info: Writing inner_transactions/out/ArrayAccessContract.arc32.json info: Writing inner_transactions/out/client_ArrayAccessContract.py +info: Writing inner_transactions/out/CreateAndTransferContract.approval.teal +info: Writing inner_transactions/out/CreateAndTransferContract.clear.teal +info: Writing inner_transactions/out/CreateAndTransferContract.arc32.json +info: Writing inner_transactions/out/client_CreateAndTransferContract.py info: Writing inner_transactions/out/Greeter.approval.teal info: Writing inner_transactions/out/Greeter.clear.teal info: Writing inner_transactions/out/Greeter.arc32.json diff --git a/tests/test_arc32.py b/tests/test_arc32.py index 231ff284fd..6281580c9c 100644 --- a/tests/test_arc32.py +++ b/tests/test_arc32.py @@ -709,6 +709,32 @@ def test_inner_transactions_tuple( app_client.call("test_assign_tuple_mixed") +def test_inner_transactions_asset_transfer( + algod_client: AlgodClient, account: algokit_utils.Account +) -> None: + example = TEST_CASES_DIR / "inner_transactions" / "asset_transfer.py" + app_spec = algokit_utils.ApplicationSpecification.from_json(compile_arc32(example)) + + # deploy + increased_fee = algod_client.suggested_params() + increased_fee.flat_fee = True + increased_fee.fee = constants.min_txn_fee * 3 + app_client = algokit_utils.ApplicationClient( + algod_client, app_spec, signer=account, suggested_params=increased_fee + ) + app_client.create() + + algokit_utils.ensure_funded( + algod_client, + algokit_utils.EnsureBalanceParameters( + account_to_fund=app_client.app_address, + min_spending_balance_micro_algos=200_000, + ), + ) + + app_client.call("create_and_transfer") + + def test_state_proxies(algod_client: AlgodClient, account: algokit_utils.Account) -> None: example = TEST_CASES_DIR / "state_proxies" / "contract.py" diff --git a/tests/test_transaction_fields.py b/tests/test_transaction_fields.py index b258d4981b..ace9916286 100644 --- a/tests/test_transaction_fields.py +++ b/tests/test_transaction_fields.py @@ -1,3 +1,4 @@ +import json from collections.abc import Iterable import mypy.nodes @@ -5,11 +6,19 @@ from puya.awst_build import constants from puya.awst_build.eb.transaction import get_field_python_name -from tests import EXAMPLES_DIR +from tests import EXAMPLES_DIR, VCS_ROOT from tests.utils import get_awst_cache _ALL_PYTHON_TXN_FIELD_NAMES = set(map(get_field_python_name, TXN_FIELDS)) _INNER_TRANSACTION_PYTHON_TXN_FIELD_NAMES = set(map(get_field_python_name, INNER_PARAM_TXN_FIELDS)) +_INTENTIONALLY_OMITTED_INNER_TXN_FIELDS = { + # the need to use approval / clear_state pages is abstracted away by + # allowing a tuple of pages in the stubs layer + "approval_program_pages", + "clear_state_program_pages", + # only allow enum version of type + "type_bytes", +} def _get_type_infos(type_names: Iterable[str]) -> Iterable[mypy.nodes.TypeInfo]: @@ -34,6 +43,7 @@ def test_group_transaction_members() -> None: def test_inner_transaction_field_setters() -> None: + unmapped = _INNER_TRANSACTION_PYTHON_TXN_FIELD_NAMES - _INTENTIONALLY_OMITTED_INNER_TXN_FIELDS for type_info in _get_type_infos( t.itxn_fields for t in constants.TRANSACTION_TYPE_TO_CLS.values() ): @@ -41,18 +51,20 @@ def test_inner_transaction_field_setters() -> None: for member in ("__init__", "set"): func_def = type_info.names[member].node assert isinstance(func_def, mypy.nodes.FuncDef) - arg_names = [a for a in func_def.arg_names if a is not None] + arg_names = {a for a in func_def.arg_names if a is not None} arg_names.remove("self") - unknown = sorted(set(arg_names) - _INNER_TRANSACTION_PYTHON_TXN_FIELD_NAMES) + unknown = sorted(arg_names - _INNER_TRANSACTION_PYTHON_TXN_FIELD_NAMES) assert not unknown, f"{type_info.fullname}: Unknown TxnField param members: {unknown}" + unmapped -= arg_names if init_args is None: - init_args = set(arg_names) + init_args = arg_names else: - difference = init_args.symmetric_difference(set(arg_names)) + difference = init_args.symmetric_difference(arg_names) assert ( not difference ), f"{type_info.fullname}.{member} field difference: {difference}" + assert not unmapped, f"Unmapped inner param fields: {sorted(unmapped)}" def test_inner_transaction_members() -> None: @@ -87,3 +99,33 @@ def test_txn_fields() -> None: # anything missing is an error missing_fields = sorted(_ALL_PYTHON_TXN_FIELD_NAMES - seen_fields) assert not missing_fields, f"Txn Fields not mapped: {missing_fields}" + + +def test_mismatched_langspec_txn_fields() -> None: + langspec_path = VCS_ROOT / "langspec.puya.json" + langspec = json.loads(langspec_path.read_text()) + arg_enums = langspec["arg_enums"] + all_txn_fields = {field["name"] for field in arg_enums["txn"]} + txn_array_fields = {field["name"] for field in arg_enums["txna"]} + txn_single_fields = all_txn_fields - txn_array_fields + inner_txn_fields = {field["name"] for field in arg_enums["itxn_field"]} + + assert not _set_difference( + all_txn_fields, [f.immediate for f in TXN_FIELDS] + ), "txn field mismatch" + + assert not _set_difference( + txn_single_fields, [f.immediate for f in TXN_FIELDS if not f.is_array] + ), "single txn field mismatch" + + assert not _set_difference( + txn_array_fields, [f.immediate for f in TXN_FIELDS if f.is_array] + ), "array txn field mismatch" + + assert not _set_difference( + inner_txn_fields, [f.immediate for f in TXN_FIELDS if f.is_inner_param] + ), "inner txn field mismatch" + + +def _set_difference(expected: set[str], actual: list[str]) -> list[str]: + return list(expected.symmetric_difference(actual))