TealInputError: Argument is not a PyTeal expression: (<pyteal.BinaryExpr object at 0x000002695E9A4CD0>,)

TealInputError: Argument is not a PyTeal expression: (<pyteal.BinaryExpr object at 0x7fe7e08b8950>,)
"""Atomic Swap"""

secret = Bytes("base32", "2323232323232323")
timeout = 3000

def htlc(
    tmpl_seller = alice,
    tmpl_buyer = bob,
    tmpl_fee = 1000,
    tmpl_secret = secret,
    tmpl_hash_fn = Sha256,
    tmpl_timeout = timeout,

    fee_cond = Txn.fee() < Int(tmpl_fee),

    safety_cond = And(
        Txn.type_enum() == TxnType.Payment,
        Txn.close_remainder_to() == Global.zero_address(),
        Txn.rekey_to() == Global.zero_address(),

    recv_cond = And(Txn.receiver() == tmpl_seller, tmpl_hash_fn(Arg(0)) == tmpl_secret)
    esc_cond = And(Txn.receiver() == tmpl_buyer, Txn.first_valid() > Int(tmpl_timeout))

    return And(fee_cond, 
               Or(recv_cond, esc_cond))

if __name__ == "__main__":
    print(compileTeal(htlc(), mode = Mode.Signature, version = 2))

Welcome to Algorand!

You have a typo:

    fee_cond = Txn.fee() < Int(tmpl_fee),

ends with a comma and hence fee_cond is actually a tuple, which is the issue.

PS: I’ve modified your post so that the code is between triple back quotes ``` to facilitate reading the code.

PS2: It is in general better to include the full Python error. Here, we would see that the error is actually linked with return And(fee_cond, from which it is much easier to see that the error stems from the comma.

PS3: This code is based on a very old version of TEAL/PyTEAL. In addition it is a smart signatures. Nowadays, you would most likely not use smart signatures but instead of smart contracts for most cases on Algorand. For a pure HTLC, it still may make sense to use smart signatures, but often you may want to go beyond a pure HTLC. In addition, nowadays, you should rather use Assert. See PyTeal opcodes cost (Asserts vs And) - #2 by fabrice