Smart Contract Asset Transfer

Hello! I am trying to allow a wallet to periodically withdraw money from an escrow smart contract. The sc wallet is supplied with x amount of an asa and every time the users wallet calls the sc with an NoOp, it will transfer some of the assets from the sc wallet to the user wallet. I am currently using PyTeal to write the transfer asset code and I am running into some trouble where the code runs however there is no transaction from the sc wallet to the user wallet. Here is my code for the transaction:

# Sends specified withdrawal amount of an asset specified by assetID to the specified account.
@Subroutine(TealType.none)
def sendAssetsTo(assetID: Expr, account: Expr) -> Expr:
    asset_holding = AssetHolding.balance(
        Global.current_application_address(), assetID
    )
    return Seq(
        asset_holding,
        If(asset_holding.value() > App.globalGet(withdraw_amount_key)).Then(
            Seq(
                InnerTxnBuilder.Begin(),
                InnerTxnBuilder.SetFields(
                    {
                        TxnField.type_enum: TxnType.AssetTransfer,
                        TxnField.xfer_asset: assetID,
                        TxnField.asset_amount: App.globalGet(withdraw_amount_key),
                        TxnField.asset_receiver: account,
                        TxnField.sender: Global.current_application_address(),
                    }
                ),
                InnerTxnBuilder.Submit(),
                App.globalPut(last_withdrawal_time_key, Global.latest_timestamp()),
            )
        ),
    )

Is there anything that I am missing that is not allowing the sc to transfer funds? Thanks!

Welcome to Algorand!

To help us debug your issue:

  1. When you submit an application call that is supposed to trigger the inner transaction, is the transaction approved? Does it appear in the blockchain/on a blockexplorer?
  2. If yes, can you point out a transaction on TestNet?
  3. If no, can you provide the error message when submitting the transaction
  4. Did you also try to debug your smart contract call using tealdbg?
    Smart contract debugging - Algorand Developer Portal

Thanks for the welcome! Glad to be here :slight_smile:

The transaction appears to be approved. Here it the transaction on the testnet: Algorand Transaction. It looks like the code is running since I see an application global state delta in the transaction where I update last_withdrawal_time however the code right above it where I try to send transaction appears to have not done anything.

When I look at the app address here: Algorand Account I see the assets sent to it but nothing leaving it.

I have not set up the smart contract debugger yet! Thanks for the recommendation and let me get onto that.

If you look at the transaction via the indexer:

curl -s https://testnet.algoexplorerapi.io/idx2/v2/transactions/MF7U3WLTDP3FWQ2HTXJZMABMOHRNMTUQ7BBE67WJDYMCTSWJMQXQ | jq

(jq is jq, just used for pretty printing)
You see the inner transaction:

{
  "current-round": 17978991,
  "transaction": {
    "application-transaction": {
      "accounts": [],
      "application-args": [
        "d2l0aGRyYXc="
      ],
      "application-id": 45988869,
      "foreign-apps": [],
      "foreign-assets": [
        45988613
      ],
      "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": 17978845,
    "fee": 1000,
    "first-valid": 17978842,
    "genesis-hash": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
    "genesis-id": "testnet-v1.0",
    "global-state-delta": [
      {
        "key": "bGF0ZXN0X3dpdGhkcmF3YWxfdGltZQ==",
        "value": {
          "action": 2,
          "uint": 1637270760
        }
      }
    ],
    "id": "MF7U3WLTDP3FWQ2HTXJZMABMOHRNMTUQ7BBE67WJDYMCTSWJMQXQ",
    "inner-txns": [
      {
        "asset-transfer-transaction": {
          "amount": 1000,
          "asset-id": 45988613,
          "close-amount": 0,
          "receiver": "3CKUZSL2XW6JA5F72DSKZA7K6GXXVV7VPDLF3EYYCIZW3IIIXPJJHKKTQ4"
        },
        "close-rewards": 0,
        "closing-amount": 0,
        "confirmed-round": 17978845,
        "fee": 1000,
        "first-valid": 17978842,
        "intra-round-offset": 0,
        "last-valid": 17979842,
        "receiver-rewards": 0,
        "round-time": 1637270765,
        "sender": "4AJWYS65MMZQPDPTQ3CV5IXGNPNUD36T46V6XSNH2IHVWCQ45TZ73UUW24",
        "sender-rewards": 0,
        "tx-type": "axfer"
      }
    ],
    "intra-round-offset": 0,
    "last-valid": 17979842,
    "receiver-rewards": 0,
    "round-time": 1637270765,
    "sender": "3CKUZSL2XW6JA5F72DSKZA7K6GXXVV7VPDLF3EYYCIZW3IIIXPJJHKKTQ4",
    "sender-rewards": 0,
    "signature": {
      "sig": "TxAv9eUXzu5miAUoaOm2QRDDpRpfUYs1JMJk2CtzHR04XYtGPHNBhLBVmVu5YQjKBpJaL40hZEFGmCvf1MN/Cw=="
    },
    "tx-type": "appl"
  }
}

Algoexplorer indexer seems to have an issue with the two accounts.

But testnet.algoexplorer.io shows the proper balances (see Algorand Account - where the balance of the asset is 199,999.9 which shows 0.1 asset have been moved to Algorand Account)

Furthermore, PureStake indexer returns the correct balances:

$ curl -s -H "X-API-Key: B3SU4KcVKi94Jap2VXkK83xx38bsv95K5UZm2lab" https://testnet-algorand.api.purestake.io/idx2/v2/accounts/4AJWYS65MMZQPDPTQ3CV5IXGNPNUD36T46V6XSNH2IHVWCQ45TZ73UUW24 | jq
{
  "account": {
    "address": "4AJWYS65MMZQPDPTQ3CV5IXGNPNUD36T46V6XSNH2IHVWCQ45TZ73UUW24",
    "amount": 998000,
    "amount-without-pending-rewards": 998000,
    "assets": [
      {
        "amount": 1999999000,
        "asset-id": 45988613,
        "creator": "",
        "deleted": false,
        "is-frozen": false,
        "opted-in-at-round": 17978829
      }
    ],
    "created-at-round": 17978827,
    "deleted": false,
    "pending-rewards": 0,
    "reward-base": 27521,
    "rewards": 0,
    "round": 17979310,
    "status": "Offline"
  },
  "current-round": 17979310
}
$ curl -s -H "X-API-Key: B3SU4KcVKi94Jap2VXkK83xx38bsv95K5UZm2lab" https://testnet-algorand.api.purestake.io/idx2/v2/accounts/3CKUZSL2XW6JA5F72DSKZA7K6GXXVV7VPDLF3EYYCIZW3IIIXPJJHKKTQ4 | jq
{
  "account": {
    "address": "3CKUZSL2XW6JA5F72DSKZA7K6GXXVV7VPDLF3EYYCIZW3IIIXPJJHKKTQ4",
    "amount": 8993000,
    "amount-without-pending-rewards": 8993000,
    "apps-local-state": [
      {
        "deleted": false,
        "id": 45988869,
        "opted-in-at-round": 17978825,
        "schema": {
          "num-byte-slice": 0,
          "num-uint": 0
        }
      }
    ],
    "apps-total-schema": {
      "num-byte-slice": 1,
      "num-uint": 6
    },
    "assets": [
      {
        "amount": 99998000001000,
        "asset-id": 45988613,
        "creator": "",
        "deleted": false,
        "is-frozen": false,
        "opted-in-at-round": 17978786
      }
    ],
    "created-apps": [
      {
        "created-at-round": 17978823,
        "deleted": false,
        "id": 45988869,
        "params": {
          "approval-program": "BSADAQAEJgcUcmVjZWl2ZXJfYWRkcmVzc19rZXkIYXNzZXRfaWQLdW5sb2NrX3RpbWUTY29udHJhY3Rfc3RhcnRfdGltZQ93aXRoZHJhd19hbW91bnQWbGF0ZXN0X3dpdGhkcmF3YWxfdGltZQt0aW1lX3BlcmlvZDEYIxJAAKAxGSMSQABBMRkiEkAAMjEZgQUSQAAQMRmBAhIxGSQSEUAAAQAjQzEAKGQSKmQyBw4QRClkKGSIAJkoZIgAtSJDMQAoZBJEIkM2GgCABXNldHVwEkAALzYaAIAId2l0aGRyYXcSQAABADEAKGQSMgcrZA8QiADOiADBDRBEKWQoZIgAhCJDMQAoZBIyBypkDBBEsSSyEClkshEyCrIUsyJDMQA2GgESRCk2GgAXZyg2GgFnKjYaAhdnJwY2GgMXZys2GgQXZycENhoFF2cnBSNnIkM1ATUAMgo0AHAANQI1AzQCQQANsSSyEDQAshE0AbIVs4k1BDIKYCMTQQAJsSKyEDQEsgmziTUGNQUyCjQFcAA1BzUINAgnBGQNQQAbsSSyEDQFshEnBGSyEjQGshQyCrIAsycFMgdniTIHK2QJJwZkGIkyBycFZAmJ",
          "clear-state-program": "BYEBQw==",
          "creator": "3CKUZSL2XW6JA5F72DSKZA7K6GXXVV7VPDLF3EYYCIZW3IIIXPJJHKKTQ4",
          "global-state": [
            {
              "key": "bGF0ZXN0X3dpdGhkcmF3YWxfdGltZQ==",
              "value": {
                "bytes": "",
                "type": 2,
                "uint": 1637270760
              }
            },
            {
              "key": "cmVjZWl2ZXJfYWRkcmVzc19rZXk=",
              "value": {
                "bytes": "2JVMyXq9vJB0v9DkrIPq8a961/V41l2TGBIzbaEIu9I=",
                "type": 1,
                "uint": 0
              }
            },
            {
              "key": "dGltZV9wZXJpb2Q=",
              "value": {
                "bytes": "",
                "type": 2,
                "uint": 60
              }
            },
            {
              "key": "dW5sb2NrX3RpbWU=",
              "value": {
                "bytes": "",
                "type": 2,
                "uint": 1637271000
              }
            },
            {
              "key": "d2l0aGRyYXdfYW1vdW50",
              "value": {
                "bytes": "",
                "type": 2,
                "uint": 1000
              }
            },
            {
              "key": "YXNzZXRfaWQ=",
              "value": {
                "bytes": "",
                "type": 2,
                "uint": 45988613
              }
            },
            {
              "key": "Y29udHJhY3Rfc3RhcnRfdGltZQ==",
              "value": {
                "bytes": "",
                "type": 2,
                "uint": 1637206981
              }
            }
          ],
          "global-state-schema": {
            "num-byte-slice": 1,
            "num-uint": 6
          },
          "local-state-schema": {
            "num-byte-slice": 0,
            "num-uint": 0
          }
        }
      }
    ],
    "created-assets": [
      {
        "created-at-round": 17978786,
        "deleted": false,
        "index": 45988613,
        "params": {
          "creator": "3CKUZSL2XW6JA5F72DSKZA7K6GXXVV7VPDLF3EYYCIZW3IIIXPJJHKKTQ4",
          "decimals": 4,
          "default-frozen": false,
          "manager": "3CKUZSL2XW6JA5F72DSKZA7K6GXXVV7VPDLF3EYYCIZW3IIIXPJJHKKTQ4",
          "name": "DALVOR",
          "name-b64": "REFMVk9S",
          "reserve": "3CKUZSL2XW6JA5F72DSKZA7K6GXXVV7VPDLF3EYYCIZW3IIIXPJJHKKTQ4",
          "total": 100000000000000,
          "unit-name": "Dalvors",
          "unit-name-b64": "RGFsdm9ycw=="
        }
      }
    ],
    "created-at-round": 17978781,
    "deleted": false,
    "pending-rewards": 0,
    "reward-base": 27521,
    "rewards": 0,
    "round": 17979312,
    "sig-type": "sig",
    "status": "Offline"
  },
  "current-round": 17979312
}

This is most likely due to the issue fixed in indexer 2.6.5: Indexer 2.6.5 Release

Here is a bit more context for the application.

How I call the Subroutine:

sendAssetsTo(App.globalGet(asset_id_key), App.globalGet(receiver_address_key))

Here are the keys:

asset_id_key = Bytes("asset_id")
receiver_address_key = Bytes("receiver_address_key")

You can find the values in the application global state here! Algorand Application

We posted at the same time. Does my above post answer your question?

Note that 0.1 asset displayed by explorer = 1000 assets in base unit as you have 4 decimals.

Yep your post helped answer my question! Thank you so much for the help :slight_smile:

Is there a way I can check when the updated Indexer will be live?

algoexplorerapi.io is already fixed:

$ curl -s https://testnet.algoexplorerapi.io/idx2/v2/accounts/4AJWYS65MMZQPDPTQ3CV5IXGNPNUD36T46V6XSNH2IHVWCQ45TZ73UUW24| jq
{
  "account": {
    "address": "4AJWYS65MMZQPDPTQ3CV5IXGNPNUD36T46V6XSNH2IHVWCQ45TZ73UUW24",
    "amount": 997000,
    "amount-without-pending-rewards": 997000,
    "assets": [
      {
        "amount": 1999998000,
        "asset-id": 45988613,
        "creator": "",
        "deleted": false,
        "is-frozen": false,
        "opted-in-at-round": 17978829
      }
    ],
    "created-at-round": 17978827,
    "deleted": false,
    "pending-rewards": 0,
    "reward-base": 27521,
    "rewards": 0,
    "round": 17995376,
    "status": "Offline"
  },
  "current-round": 17995376
}
1 Like