Inner Transaction Comprehension
Video Tutorial
Compiling Contracts
Compile contracts with:
algokit compile py filename.py
Generate Two Accounts
Create two accounts and add their private keys to your .env
file.
from algosdk.account import generate_account
private_key, address = generate_account()
print(address)
Generate One Asset
Create one asset and place its ID in your .env
file.
Note: Remember the account that owns the asset, as it will be used for asset transfers later.
from algosdk.transaction import AssetCreateTxn, wait_for_confirmation
from algosdk.v2client.algod import AlgodClient
from algosdk.account import address_from_private_key
import os
from dotenv import load_dotenv
load_dotenv()
algod_token = os.getenv('algod_token')
algod_server = os.getenv('algod_server')
algod_client = AlgodClient(algod_token, algod_server)
private_key = os.getenv('private_key')
address = address_from_private_key(private_key)
params = algod_client.suggested_params()
asset_create_txn = AssetCreateTxn(
sender=address,
sp=params,
total=10,
decimals=0,
default_frozen=False,
manager=address,
reserve=address,
asset_name = 'Test Asset One',
unit_name= 'TEST#1',
)
signed_asset_create_txn = asset_create_txn.sign(private_key)
tx_id = algod_client.send_transaction(signed_asset_create_txn)
print(tx_id)
wait_for_confirmation(algod_client, tx_id)
tx_info = algod_client.pending_transaction_info(tx_id)
print(tx_info)
Launching Contracts
Note: Adjust approval and clear teal filenames, as well as global/local states, as needed.
In this tutorial, we use a second contract, SecondApp
, which has 1 local state uint
.
from algosdk.transaction import ApplicationCreateTxn, StateSchema, OnComplete, wait_for_confirmation, PaymentTxn
from algosdk.account import address_from_private_key
from algosdk.v2client.algod import AlgodClient
from algosdk import logic
from dotenv import load_dotenv
import base64
import os
load_dotenv()
node_token = os.getenv('algod_token')
node_server = os.getenv('algod_server')
algod_client = AlgodClient(node_token, node_server)
private_key = os.getenv('private_key')
address = address_from_private_key(private_key)
params = algod_client.suggested_params()
approval_teal_file_name = 'TransactionComp.approval.teal'
clear_teal_file_name = 'TransactionComp.clear.teal'
with open(f'./{approval_teal_file_name}', 'r') as f:
approval_teal_source = f.read()
with open(f'{clear_teal_file_name}', 'r') as f:
clear_teal_source = f.read()
approval_result = algod_client.compile(approval_teal_source)
approval_program = base64.b64decode(approval_result['result'])
clear_result = algod_client.compile(clear_teal_source)
clear_program = base64.b64decode(clear_result['result'])
global_schema = StateSchema(num_uints=0, num_byte_slices=0)
local_schema = StateSchema(num_uints=0, num_byte_slices=0)
txn = ApplicationCreateTxn(
sender = address,
sp = params,
on_complete=OnComplete.NoOpOC,
approval_program=approval_program,
clear_program=clear_program,
global_schema=global_schema,
local_schema=local_schema,
)
signed_txn = txn.sign(private_key)
try:
txid = algod_client.send_transaction(signed_txn)
except Exception as e:
print(e)
print(f'Tx ID: {txid}')
wait_for_confirmation(algod_client, txid)
tx_info = algod_client.pending_transaction_info(txid)
print(f'App ID: {tx_info['application-index']}')
app_address = logic.get_application_address(tx_info['application-index'])
print(f'Application Address: {app_address}')
activate_contract = PaymentTxn(
sender = address,
sp = params,
receiver = app_address,
amt = 100_000
)
signed_activation = activate_contract.sign(private_key)
activation_tx = algod_client.send_transaction(signed_activation)
print(f'MBR For Contract to be Active Account Funded: {activation_tx}')
Inner Transaction Comprehension (ITXN and abi_calls)
Inner Txn with itxn Class
from algopy import ARC4Contract, UInt64, itxn, Global
from algopy.arc4 import abimethod
class TransactionComp(ARC4Contract):
def __init__(self) -> None:
pass
@abimethod
def inner_txn_comprehension(self) -> tuple[UInt64, UInt64, UInt64]:
asset_config_txn = itxn.AssetConfig(
total=1,
unit_name="TEST#1",
asset_name="TEST ASSET ONE",
decimals=0,
default_frozen=False,
manager=Global.current_application_address,
reserve=Global.current_application_address,
fee=Global.min_txn_fee,
).submit()
asset_config_txn_2 = itxn.AssetConfig(
total=1,
unit_name="TEST#2",
asset_name="TEST ASSET TWO",
decimals=0,
default_frozen=False,
manager=Global.current_application_address,
reserve=Global.current_application_address,
fee=Global.min_txn_fee,
)
asset_config_txn_3 = itxn.AssetConfig(
total=1,
unit_name="TEST#3",
asset_name="TEST ASSET THREE",
decimals=0,
default_frozen=False,
manager=Global.current_application_address,
reserve=Global.current_application_address,
fee=Global.min_txn_fee,
)
submit_tx_1, submit_tx_2 = itxn.submit_txns(asset_config_txn_2, asset_config_txn_3)
return asset_config_txn.created_asset.id, submit_tx_1.created_asset.id, submit_tx_2.created_asset.id
interact_with_contract_2.py
Inner Txn with abi_call Class
Note: Deploy a second application and place the generated app ID in the new inner transaction method, inner_txn_two
.
from algopy import ARC4Contract, LocalState, Txn, UInt64, gtxn
from algopy.arc4 import abimethod
class MySecondContract(ARC4Contract):
def __init__(self) -> None:
self.opted_in = LocalState(UInt64)
@abimethod()
def return_nothing(self) -> None:
pass
@abimethod(allow_actions=['OptIn'])
def local_state_return_something(self,
payment_txn: gtxn.PaymentTransaction) -> UInt64:
self.opted_in[Txn.sender] = UInt64(1)
return UInt64(1)
Replace the second App ID in the contract below, compile the contract, and include the new app in the Foreign Assets Array.
from algopy import ARC4Contract, UInt64, itxn, Global, OnCompleteAction
from algopy.arc4 import abimethod, arc4_signature, abi_call
class TransactionComp(ARC4Contract):
def __init__(self) -> None:
pass
@abimethod
def inner_txn_two(self) -> UInt64:
method_signature = arc4_signature('return_nothing()void')
itxn.ApplicationCall(
app_id=727594507,
app_args=(method_signature,),
on_completion=OnCompleteAction.NoOp,
fee=Global.min_txn_fee
).submit()
result, txn = abi_call[UInt64](
'local_state_return_something',
app_id=727594507,
on_completion=OnCompleteAction.OptIn,
fee=Global.min_txn_fee
)
txn = abi_call(
'return_nothing',
app_id=727594507,
fee=Global.min_txn_fee
)
return result
from algokit_utils import ApplicationClient
from algosdk.v2client.algod import AlgodClient
from algosdk.atomic_transaction_composer import AccountTransactionSigner, AtomicTransactionComposer, TransactionWithSigner
from algosdk.transaction import PaymentTxn, AssetTransferTxn
from algosdk.account import address_from_private_key
from pathlib import Path
import os
from algosdk.util import algos_to_microalgos
from algosdk.abi import ABIType
from dotenv import load_dotenv
load_dotenv()
algod_token = os.getenv('algod_token')
algod_server = os.getenv('algod_server')
algod_client = AlgodClient(algod_token, algod_server)
path = Path(__file__).parent / './TransactionComp.arc32.json'
app_id = int(os.getenv('app_id'))
private_key = os.getenv('private_key')
signer = AccountTransactionSigner(private_key)
address = address_from_private_key(private_key)
params = algod_client.suggested_params()
app_client = ApplicationClient(
algod_client=algod_client,
app_spec=path,
app_id=app_id,
signer=signer,
sender=address,
suggested_params=params,
)
atc = AtomicTransactionComposer()
#asset_id = 723609532
#arbitrary_account = 'MXOT5NO6DVCGIS22AWEP7N5WD72RSV6QJG4OWGDOTEH3DQKCG4R4WLLMR4'
#app_client.compose_call(atc, call_abi_method='txn_comprehension', transaction_parameters={'accounts': [arbitrary_account], 'foreign_assets': [asset_id]})
#app_client.compose_call(
# atc,
# call_abi_method='inner_txn_comprehension',
#)
second_app = int(os.getenv('second_app_id'))
app_client.compose_call(
atc,
call_abi_method='inner_txn_two',
transaction_parameters={
'foreign_apps': [second_app]
}
)
result = atc.execute(algod_client, 2)
all_tx_ids = [result.abi_results[i].tx_id for i in range(len(result.abi_results))]
all_abi_results = [result.abi_results[i].return_value for i in range(len(result.abi_results))]
print(all_tx_ids)
print(all_abi_results)