Smart contract to transfer asset to another address

I want to create a simple smart contract (stateless or stateful) that sends an asset to another address but I didn’t find any sample for it. I want to call the deployed app from a client application.
Could you please guide me on how to implement this? Is there an example code for something like this?

See

for the TEAL code (the code of the smart contract)

A full example for payment transactions: https://developer.algorand.org/tutorials/creating-a-license-manager-contract-utilizing-pyteal-and-inner-transactions/?from_query=inner%20transaction

This can easily be adapted for asset transactions.

1 Like

Thank you, I used this example.
My issue is that the app call runs successfully but no asset transfer happens.
Now i just have one transaction for call app with ApplicationNoOpTxn,I wonder if I need to perform a group transaction (one for app call and another for asset transfer inner transaction)? if yes, how should I do that?(the example used goal but i want to implement it in pyteal code)

here is the app call transaction(I rekeyed the wallet address, which holds assets, to the application address. Which allows the application to transfer the assets.):
https://testnet.algoexplorer.io/tx/ZQTLARZGYY7UKG6YUENDPX3JX6XDVPGZR7RECVOOVXMDOSTEPO5A

Here is the code where i fill fields and also asset transfer subroutine:

@Subroutine(TealType.uint64)
def doTransfer():
    return Seq(
        inner_asset_transfer(Int(48519365),
                             Int(1),
                             Txn.accounts[1],
                             Txn.accounts[2]),
        Int(1))

@Subroutine(TealType.none)
def inner_asset_transfer(asset_id: TealType.uint64, asset_amount: TealType.uint64, asset_sender: TealType.bytes,
                         asset_receiver: TealType.bytes) -> Expr:
    return Seq([
        InnerTxnBuilder.Begin(),
        InnerTxnBuilder.SetFields({
            TxnField.type_enum: TxnType.AssetTransfer,
            TxnField.xfer_asset: asset_id,
            TxnField.asset_sender: asset_sender,
            TxnField.asset_amount: asset_amount,
            TxnField.asset_receiver: asset_receiver,
            TxnField.fee: Int(1000),
        }),
        InnerTxnBuilder.Submit()
    ])
    program = Cond(
        [Txn.application_id() == Int(0), on_creation],
        [Txn.on_completion() == OnComplete.OptIn, handle_optin],
        [Txn.on_completion() == OnComplete.CloseOut, handle_closeout],
        [Txn.on_completion() == OnComplete.UpdateApplication, handle_updateapp],
        [Txn.on_completion() == OnComplete.DeleteApplication, handle_deleteapp],
        [Txn.on_completion() == OnComplete.NoOp, Return(doTransferFunc)],     
    )

Here is where i pass the arguments to the transaction (call app):

        assets = [48519365]
        txn = transaction.ApplicationNoOpTxn(sender, params, index, app_args, accounts, None, assets)

Thanks

Actually your smart contract worked and the inner transaction happened!
Just algoexplorer.io does not show inner transactions right now.

But you can see them using the indexer API:
(I’m using jq just for nicer JSON formatting)

$ curl -s https://testnet.algoexplorerapi.io/idx2/v2/transactions/ZQTLARZGYY7UKG6YUENDPX3JX6XDVPGZR7RECVOOVXMDOSTEPO5A | jq
{
  "current-round": 18260976,
  "transaction": {
    "application-transaction": {
      "accounts": [
        "NQYDEZTWV4MNRZBI3DLWKX5C576PWWRA2ZFHCFHBUYZYBOCFCJB6BASBPQ",
        "CIBXLVQ4EI6I2UG57RR3FW72MI6WSVCWLTDJW2GBSKOXJ34ZQGK4KC54C4"
      ],
      "application-args": [
        "QWRk"
      ],
      "application-id": 48519967,
      "foreign-apps": [],
      "foreign-assets": [
        48519365
      ],
      "global-state-schema": {
        "num-byte-slice": 0,
        "num-uint": 0
      },
      "local-state-schema": {
        "num-byte-slice": 0,
        "num-uint": 0
      },
      "on-completion": "noop"
    },
    "close-rewards": 0,
    "closing-amount": 0,
    "confirmed-round": 18233308,
    "fee": 1000,
    "first-valid": 18233306,
    "genesis-hash": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
    "genesis-id": "testnet-v1.0",
    "id": "ZQTLARZGYY7UKG6YUENDPX3JX6XDVPGZR7RECVOOVXMDOSTEPO5A",
    "inner-txns": [
      {
        "asset-transfer-transaction": {
          "amount": 1,
          "asset-id": 48519365,
          "close-amount": 0,
          "receiver": "CIBXLVQ4EI6I2UG57RR3FW72MI6WSVCWLTDJW2GBSKOXJ34ZQGK4KC54C4",
          "sender": "NQYDEZTWV4MNRZBI3DLWKX5C576PWWRA2ZFHCFHBUYZYBOCFCJB6BASBPQ"
        },
        "close-rewards": 0,
        "closing-amount": 0,
        "confirmed-round": 18233308,
        "fee": 1000,
        "first-valid": 18233306,
        "intra-round-offset": 22,
        "last-valid": 18234306,
        "receiver-rewards": 0,
        "round-time": 1638350421,
        "sender": "CM4DTUWOFJ7YS5WLPN5GN3VC4A7DTSER65X5R5GRBRY6G43K3MNY26A7NY",
        "sender-rewards": 0,
        "tx-type": "axfer"
      }
    ],
    "intra-round-offset": 22,
    "last-valid": 18234306,
    "receiver-rewards": 0,
    "round-time": 1638350421,
    "sender": "X54JZH3JWESRP5DIPF6H6TEOURJUDMLFTWOKZY6T4V55L2VIA3BWRZCEJU",
    "sender-rewards": 0,
    "signature": {
      "sig": "LbJqL0cYhiZbVBzGdXMZaiyjoZtiOTJWisrIVzJb4CvYH8/hnYBrEm1i1Mq2xuGp0L6iFCIrC062TXRIrSvcAQ=="
    },
    "tx-type": "appl"
  }
}