algorand / pyteal

Algorand Smart Contracts in Python
https://pyteal.readthedocs.io
MIT License
285 stars 131 forks source link

Document AssetHolding & AssetParam #39

Closed jasonpaulos closed 3 years ago

jasonpaulos commented 3 years ago

Summary

Currently the examples and documentation don't show how to use AssetHolding and AssetParam.

Scope

Add a section to the documentation that shows how to properly use these expressions.

Urgency

This is a nice to have improvement.

Lumene98 commented 3 years ago

Hi @jasonpaulos, did you add this or can I just know the use? Does it refer to ContractAccount assets?

jasonpaulos commented 3 years ago

Hi @Lumene98, I haven't added much documentation about AssetHolding or AssetParam yet, but I hope to do so soon. These objects are used to look up information about Algorand Standard Assets (ASAs) in TEAL programs.

In the meantime, there is basic documentation generated from code comments that might be helpful.

Lumene98 commented 3 years ago

Hi @Lumene98, I haven't added much documentation about AssetHolding or AssetParam yet, but I hope to do so soon. These objects are used to look up information about assets in TEAL programs.

In the meantime, there is basic documentation generated from code comments that might be helpful.

* AssetHolding is used to get an account's balance record for an asset (quantity and frozen status). Docs: https://pyteal.readthedocs.io/en/stable/api.html#pyteal.AssetHolding

* AssetParam is used to get information about a specific asset, such as name, total quantity, etc. Docs: https://pyteal.readthedocs.io/en/stable/api.html#pyteal.AssetParam

Thanks

Lumene98 commented 3 years ago

AssetHolding.balance(Int(1), asset_id).value() @jasonpaulos Is this the correct use?

jasonpaulos commented 3 years ago

Hi @Lumene98, the correct use is actually:

asset_id = Int(...)
asset_balance = AssetHolding.balance(Int(1), asset_id) # asset_balance is a MaybeValue: https://pyteal.readthedocs.io/en/stable/api.html#pyteal.MaybeValue
app = Seq([
    asset_balance, # this is required to load the asset balance
    If(asset_balance.hasValue(),
        Return(asset_balance.value()), # that user holds the asset and has a balance
        Err(), # that user does not hold the asset, do something else
    )
])
Lumene98 commented 3 years ago

Hi @Lumene98, the correct use is actually:

asset_id = Int(...)
asset_balance = AssetHolding.balance(Int(1), asset_id) # asset_balance is a MaybeValue: https://pyteal.readthedocs.io/en/stable/api.html#pyteal.MaybeValue
app = Seq([
    asset_balance, # this is required to load the asset balance
    If(asset_balance.hasValue(),
        Return(asset_balance.value()), # that user holds the asset and has a balance
        Err(), # that user does not hold the asset, do something else
    )
])

I tried it but I'm not getting any results, so I had to adapt it to my code and the result is something like this

on_create = Seq(
        [
            asset_balance,
            Assert(
                asset_balance.hasValue())
            ),
            App.globalPut(Bytes("total_suppy"), asset_balance.value()),
            App.globalPut(Bytes("dispenser_holding"), asset_balance.value()),
            Int(1),
        ]
    )

And I get a TEAL runtime error opcode, this is the actual holding of the account I'm testing

Asset Holding Info: {
  amount: 10000000000,
  'asset-id': 82,
  creator: 'WHVQXVVCQAD7WX3HHFKNVUL3MOANX3BYXXMEEJEJWOZNRXJNTN7LTNPSTY',
  'is-frozen': false
}
jasonpaulos commented 3 years ago

I don't see any issues with that code. How are you testing this?

Lumene98 commented 3 years ago

I'm using algorand builder, but I'm not sure it is related to that because for the others parameters in the global state it's working properly

Lumene98 commented 3 years ago

@jasonpaulos Is there a way to avoid hard coding the asset id in the contract? for example, in this code(which doesn't work because the stack variable(asset_balance) is not defined before the on_create so basically what I want to do it to get the asset holdings during creation, the error I get is Length of stack is less than min length required for current op at line 29 The line is the store 1 after

int 1
txna ApplicationArgs 1
btoi
asset_holding_get AssetBalance
store 0
#Txn.application_args[1] => asset id
asset_balance = AssetHolding.balance(Int(1), Btoi(Txn.application_args[1])) 

on_create = Seq(
        [
            asset_balance,
            Assert(
                And(
                    Txn.application_args.length() == Int(2),
                    asset_balance.hasValue(),
                )
            ),
            App.globalPut(
                Bytes("dispenser_holding"),
                asset_balance.value(),
            ),
            Int(1),
        ]
    )

Questo invece è il codice teal generato:

#pragma version 2
txn ApplicationID
int 0
==
bnz l0
txn OnCompletion
int CloseOut
==
bnz l1
txn OnCompletion
int OptIn
==
bnz l2
err
l0:
int 1
txna ApplicationArgs 1
btoi
asset_holding_get AssetBalance
store 0
#The error is on this line
store 1
txn NumAppArgs
int 2
==
load 0
&&
bnz l6
err
l6:
byte "total_suppy"
load 1
app_global_put
byte "dispenser_holding"
load 1
app_global_put
byte "asset_id"
txna ApplicationArgs 1
app_global_put
byte "interest_index"
txna ApplicationArgs 0
btoi
app_global_put
int 1
b l5
l1:
int 1
b l5
l2:
int 0
byte "balance"
int 0
app_local_put
int 1
b l5
fabrice102 commented 3 years ago

@Lumene98, I have tried to run the program in a fresh sandbox and I do not encounter the error you are encountering. Can you give use the exact steps you used to reproduce it on a minimal example that still has the issue? Can you also check you are using the latest version of all the tools you are using (SDK or goal)?

You may also want to consider using the TEAL debugger to see the state of the stack: https://developer.algorand.org/docs/features/asc1/debugging/

Additional information:

int 1
txna ApplicationArgs 1
btoi

should load properly the two arguments of the stack for asset_holding_get (see https://developer.algorand.org/docs/reference/teal/opcodes/#asset_holding_get)

And then asset_holding_get push back two results on the stack, so

store 0
store 1

should work without issue.

Lumene98 commented 3 years ago

@Lumene98, I have tried to run the program in a fresh sandbox and I do not encounter the error you are encountering. Can you give use the exact steps you used to reproduce it on a minimal example that still has the issue? Can you also check you are using the latest version of all the tools you are using (SDK or goal)?

You may also want to consider using the TEAL debugger to see the state of the stack: https://developer.algorand.org/docs/features/asc1/debugging/

Additional information:

int 1
txna ApplicationArgs 1
btoi

should load properly the two arguments of the stack for asset_holding_get (see https://developer.algorand.org/docs/reference/teal/opcodes/#asset_holding_get)

And then asset_holding_get push back two results on the stack, so

store 0
store 1

should work without issue.

Thanks for the response, I'm pretty sure it's related to algorand-builder runtime. The issue is not pyteal I think because with sandbox it does work properly.