How to access asset URL in PyTeal?

I’m writing a stateful contract that should approve a transaction group if its first element is an “asset transfer transaction” and the asset to be transferred has the url “test”. (The contract has some additional logic, but this is the part I don’t understand.)

I know that Gtxn[0].xfer_asset() contains the ID of the asset to be transferred. But how to get the url from this?

I know that Gtxn[0] has the attribute assets, but I don’t know what it represents. Gtxn[2].assets[0].url() == Bytes("test") gives me the error AttributeError: 'GtxnaExpr' object has no attribute 'url', which is fair enough because instances of the class GtxnaExpr don’t seem to have any attributes at all.

Txn.config_asset_url()
or
Gtxn[2].config_asset_url() == Bytes("test")

1 Like

I think only transactions of type TxnType.AssetConfig have the attribute config_asset_url(). My transaction is of type TxnType.AssetTransfer and doesn’t have that attribute.

You need to have the asset ID transferred in the first transaction to also be indicated as a “foreign asset” for the application call transaction. See Overview - Algorand Developer Portal

You can check it’s the correct asset using something like

Txn.assets[0] == Gtxn[0].xfer_asset()

(First [0] is because it’s the first foreign asset; second [0] is because you want to look at the asset of the first transaction.)

Then you can access the URL using:

AssetParam.url(Int(0))

(Int(0) is because it’s the first foreign asset.)
See
https://pyteal.readthedocs.io/en/latest/assets.html?highlight=asset#asset-parameters

Note: I haven’t tested the code above.

1 Like

The line Assert(AssetParam.url(Int(0)).value() == Bytes('test')) gives me the error pyteal.TealCompileError: Scratch slot load occurs before store. Any idea what that means and how it can be fixed?

See how to use AssetParm.url at the bottom of Asset Information — PyTeal documentation

# get the total number of units for Txn.assets[0]
# if the asset is invalid, exit with an error
assetURL = AssetParam.url(Int(0))
program = Seq([
    assetURL,
    Assert(assetURL.hasValue()),
    assetURL.value()
])
1 Like

Thanks, that works. Tragically, this does not seem to be supported in Signature mode. When I try to compile this code in signature mode I get the error pyteal.TealInputError: Op not supported in Signature mode: asset_params_get. Is there a way to get this functionality in Signature mode? I am aware of the possible workaround of creating a Stateful contract that makes these checks, but I was hoping to get away with only Signature mode.

No there is no way you can do that in Signature mode.
The reason is that TEAL scripts in Signature mode are evaluated when the transactions is received by the node and are not re-evaluated when a block is proposed.
This is to allow for higher performance.
But this means that in Signature mode, TEAL cannot access any data that may change between the time the transaction is submitted and the time the transaction is added to a block.

I see, that makes sense. Can the creator address be used in Signature mode? There is no risk of this changing. But I didn’t find any way to access that at all (in Signature or Application mode).

There is a risk changing: the asset may not exist when you submit the transaction, but then it exists when it’s in a block.

But actually, the current constraint is a bit stronger: in Signature mode, the only things that can be accessed are fields of the transactions in the group, and nothing from the ledger.