Child application deployment from parent application - General - Algorand

Child application deployment from parent application

post by elia on Oct 29, 2022

Hi everyone, I’m struggling a little with a problem regarding the creation of a child application from the parent application.

I’m currently using beaker and pyteal for my project.

Inside the application call transaction ParentApp.parent_app_call() I’m trying to deploy a child application with an InnerTxn.

The definition of the parent_app_call is the following:

@external(authorize=Authorize.only(Global.creator_address()))
    def parent_app_call(self,
        parent_arg1: abi.Uint64,
        parent_arg2: abi.String,
        parent_arg3: abi.Uint64,
        *,
        output: abi.Uint64 # child_app_id
    ):
        return Seq(
            Assert(self.parent_state.get() == Int(1), comment="must be in ## state"),
            InnerTxnBuilder.Begin(),
            InnerTxnBuilder.SetFields(
                {
                    TxnField.type_enum: TxnType.ApplicationCall,
                    TxnField.approval_program: self.child_app.approval.binary,
                    TxnField.clear_state_program: self.child_app.clear.binary,
                    TxnField.fee: Int(0),
                    TxnField.application_args: [
                            Global.creator_address(),
                            Global.current_application_address(),
                            Itob(parent_arg1.get()),
                            Itob(parent_arg3.get()),
                            parent_arg2.get()
                        ],
                }
            ),
            InnerTxnBuilder.Submit(),
            self.parent_state.set(Int(2)), # in ## phase
            output.set(InnerTxn.created_application_id())
        )

From the main I call parent_app_call as follows:

sp = creator_app_client.client.suggested_params()
sp.fee = sp.min_fee * 2
sp.flat_fee = True
result = creator_app_client.call(
    ParentApp.parent_app_call,
    parent_arg1=1,
    parent_arg2="string",
    parent_arg3=10,
    suggested_params=sp
)

The main executes without problems deploying the ParentApp and calling its methods, but parent_app_call is raising an error.

Traceback (most recent call last):
  File "/Users/usr1/Projects/Blockchain/Algorand/PyTealLearning/project/venv/lib/python3.10/site-packages/algosdk/v2client/algod.py", line 78, in algod_request
    resp = urlopen(req)
... 
algosdk.error.AlgodHTTPError: TransactionPool.Remember: transaction JL5X7K4ELISIYP5AJYFBU6F5JFMIDANL5NSSHSRQUJMD45JJ7OUQ: logic eval error: logic eval error: err opcode executed. Details: pc=186, opcodes===
bnz label3
err
label3:
. Details: pc=1337, opcodes=extract 2 0
itxn_field ApplicationArgs
itxn_submit

During handling of the above exception,...

goal app method --app-id 1 --method "parent_app_call(uint64,string,uint64)uint64" \
--from $ADDR --arg 1 --arg '"string"' --arg 10 \
--fee 2000 --dryrun-dump -o test.dr

Do you have any suggestions on how to tackle this problem? What am I missing?

post by fabrice on Nov 2, 2022

Have you tried to call directly the child application from the SDK/goal?

Does it work? Note also that if you’re using ABI for the inputs of the child application call, then:

            InnerTxnBuilder.SetFields(
                {
                    TxnField.type_enum: TxnType.ApplicationCall,
                    TxnField.approval_program: self.child_app.approval.binary,
                    TxnField.clear_state_program: self.child_app.clear.binary,
                    TxnField.fee: Int(0),
                    TxnField.application_args: [
                            Global.creator_address(),
                            Global.current_application_address(),
                            Itob(parent_arg1.get()),
                            Itob(parent_arg3.get()),
                            parent_arg2.get()
                        ],
                }
            ),

is most likely incorrect: arguments are most likely not encoded as expected.

post by elia on Nov 3, 2022

Thanks for your answer @fabrice.

The child application is correctly deployed as a standalone using its create method. I also think encoding the arguments on the inner transaction could be the problem.

What would be the correct way to invoke the create method using InnerTxnBuilder.MethodCall?

InnerTxnBuilder.Begin(),
InnerTxnBuilder.MethodCall(
    app_id=Int(0),
    method_signature="create(address,address,uint64,uint64,string)void",
    args=[
        Global.creator_address(),
        Global.current_application_address(),
        parent_arg1,
        parent_arg3,
        parent_arg2
    ],
    extra_fields={
        TxnField.approval_program: self.child_app.approval.binary,
        TxnField.clear_state_program: self.child_app.clear.binary,
        TxnField.fee: Int(0)
    }
),
InnerTxnBuilder.Submit(),

but app_id=Int(0) is not an acceptable app reference:

beaker.client.logic_error.LogicException: Txn XSZKJYKCHVXFOPSWUPNWDOAUXC3Z4A3BP6SQ56VTJFUGZ2E6A5MA had error 'invalid App reference 0' at PC 858 and Source Line 418:
    assert
    itxn_begin
    pushint 6 // appl
    itxn_field TypeEnum
    intc_0 // 0
    itxn_field ApplicationID                <-- Error

post by Ben on Nov 3, 2022

The MethodCall function will try to submit an app call to the app id passed. Since 0 is not a valid app id its failing here. You’ll have to use the normal way of executing inner transactions with SetField or Execute to call an ABI method during create until something is changed in pyteal.

post by Ben on Nov 4, 2022

Great! In the latest beaker you can get most of those fields from the Precompile object itself.