Find Tokens To Price

Now, we'll enhance our script to pre-fetch the price of each token involved in the different transactions, using the Pricing API.

We're also going to save all transactions to a local JSON file, in preparation for the next step.

Expanding the script to fetch tokens that need pricing

First, some background:

Our Pricing API exposes an endpoint where you can POST a list of tokens to price, along with the blockNumber that you need each price for. It then processes these requests asynchronously, so that when you call for the individual prices they're ready to go.

Calling this endpoint as you encounter new tokens that need prices will speed-up the overall processing time when it's time to pull the final export.

Update your script to be as follows:

require('dotenv').config();
const axios = require('axios');
const fs = require('fs');

const fetchAllTransactions = async (
    chain,
    accountAddress,
    startTime,
    endTime
) => {
    let transactions = [];
    let hasNextPage = true;
    let nextPageUrl = `https://translate.noves.fi/evm/${chain}/txs/${accountAddress}?startTimestamp=${startTime}&endTimestamp=${endTime}`;

    while (hasNextPage) {
        try {
            const response = await axios.get(nextPageUrl, {
                headers: { apiKey: `${process.env.NOVES_API_KEY}` }
            });

            transactions = transactions.concat(response.data.items);
            hasNextPage = response.data.hasNextPage;

            if (hasNextPage) {
                nextPageUrl = response.data.nextPageUrl;
            }
        } catch (error) {
            console.error('Error fetching transactions:', error);
            hasNextPage = false;
        }
    }

    return transactions;
};

const preFetchPrices = async (tokens) => {
    try {
        const response = await axios.post(
            'https://pricing.noves.fi/evm/preFetch',
            { tokens: tokens },
            {
                headers: { apiKey: `${process.env.NOVES_API_KEY}` },
            }
        );
        return response.data;
    } catch (error) {
        console.error('Error posting price pre-fetch request:', error);
    }
};

const findTokensToPrice = async (transactions, chain) => {
    const tokensToPrice = [];
    transactions.forEach(tx => {
      tx.classificationData.sent.forEach(item => {
        tokensToPrice.push({ chain, tokenAddress: item.token.address, blockNumber: tx.rawTransactionData.blockNumber });
      });
      tx.classificationData.received.forEach(item => {
        tokensToPrice.push({ chain, tokenAddress: item.token.address, blockNumber: tx.rawTransactionData.blockNumber });
      });
    });
  
    await preFetchPrices(tokensToPrice);
  };

const chain = 'eth'; // Replace with the desired chain
const accountAddress = '0x....'; // Replace with the desired account address
const startTime = 1640995200; // Start timestamp for January 1, 2022
const endTime = 1672531199; // End timestamp for December 31, 2022  

fetchAllTransactions(chain, accountAddress, startTime, endTime)
  .then(async transactions => {
    await findTokensToPrice(transactions, chain);
    fs.writeFileSync('transactions.json', JSON.stringify(transactions, null, 2));
    console.log('Prices requested and transactions stored in file.');
  });

We've now added a couple of functions that deal with finding all tokens that need pricing (by parsing them from the sent and received arrays in the transaction objects), and calling the Pricing API pre-fetch the prices that will be needed.

In the next step, we'll pull the individual prices to enrich our data further.