Hi all! I’m working on an application that requires me to issue assets (ASAs) that serve as a placeholder for an object of changing state. Specifically, a single ASA should be able to represent its dynamic “weight” as it changes over time. Is there a way for me to store the current state attributes as well as modify them over the life cycle of the ASA?
MetaDataHash seemed like an attractive way to record the ASA state. Yet, the documentation seems to indicate that it can only be modified upon creation. Can the ManagerAddr modify the MetaDataHash of an ASA after creation?
If this is not the case, any ideas for other ways to dynamically store metadata/state on the ASA? Right now it seems like the only way is to destroy the changing ASA and recreate it with the desired attributes – which is more computationally intensive than a modification.
there is no such a way to have a “stateful ASA”, this means that its properties are static and defined upon creation. The only properties you can modify in ASAs are the management addresses (Manager, Freeze, Clawback and Reserve).
What about using Stateful ASC1 instead? Or also, you can have a hybrid implementation pairing ASA and Stateful ASC1 so that you can:
Benefit from ASA for the token behaviour (transfers, preventing double spendings, etc.)
Benefit from ASC1 to dynamically store ASA’s properties, building your own rules to handle ASA’s state changes, like: let ASA’s weight change if and only if…
Thank you for your response @cusma. The token behavior is definitely essential. This seems to leave us with 2 options to “modify” a given token:
Using a coupled ASA and a stateful ASC1, as you suggested, storing the state of the token in the smart contract. In this case, the use of a stateful contract for a single field consumes valuable space on the chain. Is there by any chance a reference sample app where an analogous “coupling” mechanism (i.e. each ASA is mapped to a unique stateful ASC1) has been implemented?
Store the weight as metadata. When a change in weight is needed, destroy the outdated token and recreate it with the new weight. I believe that this could be pulled off in a stateless ASC1 (contract account) as long as the token fields (metadata) can be read/parsed from within the contract. In this case, the destruction and recreation of the token seems more computationally wasteful.
I should note that the weight update of the token will happen as part of an atomic transfer — not sure if this ought to inform the decision of whether to rely on a stateless or a stateful ASC1 in order to optimize performance.
It might come down to the following: would the space required to maintain a stateful ASC1 be more operational expensive than maintaining stateless ones?
AlgoRealm is a solution in which I showed how you can combine ASA with Stateful and Stateless ASC1 to extend ASA properties to embed royalties into a NFT. This specific example makes use of a Sateful ASC1 to track dynamic properties of two NFTs (latest amount of donation and the nickname of the donor).
This approach could be not so smooth, due to the fact that you should always return the whole ASA supply to its Creator first and then execute the Asset Destroy transaction as Asset Manager. Also, for each new ASA users must opt-in again.
You can assign the Manager Address to a Stateless Contract Account in order to approve / reject the Asset Destroy transaction based on some logical conditions. But this approach can not rely just on a Stateless ASC1 because if you intend to parse the Asset MetaDataHash field, that is an information stored on the blockchain state, you need to use the asset_param_get opcode that can only by used into Sateful ASC1. So a pure Stateless ASC1 is not a god fit for your requirements.
The AlgoRealm solution mentioned above works exactly in this way: it handles NFT update into Atomic Transfers that implement a more complex group transaction that includes Application Call, NFT Asset Transfers and Royalties Payments.
Initialise a Stateless Contract Account takes just 0.1 ALGO for the minimum balance (as any other Account on Algorand) and would require additional 0.1 ALGO for minimum balance for each ASA opt-in or additional costs if the Contract Account need to opt-in an Application.
On the other hand, the minimum balance of the Application Creator and Users depends on the number and type of variables used by the Sateful ASC1, as described here. So, for example if the ASA “weight” property is Global, regardless the User that own the ASA, then you will need just a Global Int. Otherwise if the ASA could have different “weights” for different owners than you will need a Local Int.
So, to summarise, given your description and the considerations above, I would say that the architecture that best fits your use case is: ASA + Stateful ASC1 (with Global or Local properties depending on your model).