#11 Useful queries part3
In the first two parts of common queries, we introduced some common query methods such as price query, holder, and holding balance of ERC20 tokens. In this section, we'll look at some other common queries.
Custom data table using CTE
Dune V2 does not currently support user-custom tables and views. For some data from external sources or a small amount of manually curated data, we can consider using CTE to generate a custom list of data within the query. It can support custom CTE tables with thousands of rows with only a few fields and that they will execute successfully as long as they do not exceed the maximum size of the Dune query request. There are two ways to customize CTE tables:
Example of the first syntax:
Example of the second syntax:
Of course, with the second syntax, you can omit the CTE definition and use the SELECT query directly if you happen to only need to return this part of the custom data.
Example link to the above query:
Due to the limitations mentioned earlier, the execution may not succeed when there are too many rows. You will need to duplicate the same CTE code for every query, which is relatively inconvenient. For large amounts of data, multiple times, long-term use, etc., you should still consider generating the spells table by submitting spellbook PR.
Decode data from the logs
Earlier in calculating the price of ERC20 tokens, we saw an example of calculating the price from logs. Let's look at another example where we need to decode data directly from logs. When the smart contract is not decoded by Dune, or the decode table for the corresponding event is not generated because the ABI data used during decoding is incomplete, we may need to decode the query data directly from the logs. Taking the Lens protocol as an example, we found that in the Lens smart contract source code (Lens Core), almost every operation has generated event logs. However, there are only a few event-related tables in Dune's decoded data. Further investigation revealed that the ABI used during decoding was missing the definition of these events. Although we can regenerate or get the Lens team to get the full ABI and submit it to Dune to parse again, the main point here is how to extract data from the undecoded logs.
In the Lens smart contract source code, we see the FollowNFTTransferred
event definition, code link. There is also a Followed
event in the code, but decoding is complicated by the array argument, so we'll use the previous event as an example. From the event name, we can infer that when a user follows a Lens Profile, a FollowNFT will be generated and transferred to the follower's address. We can then find a transaction record of interest. Let's look at the logs inside for the following transaction:https://polygonscan.com/tx/0x30311c3eb32300c8e7e173c20a6d9c279c99d19334be8684038757e92545f8cf. The transaction Logs page in our browser and switch to the "Logs" TAB, so we can see that there are four event logs in total. In certain instances, the blockchain browser can display the original event name. The Lens transaction we're looking at doesn't show the original name, so how do we know which one corresponds to the FollowNFTTransferred
event log? Here we can use third-party tools to compare by generating the keccak256 hash of the event definition. Keccak - 256 this page can generate online Keccak - 256 hash value. Let's clean up the definition of the FollowNFTTransferred
event in the source code to a minified mode (remove parameter names, remove Spaces), Get FollowNFTTransferred (uint256 uint256, address, the address, uint256)
, then paste it to Keccak - 256 tool page, The generated hash value for 4996ad2257e7db44908136c43128cc10ca988096f67dc6bb0bcee11d151368fb
. (The latest Dune parse table already has the full event table for the Lens project, here is just for example purposes)
Using this hash, we can search Polygonscan's transaction log list to find a match. You can see that the first log entry is exactly what we're looking for.
After finding the corresponding log record, with the event definition, we can easily decode the data:
Example link to the above query:
Use sequences of numbers to simplify queries
When studying NFT projects, we may want to analyze the distribution of prices of all transactions for a given NFT project during a certain time period (i.e., how many transactions were recorded in each price range). We typically set the minimum and maximum transaction prices (either by input or by querying the transaction data and handling outliers), divide the range into N ranges, and count the number of transactions in each range. Here is an example of a query that is simple in logic but cumbersome in comparison:
In this example, we define two parameters min_price
and max_price
, divide their difference equally into 20 price bands, and then use a lengthy CASE statement to count the number of transactions in each band. Imagine if you had to break it up into 50 groups. Is there an easier way? The answer is yes. Look at the code first:
In CTE num_series
, we useunnest(sequence(1, 20)) as tbl(num)
to generate a sequence of numbers from 1 to 20 points and convert it into 20 rows of one number per row. Then in bin_gap
, we get the low and high price for each interval by joining the two CTEs. Using the union all
set adds an additional range of high price values large enough to cover other transactions. bucket_trade
can then be simplified to simply concatenate bin_gap
and compare prices falling into the corresponding range. The overall logic is simplified and much clearer to understand.
Example link to the above query:
Read data from Array and Struct fields
Some smart contracts emit event logs using array parameters and the data table generated by Dune after decoding is also stored in arrays. The Solana blockchain's raw transaction tables make heavy use of arrays to store data. Some data is stored in structs, or we need to borrow them when we want to extract the data (see below for an example). Let's look at how to access the data stored in array fields and struct fields.
The first two fields returned by the preceding query are arrays (shown in the following image):
We can use cross join unnest(tokens) as tbl1(token)
to split the tokens
array field into multiple lines:
We can also split the deltas
field. But because each cross join
appends the split value to the original result set of the query, if we perform operations on both fields at the same time, we will have an incorrect result set that looks like a Cartesian product. The following screenshot shows the query code and the resulting output:
To avoid duplication, it is advisable to split multiple fields simultaneously within the same unnest()
function, it will return a temporary table with multiple corresponding new fields.
The result is shown in the following figure:
Example link to the above query:
Read JSON string data
In some smart contracts, objects containing multiple values are serialized as json strings in the parse table, such as the Lens creation Profile event we saw earlier. We can use :
to read variables directly from a json string. For example:
Alternatively, use the json_query()
or json_extract()
function to extract the corresponding data. The json_extract()
function supports type conversion when you need to extract array values from a JSON string. Here are some examples:
Example link to the above query:
Dune SQL (Trino) For detailed help on JSON functions, check out: https://trino.io/docs/current/functions/json.html
About Us
Sixdegree
is a professional onchain data analysis team Our mission is to provide users with accurate onchain data charts, analysis, and insights. We are committed to popularizing onchain data analysis. By building a community and writing tutorials, among other initiatives, we train onchain data analysts, output valuable analysis content, promote the community to build the data layer of the blockchain, and cultivate talents for the broad future of blockchain data applications. Welcome to the community exchange!
Website: sixdegree.xyz
Email: contact@sixdegree.xyz
Twitter: twitter.com/SixdegreeLab
Dune: dune.com/sixdegree
Github: https://github.com/SixdegreeLab
Last updated