xGov-86: Bonfire šŸ”„

This is the official discussion thread for xGov-86: Bonfire

Author Brian Whippo (@SilentRhetoric)

Category Tools

Focus DeFi

Open-Source Yes

ALGO Requested 10000

Abstract

Burn ASAs by throwing them into the Bonfireā€“a standard, permissionless, and verifiable way to take ASAs out of circulation forever by implementing an interface for ARC-54: ASA Burning App.

Team

Brian Whippo is a self-taught, full-stack software developer passionate about bringing the promises of blockchain to the people. When he is not trying to build a better world with the Algofam, he is leading strategic technology transformation at a top financial institution, where he has been designing better ways to manage derivatives and commodities for over 14 years.

LinkedIn - Brian Whippo
GitHub - SilentRhetoric

Experience with Algorand

Brian has been an active developer and contributor in the Algorand community since 2021 in various capacities:

  • Built the open source Solid Algo Wallets Javascript library for integrating several wallets into a web site, a project funded by xGov #49
  • Created the open source xGov Viewer app for reviewing xGov proposals and analyzing proposal voting data
  • Completed the Encode x Algorand Bootcamp and won a 3rd place prize in the 2022 Encode x Algorand Hackathon
  • Collaborated with Joe Polny (@joe-polny) from Algorand Foundation to draft the ARC-12 standard for ā€œclaimableā€ assets. Notably, this xGov proposal seeks to address one use case which we had intended to be solved by ARC-12.
  • Runs two participation nodes in Algorand consensus

Present Proposal

I will build Bonfire, a web app that implements a user interface for ARC-54: ASA Burning App, a community standard for burning ASAs. I will deliver:

  • A web app with multi-wallet connectivity
  • A simple interface for burning ASAs by sending them to the ARC-54 smart contract
  • Open source code for everything with documentation
  • Free-tier site hosting for a website for the foreseeable future. (Eventually, it would probably make sense to integrate this with ChainUI so that the interface would always be available.)

The project will be completed in Q1 2024.

Benefits for the community

ARC-54 and a user interface to burn ASAs will help the community by enabling tokens to be easily, permissionlessly, permanently, and verifiably burned. By standardizing how ASAs are burned in the ecosystem, the burning address can be known to defi sites like DefiLlama that track circulating supply metrics and exclude tokens burned there. Projects which want to burn tokens to reduce their supply can use the ARC-54 burning approach to avoid any doubts about how or where the tokens were burned.

Additional information

For fun, I will aim to light the Bonfire on February 7th as a poetic nod to the ā€œBonfire of the Vanitiesā€ on 7 February 1497, when supporters of the Dominican friar Girolamo Savonarola collected and burned thousands of objects such as cosmetics, art, and books in the public square of Florence, Italy, on the occasion of Shrove Tuesday, martedĆ­ grasso.

Link to proposal on GitHub:

3 Likes

Can you give an example of why one would burn an ASA or what they might burn?

2 Likes

Two use cases stand out:

  1. Fungible token issuers may want to burn a sum of their treasury to decrease circulating supply and increase the value of tokens already purchased or airdropped. This is fairly standard practice in the industryā€”even major blockchains have done token burns. Having ARC-54 as a standard will make it easy for analytics sites and people alike to easily ascertain that tokens have been properly burned.

  2. As a general-purpose tool, Bonfire lets token holders get rid of any ASA they donā€™t want, from fungible coins to non-fungible tokens (NFTs). You can always send tokens back to the creator account, but if the tokens have some value, you may not want to hand that back to the creator. Doing this today would be quite manual if, say, you have dozens of NFTs with different creator accounts. Tossing them indiscriminately into the bonfire will be easier.

Throughout Algorandā€™s history there have been some half-baked tools to help people burn tokens, but as of this writing they are either no longer being hosted online or never had a web interface at all. Some solutions required trust in a third party, while others sent burned tokens to different addresses, which is a mess if you want block explorers to label a known, trustless burn account. There simply has never been a proper standard for this utility, let alone with an intuitive and free UI.

2 Likes

Thank you for this! Helpful.

How do you plan to make revenue out of this for long term sustainability. Just curious

This is proposed as a community utility. I have no plans to commercialize this.

It will be built in such a way that it could eventually be uploaded to ChainUI so that the tool is always available to anyone even if the web hosting becomes a cost issue.

2 Likes

That is a good idea.

@SilentRhetoric, I voted for this and Iā€™m glad to see it get funded.

Free-tier site hosting for a website for the foreseeable future. (Eventually, it would probably make sense to integrate this with ChainUI so that the interface would always be available.)

If it is just going to be a single page web app this would be a better fit for Arweave, because then it wonā€™t rely on people repinning on IPFS or continuous payment of someone to do so.

1 Like

Thank you for your support and the technical suggestion.

The tool will be built as a single-page application to make it easy to host/pin/store anywhere.

The community will be free to use the open source code to create integrations with other apps, stripped-down functionality for lightweight decentralized hosting, or even reskins of my ā€œwhite labelā€ site for custom-branded experiences.

1 Like

Introduction
I think arc-0054 proposes one of the most useful technologies developed by Algorand by creating a network wide mechanism for verified burns. I posted this comment as Issue #312 on GitHub as well.

Issues

  1. There appears to be no way to verify the private key security of the Burn Address.

The Burn AddressBNFIREKGRXEHCFOEQLTX3PU5SUCMRKDU7WHNBGZA4SXPW42OAHZBP7BPHY was funded byZA5Y6ZVM2KOOV7JIIN3LSFNTCZDSOEHVFG6BECIFDIVFPIJWO7AVPO5OZI with TXID CY2OQBJFSB6N7C27FJ2KCONAEJGQAZYLIAWUST7RUWMLFGMLOYUA. The funding address is still active for both receiving and sending assets. Moreover, the approval program makes no apparent mention of creating the Burn Address. Instead the approval program states:

	global CurrentApplicationAddress
	itxn_field AssetReceiver

So, one issue here is that it appears possible that there is an owner of the private key for the Burn Address or that the private key for the Burn Address is potentially recoverable. The other issue is that it appears possible to change CurrentApplicationAddress.

  1. The Burn Address does not appear to be connected to an Application ID as specified in the approval program.

I searched the Burn Address on PeraExplorer and found that it was not connected to any Application ID. The first lines of the approval program state:

txn ApplicationID
int 0
>

The issue here is there appears to be no way to verify that this approval program is connected to the Burn Address because the Burn Address has no associated applications.

Conclusion
Any response on information regarding these issues would be appreciated. Thanks!

This is a good question. It requires understanding a few things about Algorandā€™s smart contracts to fully grasp why the Bonfire account is, in fact, an address to which there is one way in and no way out.

Algorand application addresses can be derived from the application ID following the procedure described here: https://developer.algorand.org/docs/get-details/dapps/smart-contracts/apps/.

The Javascript code to see how this is done in the algosdk can be found here: js-algorand-sdk/src/encoding/address.ts at 77591972822f130ed6cc52fcc3d2c18bba1713ff Ā· algorand/js-algorand-sdk Ā· GitHub

Following this approach, it is possible to confirm that the Bonfire mainnet application ID 1257620981 does indeed have the application address BNFIREKGRXEHCFOEQLTX3PU5SUCMRKDU7WHNBGZA4SXPW42OAHZBP7BPHY, which can be seen on Pera Explorer here: 1257620981 | Pera Algorand Explorer.

Because this address belongs to an application, the only way for transactions to be issued from the address is if they are generated as inner transactions by the applicationā€™s logic, as described here: Inner transactions - Algorand Developer Portal.

To know what kinds of inner transactions the application can send, one must look at the TEAL code of the smart contract. This is visible on Pera Explorer and even more clearly on Allo, which has a nice visualization of the TEAL:

If one takes the time to step through the code, it is possible to confirm that this application has only one provision to send inner transactions, which is to send asset transfers with no quantity to its own address, which is effectively an opt-in transaction.

Additionally, the code of this smart contract application can be compared back to the details in ARC-54 here: ARC-54: ASA Burning App.

The high-level TealScript source code in the ARC is even easier to read to see that the application is very limited in what it can do, and it is possible to take that TealScript source code and compile it down to TEAL to verify that the resulting TEAL matches what is on the chain at application ID 1257620981 with address BNFIREKGRXEHCFOEQLTX3PU5SUCMRKDU7WHNBGZA4SXPW42OAHZBP7BPHY.

That was a bit of a journey, but it is all fully verifiable.

2 Likes

Thanks for the detailed response.

Issue 1.

I read the address.ts file you provided regarding how addresses can be derived from the Application ID. I also read the general procedure for doing so that you mentioned in the smart contract docs, which state:

The public address is devised by taking the application ID as an 8-byte big-endian array, prefixing it with appID , and then encoding it using the standard encoding method for Algorand addresses.

But, it does not appear this was the method used to create the current Application Account because the creator of App #1257620981 was ALOUDFELLINGJWERJIW3O4CFODNBGK6K5Q6JYSQCOB3W733QBUSLGQHODE and the current Application Account: BNFIREKGRXEHCFOEQLTX3PU5SUCMRKDU7WHNBGZA4SXPW42OAHZBP7BPHY was independently funded by ZA5Y6ZVM2KOOV7JIIN3LSFNTCZDSOEHVFG6BECIFDIVFPIJWO7AVPO5OZI, as I previously mentioned. I also reviewed the source code for the application from Allo, but similar to the ARC-0054 specification, there is no account creation method in the approval program.

I might be missing something and please correct me if I am wrong. But, there is no way to verify private key security according to the ARC-0054 standard. For example, the contract creator may generate Address B, having the private key pk, then simply update the Application Account with Address B. For example, the application was already updated once to change the Application Account to the current address: INGI2FSZY54BIBPLKGCUUVWJRTRUMNPS2SHEGLHPR3NOH4MRGW7Q. So, the person having the private key pk to Address B could simply withdraw the funds in the Application Account. Similarly, whoever has the private key to the current Application Account: BNFIREKGRXEHCFOEQLTX3PU5SUCMRKDU7WHNBGZA4SXPW42OAHZBP7BPHY could simply withdraw all the current funds, or the private key to Application Account could be otherwise stolen or compromised.

Could you please provide more information on this?

Issue 2.

You are correct. I check the burn address on Allo, which identifies it as an application account associated with App #1257620981. I had originally checked the burn address on Pera, which expressly states 0 applications are connected to the address, which appears to be wrong.

A few more things about the smart contract:

  1. Smart contracts donā€™t need to have any special logic in their TEAL code related to their creation. It is possible to have a method that sets up initial state or things like that, but this is purely optional. The burn app currently has just the opt in method and can do nothing else. This brings me to an interesting bit of trivia about the Bonfire appā€™s smart contract.

  2. When you deploy a smart contract app on Algorand, it gets assigned a uint64 application ID, much like ASAs are given ever-increasing IDs. The app ID is then hashed as linked above to get the application address. Just as one can generate a large number of regular addresses until finding one with a desired set of lettersā€”a ā€œvanityā€ addressā€”the same is possible for applications. This is how the Bonfire smart contract has an address ā€œBNFIREā€¦ā€.

  3. When the app ID was deployed to mainnet by ā€œALOUDFELLINGā€¦ā€ it originally had different logic controlling how the application could be updated. This enabled them to issue a transaction to update the TEAL code for the approval program and effectively reprogram this smart contract, changing it in two key ways: it has the one method to opt into ASAs, and it can no longer be updated or deleted and is thus permanently immutable.

2 Likes

Thanks. I ran:

app_id = 1257620981
app_addr = logic.get_application_address(app_id)
print(f"Application ID: {app_id}")
print(f"Application Addr: {app_addr}")

And got the App ID and Application Account out.

Application ID:   1257620981
Application Addr: BNFIREKGRXEHCFOEQLTX3PU5SUCMRKDU7WHNBGZA4SXPW42OAHZBP7BPHY

Regarding the Teal code and functional capabilities of the smart contract, I have a couple more questions.

1. First, regarding Label 6.

###########################################################
###################### Label 6 ############################
###########################################################
# This label is executed if the value on top of the stack matches the byte array 0x44f8d5de.
label6:
# This instruction pushes the second application argument onto the stack.
# Ith value of the array field F of the current transaction.
# txna can be called using txn with 2 immediates.
txna ApplicationArgs 1
# This instruction converts the value on top of the stack into an integer.
btoi
# This instruction pushes the assets associated with the transaction onto the stack.
txnas Assets
# This instruction calls the subroutine labeled label4.
callsub label4
# This instruction pushes the integer constant intc_1 onto the stack.
intc_1
# This instruction returns from the current subroutine.
return

What value is being passed to txna ApplicationArgs 1?

2. Second, regarding Label 4.

###########################################################
###################### Label 4 ############################
###########################################################
# This subroutine is defined to transfer an asset.
label4:
# This instruction sets the protocol version to 1.0.
# Prepare top call frame for a retsub that will assume A args and R return values.
proto 1 0
# This instruction begins an inner transaction.
itxn_begin
# This instruction pushes the integer 4 onto the stack.
pushint 4
# This instruction sets the type of the inner transaction to TypeEnum.
# TypeEnum can take on several different values, each representing a distinct transaction type.
# UpdateApplicationOC = 4
# set field F of the current inner transaction to A
itxn_field TypeEnum
# This instruction pushes the current application's address onto the stack.
# global field F
global CurrentApplicationAddress
# This instruction sets the recipient of the asset transfer.
itxn_field AssetReceiver
# This instruction digs one level deep into the transaction frame and pushes the value at that level onto the stack.
# Nth (signed) value from the frame pointer.
frame_dig -1
#This instruction sets the asset to be transferred.
itxn_field XferAsset
# This instruction pushes the integer constant intc_0 onto the stack.
# constant 0 from intcblock
intc_0
# This instruction sets the amount of the asset to be transferred.
# set field F of the current inner transaction to A
itxn_field AssetAmount
# This instruction pushes the integer constant intc_0 onto the stack.
# constant 0 from intcblock
intc_0
# This instruction sets the fee for the inner transaction.
# set field F of the current inner transaction to A
itxn_field Fee
# This instruction submits the inner transaction.
# execute the current inner transaction group.
# Fail if executing this group would exceed the inner transaction limit, or if any transaction in the group fails.
# itxn_submit resets the current transaction so that it can not be resubmitted.
itxn_submit
# This instruction returns from the subroutine.
retsub

A. What is the value of frame_dig -1?

B. Why is the int value 4 being passed to itxn_field TypeEnum? As I understand it, int 4 is the update application argument according to the transaction.py file, line 1545:

    # UpdateApplicationOC indicates that an application transaction will
    # update the ApprovalProgram and ClearStateProgram for the application
    UpdateApplicationOC = 4

TypeEnum is used to represent the type of a transaction as an integer, and 4 represents an AssetTransfer. I actually have no idea where this is in our main docs, but I remember it from writing PyTeal: Transaction Fields and Global Parameters ā€” PyTeal documentation

Letā€™s break down the raw Teal into chunks with clearer comments and step through each chunk:

label4:


# This sets up the subroutine to expect one argument (and no return value). 
# The argument to the application call is the ASA ID that the Bonfire app needs to opt into
# That arg is passed into this subroutine here and will be fetched shortly
proto 1 0


# This instruction begins an inner transaction.
itxn_begin


# Set the innerTxn type to 4, which means asset transfer
pushint 4
itxn_field TypeEnum


# Set the innerTxn receive to this application's address
global CurrentApplicationAddress
itxn_field AssetReceiver


# "Dig" into the frame, which in this case has one argument as indicated in proto 1 0 above
# This sets the innerTxn's transfer asset to the ASA ID that was passed in as an argument above
frame_dig -1
itxn_field XferAsset


# Set the innerTxn amount to zero
intc_0
itxn_field AssetAmount


# Set the InnerTxn fee to zero
intc_0
itxn_field Fee


# Send the inner transaction. 
# Note that the innerTxn built above is a send-to-self with zero quantity, which effectively opts this application into the given ASA ID
itxn_submit

retsub
1 Like

Thanks for your explanation for your explanation of the Teal. Iā€™m building an app to use the address, but I am getting an error, telling me the address in unavailable. I verified the burn account is already optedin to the asset id and has received test transactions manually sent.

    raise error.AlgodHTTPError(m, code, j.get("data"))
algosdk.error.AlgodHTTPError: TransactionPool.Remember: transaction NJMQKBNRZXFTSPGB3OEC7UD2MVROVW744ZBXYQVSAE4YO6F2PLJQ: logic eval error: unavailable Account BNFIREKGRXEHCFOEQLTX3PU5SUCMRKDU7WHNBGZA4SXPW42OAHZBP7BPHY. Details: app=2320890724, pc=275, opcodes=itxn_field XferAsset; pushbytes 0x0b4a8891468dc87115c482e77dbe9d9504c8a874fd8ed09b20e4aefb734e01f2 // addr BNFIREKGRXEHCFOEQLTX3PU5SUCMRKDU7WHNBGZA4SXPW42OAHZBP7BPHY; itxn_field AssetReceiver

The PyTeal function for the application accountā€™s transaction to the Bonfire burn address.

    ##############################
    # return burn
    ##############################
    send_burn = Seq([
        InnerTxnBuilder.Begin(),
        InnerTxnBuilder.SetFields({
            TxnField.type_enum: TxnType.AssetTransfer,
            TxnField.xfer_asset: asset_id,
            TxnField.asset_receiver: Addr("BNFIREKGRXEHCFOEQLTX3PU5SUCMRKDU7WHNBGZA4SXPW42OAHZBP7BPHY"),  
            TxnField.asset_amount: Int(10000),
            TxnField.fee: Int(1000),  
        }),
        InnerTxnBuilder.Submit(),
        Approve()  
    ])
    ##############################

This is the part of the Teal responsible for the inner transaction.

itxn_begin
int axfer
itxn_field TypeEnum
int 297995609
itxn_field XferAsset
addr BNFIREKGRXEHCFOEQLTX3PU5SUCMRKDU7WHNBGZA4SXPW42OAHZBP7BPHY
itxn_field AssetReceiver
int 10000
itxn_field AssetAmount
int 1000
itxn_field Fee
itxn_submit

I am reading through the inner txn docs and do not think there is anything to suggest an internal txn cannot go to an external account.

Solved

In writing this I learned the problem is that the Bonfire burn address needs to be included as an external account in the app call transaction.

1 Like