Argument at index 0 of subroutine call is not a PyTeal expression: my_field

Hi Community,

I am trying to save space by creating a subroutine. I have the same logic applicable to many fields.

Here my subroutine:

    @Subroutine(TealType.bytes)
    def update_contracts_fields(field):
        saved_field = App.globalGet(Bytes(field))
        saved_seller_pub = App.globalGet(Bytes(SELLER_PUB))
        saved_buyer_pub = App.globalGet(Bytes(BUYER_PUB))

        logic = Seq(
            Assert(App.globalGet(Bytes(COMMITMENT_STATE)) != Bytes(COMM_STATE_EFFECTIVE)),
            # Cond(
            #
            # ),
            Cond(
                [  # if currently set to nothing
                    saved_field == Bytes(""),
                    Seq(  # first input provided by buyer
                        Assert(Txn.sender() == saved_buyer_pub),
                        App.globalPut(Bytes(field), Txn.application_args[1]),
                    )
                ],  # if same value as existing, skips
                [saved_field == Txn.application_args[1], Approve()],
                [  # if currently set to something the change must be attested
                    saved_field != Txn.application_args[1],
                    Seq(
                        Cond(  # if sender is the seller we remove the signature of the buyer, and vice versa
                            [Txn.sender() == saved_seller_pub, App.globalPut(Bytes(SIGNED_BY_BUYER), Bytes(""))],
                            [Txn.sender() == saved_buyer_pub, App.globalPut(Bytes(SIGNED_BY_SELLER), Bytes(""))]
                        ),  # then we can update the value
                        App.globalPut(Bytes(field), Txn.application_args[1])
                    )
                ]
            ),
        )

        return logic

I am trying then o use it as follows:

FIELD_TO_UPDATE = "my_field"

def noop_update_field():
     return Seq(update_contracts_fields(FIELD_TO_UPDATE))

And then I get the error in the title.

What am I doing wrong?

Thanks in advance

The argument of a subroutine should by a PyTEAL type.
In your case, you should call

update_contracts_fields(Bytes(FIELD_TO_UPDATE))

and in your subroutine, you should use directly field, instead of Bytes(field).

Thank you @fabrice, I did as you said and had another issue, it was expecting a TealType.none in the subroutine declaration.

I have fixed that and now it tells me that

pyteal.TealInputError: Subroutine function does not return a PyTeal expression. Got type <class 'tuple'>

I see examples of subroutines returning a logic like mine at Control Flow — PyTeal documentation

So what am i doing wrong now?

Thank you
Luca

Can you show a minimum example with the issue (that people can run with python so they can see the exact issue)?
Can you compare with Control Flow — PyTeal documentation?

You need to return a PyTeal expression in the Python function. It looks like you are returning a Python tuple, something like return (aa, bb), which is not allowed.

Hi @fabrice,

The code has not changed apart from your recommendations above, the function returns a sequence like most examples at Control Flow — PyTeal documentation

I simplified the code now to try to narrow it to more simple logic but still:

@Subroutine(TealType.none)
    def update_contracts_fields(field):
        saved_field = App.globalGet(field) 
        logic = Seq(Cond(
                [  # if currently set to nothing
                    saved_field == Bytes(""),
                    App.globalPut(field, Txn.application_args[1]),

                ],
                [  # if currently set to something the change must be attested
                    saved_field != Txn.application_args[1],
                        App.globalPut(field, Txn.application_args[1])
                ]
            ), Approve())

        return logic

I tried removing the Seq() and I have other subroutines that do work returning a Cond() but here is get this error that I am returning a tuple.

Here the full error if it is of any help

Traceback (most recent call last):
  File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/contractsvenv/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 3369, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-5-0f28285fdfe3>", line 1, in <cell line: 1>
    approval_program_teal = approval_program()
  File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/algorand_src/contract.py", line 453, in approval_program
    return compileTeal(program, Mode.Application, version=5)
  File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/contractsvenv/lib/python3.9/site-packages/pyteal/compiler/compiler.py", line 211, in compileTeal
    compileSubroutine(
  File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/contractsvenv/lib/python3.9/site-packages/pyteal/compiler/compiler.py", line 158, in compileSubroutine
    subroutine.getDeclaration(),
  File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/contractsvenv/lib/python3.9/site-packages/pyteal/ast/subroutine.py", line 60, in getDeclaration
    self.declaration = evaluateSubroutine(self)
  File "/Users/luca/Library/Mobile Documents/com~apple~CloudDocs/FDT VM/code/contractsvenv/lib/python3.9/site-packages/pyteal/ast/subroutine.py", line 219, in evaluateSubroutine
    raise TealInputError(
pyteal.TealInputError: Subroutine function does not return a PyTeal expression. Got type <class 'tuple'>

I am starting to think that is because dynamic logic cannot be used in subroutines