Mergeable Tokens on Algorand

I’m currently looking into evaluating different smart contract platforms to implement mergeable tokens for an insurance crowd sourcing use case. These tokens have a few numerical properties, foremost value and risk. Value behaves similar to a fungible ASA. There are two dissimilarities though:

  1. Exactly 2 mergeable tokens can be combined, producing a single output mergeable token
  2. The output risk value is the average of the two input risk values

What is a good starting place to implement this in TEAL? I think I have a rough idea of how to approach this in Solidity but I am completely new to Algorand so any pointers are much appreciated.

Thank you

You may be able to do this with a combination of smart contracts and ASAs where the contract handles the merge. You would need to give more information on what you need to be sure. Another option is to build it all in a stateful smart contract where the data per user is stored in local storage. The contract could handle extra properties and doing the combine operation. The only issue with using a stateful smart contract is the default wallets don’t show these as ASAs currently when listing balances. The stateful smart contract documentation is here: Algorand Developer Docs
You also may want to watch this video to get started with writing smart contracts: Algorand Partner Training | Overview of Stateful and Stateless Smart Contracts - YouTube

1 Like

Thank you, Jason. Yes, it would be excellent to describe these as non-fungible ASA. However, I’m unclear how to express the additional data in an ASA:

      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”Œ ─ ─ ─ ─ ─ ─ ─ ─ ─  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”Œ ─ ─ ─ ─ ─ ─ ─ ─ ─ 
      β”‚          ASA1          β”‚ Additional Values β”‚ β”‚          ASA2          β”‚ Additional Values β”‚
      β”‚       Holder: A        β”‚β”‚Risk: 80%           β”‚       Holder: A        β”‚β”‚Risk: 20%          
      β”‚                        β”‚ ...               β”‚ β”‚                        β”‚ ...               β”‚
      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”” ─ ─ ─ ─ ─ ─ ─ ─ ─  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”” ─ ─ ─ ─ ─ ─ ─ ─ ─ 
                   β”‚                                              β”‚                                
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                
                                           β”‚                                                       
                                           β–Ό                                                       
                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                           
                              β”‚                        β”‚                                           
                              β”‚        Contract        β”‚                                           
                              β”‚                        β”‚                                           
                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                           
                                           β”‚                                                       
                                           β–Ό                                                       
                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”Œ ─ ─ ─ ─ ─ ─ ─ ─ ─                        
                              β”‚          ASA3          β”‚ Additional Values β”‚                       
                              β”‚       Holder: A        β”‚β”‚Risk: 50%                                 
                              β”‚                        β”‚ ...               β”‚                       
                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”” ─ ─ ─ ─ ─ ─ ─ ─ ─

Are you using the URL field. As a workaround, you could put it there or in the creation tx note field but that is not readily accessible in a contract later. It would have to be passed as a parameter to the contract that does the combining. You could make a stateful contract track the risk of the ASA as a local state variable. You could store the NFT id and the risk in local storage. As another question. How many of these NFTs will you have?

1 Like

if you used ASAs and tracked the additional properties in a stateful contract you could guarantee that the additional properties are transferred appropriately with some custom logic similar to what we do in this example: Algorand Developer Portal

1 Like

BTW if you wanted to do it completely in stateful take a look at this sample from Jason Paulos:

1 Like

Excellent points, thanks Jason. I pondered (ab)using URL or tx note but it felt too much of a hack (I haven’t even gotten as far as understanding whether these would be accessible from a contract). I think there will be roughly 500 NFT to begin with, all with bespoke risk parameters and a handful of other bespoke parameters.

If I understand your examples correctly, the β€œAssets and Custom Transfer Logic” use ASA, therefore, at least for regular transfers of the NFT, users could use standard wallet functionality (which is a plus), even though for merging the NFT they would need lower level access. Whereas the β€œasset.py” approach is completely bespoke and wouldn’t be supported by any standard wallet.

@Supirogurafu in your system are both ASA1 and ASA2 consumed (destroyed), such that:

  • Holder: A gives up ownership of ASA1 and ASA2 (assetSend transaction)
  • ASA1 and ASA2 are destroyed (assetDestroy transaction)
  • Contract Mints new ASA3 (assetCreate transaction)
  • Holder: A receives ASA3 (assetSend transaction)
1 Like

Yes, you’re describing my intention correctly, @ryanRfox. Abstracting from the very helpful tutorial on Assets and Custom Transfer Logic I would assume the contract would need to be the manager address so that the two input assets would be destroyed and the output asset would be generated. Presumably in that contract I could write the β€œrisk” parameter to global/local state.

Yes, the manager address must be able to destroy ASA1 and ASA2 so that logic will be in there. The logic needs to include the ability to optin to each ASA prior to receiving them. This will cause some limitations if you go beyond issuing ASA1000 as you would need some other method to observe the manager of ASA9999 destroyed it and also ASA1 was destroyed.

I have a similar combine/destroy/reissue ASA system I’m designing. I’m using the metaDataHash and URL fields in non-standard ways to store data accessible to program logic. You may consider using these fields to store your risk value.

1 Like

This is very helpful, @ryanRfox. Thank you. I think I can probably work with the url field. However, I’m currently stuck trying to understand how to approach the merging of the assets, meta data aside. I.e. how do I ensure that the contract owns both expected input assets? Ideally I want to create a transaction which moves both assets at the same time. But this does not seem to be possible?

I think the simpler solution is to have both assets replaced by the new asset ASA3.
Your merged asset is just a brand new asset.
You can keep history of merge in the note field of the transaction creating ASA3 for example or in the local state of the stateless smart contract account that you use to create ASA3.

Note: only the creator can destroy assets, not the managers

Edit: The above note is indeed incorrect.

1 Like

Who destory the ASA is the Asset Manager, but the whole supply must be in the Asset Creator account:

2 Likes

Understood, Fabrice. This is what I was hoping to do. However, even the mechanics of this basic use case are unclear to me: How does the smart contract that issues ASA3 register that ASA1 and ASA2 have been sent to it. Would this be a transaction group like that?

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚group1                        β”‚
β”‚β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚β”‚tx1 (AssetTransfer ASA1)    β”‚β”‚
β”‚β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚
β”‚β”‚tx2 (AssetTransfer ASA2)    β”‚β”‚
β”‚β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚
β”‚β”‚tx3 (AppCall)               β”‚β”‚
β”‚β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Is this about correct? If so, how would I evaluate tx1 and tx2 from tx3?

Yes, that group looks correct. The TEAL program will make use of the global transaction OpCode gtxn i field to access fields at global transaction index i.

1 Like