Using eosio singleton tables (on WAX Blockchain)
We use the tables within a smart contract to store the information as if it were a database. Thanks to the indexes we can quickly access the records we need and thus save us valuable microseconds of code execution. But sometimes we need to store simple data that reflects the current state of something we're keeping an eye on, such as the current version of the program or an event counter.
These types of tables do not require an index since they will only have one record to access. They are the singleton tables.
To illustrate a use case I am going to perform an exercise that I think can be quite useful. Many times I have found in my WAX wallet some totally useless NFTs or with residual value. Promotional or collection NFTs that we hoped could monetize, but have come to nothing. In the end, the only solution to get rid of the garbage is to burn it. The problem is that burning several NFTs from the Atomic Market interface, if we are in that environment, is a bit tedious since you have to do it one at a time.
I intend to create a smart contract that helps us burn the NFTs we send it, regardless of the number, and that thanks to a singleton table keep track of how many NFTs we have burned.
We create the structure of our smart contract and we will continue with the explanation. You can consult the following article to see how to prepare the programming environment and create your first smart contract:
Declaring the singleton object
The first thing we need is to include the eosio/singleton library in our header file
#include <eosio/singleton.hpp>
We will create a table with the data we want to store. For our example we are only going to use a counter that will increase for each NFT burned.
TABLE burned
{
uint64_t burned_items = 0;
} burned_reg;
At the same time as creating the table structure I took the opportunity to initialize the counter to 0 and also to declare the object "burned_reg" as "burned" type. We will use this object later to access the table.
Next, we declare our singleton object from the created table and assign it a name so that we can access it from outside the smart contract:
typedef singleton<"burned"_n, burned> t_burned;
Now we can make use of our singleton table.
Receiving NFTs to delete
In order for the smart contract to erase (burn) all the NFTs it receives, we will declare a passive function that remains to listen for events in the smart chain. These types of functions do not need to be called but are activated when the event to which they are associated occurs; in our case, when we receive an NFT.
To transfer the NFTs of the AtomicAssets standard from one account to another, it is necessary to make use of the "transfer" action, which receives as parameters the account of the sender, the recipient, an array with the IDs of the transmitted NFTs and a text as a message (memo).
From our smart contract we can use the attribute "on_notify" to capture the event of the transaction and act accordingly.
We declare a function with the attribute "eosio::on_notify" with the same parameters as the function we want to capture, "atomicassets::transfer"
[[eosio::on_notify("atomicassets::transfer")]] void gettransfer(
name from,
name to,
vector<uint64_t> asset_ids,
string memo);
Now, every time the smart contract receives an NFT from AtomicAssets this function will be automatically executed with the same parameters of the captured transaction.
Burning NFTs array
What the "transfer" function sends is an array with the NFTs that are transmitted. Although we only send 1 NFT it will also be an array of 1 element.
To delete the NFTs we will call the action "burnasset" of the smart contract of AtomicAssets but this action can only receive the ID of an NFT in each call so if we want to burn several in a row we will have to implement a loop that runs through all the elements of the array "asset_ids" to send them one by one.
for (auto it = asset_ids.begin(); it != asset_ids.end(); it++)
{
action(
permission_level{get_self(), name("active")},
name("atomicassets"),
name("burnasset"),
make_tuple(get_self(), *it))
.send();
}
Update singleton table
Once all the sent NFTs have been burned, we can proceed to update the singleton table by adding the burned units to the previously stored value.
First, we declare the burned object with the structure and contents of the table created earlier. The "get_or_create" method will be used to obtain that structure or to initialize it if it does not already exist (first access). If this is the case, the counter will start with the value 0 as indicated in the definition of the object burned_reg.
auto burned = _burned.get_or_create(_self, burned_reg);
We perform a simple accumulation operation by adding to "burned_items" the total number of NFTs received (number of elements of the array):
burned.burned_items += asset_ids.size();
And, finally, we update the record of our table:
_burned.set(burned, _self);
The code
You can get the code on Github:
https://github.com/3dkrender/totheburning
I am Marcos DK, artist, game developer, Steem Witness and top21 WAX Block Producer with 3DK Render Guild. Please, support us with a vote as your witness.
Support us on WAX Blockchain:
https://eosauthority.com/vote/producers?network=wax
Web: https://3dkrender.com
Twitter: https://twitter.com/MarcoS3DK
Discord: https://discord.gg/3dkrender