Skip to main content

Find Whale Transaction

Updated on
Nov 15, 2024

Overview

Blockchain adoption has reached a point where millions of transactions occur daily. While most of these transactions are relatively small, wealthy cryptocurrency participants (whales) are also making significant moves.

In this function example, we will get transactions with native asset transfers and return the ones that exceed a given threshold..

What We Will Do

For this example, we will extract the native asset transfers above a given threshold. We will demonstrate this in two ways:

  1. A standalone Function which can be called via API, passing the transaction size as a parameter.
  2. A transformation that can be applied to a QuickNode Stream, feeding the output to the destination of your choice, block by block.

Sample Function

The following Function code extracts Ethereum whale transactions in JavaScript Node.js v20 runtime using the block dataset:

function main(params) {
// Extract block data from the params object
const block = params.data[0];

// Extract metadata
const network = params.metadata.network;
const blockNo = hexToInt(block.number);

// Configure native asset details. On Ethereum, this is eth, Polygon it is matic, etc.
const asset = {
units: "eth",
decimals: 18
};

// Apply the minimum tx size to filter on, via the value passed in through user_data
const minTxSize_dec = params.user_data.minTxSize;

// Convert the tx size to the number stored onchain, with decimal places added
const minTxSize_val = decToVal(minTxSize_dec, asset);

// Extract matching transactions
const transactions = block.transactions;
const txArray_raw = transactions.filter(obj => hexToInt(obj.value) >= minTxSize_val);
const count = txArray_raw.length;

// Decode transactions into a cleaner format
const txArray_clean = [];
txArray_raw.forEach((tx, txIndex) => {
const value_clean = valToDec(hexToInt(tx.value), asset);
txArray_clean.push({
hash: tx.hash,
to: tx.to,
from: tx.from,
value: value_clean,
units: asset.units
});
});

// While debugging, it is useful to include raw tx array, only return the necessary data in prod
const returnObj = {
block: blockNo,
network: network,
result: `${count} transaction(s) w/ value > ${minTxSize_dec} ${asset.units}`,
transactions_clean: txArray_clean,
transactions_raw: txArray_raw
};

return returnObj;
}

function hexToInt(hex) {
let decodedVal = hex.substring(2);
decodedVal = parseInt(decodedVal, 16);

return decodedVal;
}

function hexToStr(hex) {
let decodedStr = hex.substring(2);
decodedStr = Buffer(decodedStr, 'hex').toString();

return decodedStr;
}

function valToDec(val, asset) {
const dec = val / Math.pow(10, asset.decimals);
return dec;
}

function decToVal(dec, asset) {
const val = dec * Math.pow(10, asset.decimals);
return val;
}

Request

We will invoke the function with the following cURL command. Be sure to replace the YOUR_API_KEY with your own QuickNode API key and the POST URL with the URL of your Function.

curl -X POST "https://api.quicknode.com/functions/rest/v1/functions/{functionId}/call?result_only=true" \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"network": "ethereum-mainnet",
"dataset": "block",
"block": "latest",
"user_data": {
"minTxSize": 5
}
}'

Response

Resulting in the following response:

{
"block": 21194293,
"network": "ethereum-mainnet",
"result": "3 transaction(s) w/ value > 5 eth",
"transactions_clean": [
{
"hash": "0x3008e9ae83d164e52a608b205987278245ec2874f0bd7d5fb68dd4497429dfd8",
"to": "0xb69bef6281a18c8f90eb8c04c2407f55094c95f9",
"from": "0x46340b20830761efd32832a74d7169b29feb9758",
"value": 7.14751,
"units": "eth"
},
{
"hash": "0xa2f9427b396f9b61344d44c81494a06a01c777ec32bf1143bcdb231cd8cdd062",
"to": "0x1c727a55ea3c11b0ab7d3a361fe0f3c47ce6de5d",
"from": "0xf962e467c553c2ef45d5462c52429837f4fd8c8a",
"value": 330,
"units": "eth"
},
{
"hash": "0x0d245bae645839b3cf2fabd59a01ee1a5025a7e19537755429f8bb8d09a41025",
"to": "0xfa8074696cd3bd1dacace2f25abcfa935f075e37",
"from": "0xb5d85cbf7cb3ee0d56b3bb207d5fc4b82f43f511",
"value": 10.653833003940589,
"units": "eth"
}
],
"transactions_raw": [
{
"blockHash": "0x2aa5c7b46dfa0b2698e47f9e232654b170e0229b748da0b4e615c3a6c6be115b",
"blockNumber": "0x1436635",
"from": "0x46340b20830761efd32832a74d7169b29feb9758",
"gas": "0x55730",
"gasPrice": "0x686fa4aad",
"hash": "0x3008e9ae83d164e52a608b205987278245ec2874f0bd7d5fb68dd4497429dfd8",
"input": "0x",
"nonce": "0xc2109a",
"to": "0xb69bef6281a18c8f90eb8c04c2407f55094c95f9",
"transactionIndex": "0x70",
"value": "0x63310e79d28d6000",
"type": "0x0",
"chainId": "0x1",
"v": "0x25",
"r": "0x9457b16f23678a0f72f4e1e80af256fbea1e307f7fc6f46b9cf349e48e4e506c",
"s": "0x717ccc7780e8fc95c3aa914b613af9acec5e39e17e1fbf874b0f8718737402b1"
},
{
"blockHash": "0x2aa5c7b46dfa0b2698e47f9e232654b170e0229b748da0b4e615c3a6c6be115b",
"blockNumber": "0x1436635",
"from": "0xf962e467c553c2ef45d5462c52429837f4fd8c8a",
"gas": "0x5208",
"gasPrice": "0x671ffe005",
"hash": "0xa2f9427b396f9b61344d44c81494a06a01c777ec32bf1143bcdb231cd8cdd062",
"input": "0x",
"nonce": "0xb",
"to": "0x1c727a55ea3c11b0ab7d3a361fe0f3c47ce6de5d",
"transactionIndex": "0x7f",
"value": "0x11e3ab8395c6e80000",
"type": "0x0",
"chainId": "0x1",
"v": "0x25",
"r": "0xa63913294bdaf5da7aa161aef1c06187429ecffca8a3fca92b5dd042a553e034",
"s": "0x3fab6f14508a6b13e04f8b80cab55651243712e8c9cf84d33aa72ab0237ad173"
},
{
"blockHash": "0x2aa5c7b46dfa0b2698e47f9e232654b170e0229b748da0b4e615c3a6c6be115b",
"blockNumber": "0x1436635",
"from": "0xb5d85cbf7cb3ee0d56b3bb207d5fc4b82f43f511",
"gas": "0x5208",
"gasPrice": "0x63342f948",
"maxFeePerGas": "0xc1b710800",
"maxPriorityFeePerGas": "0x3b9aca00",
"hash": "0x0d245bae645839b3cf2fabd59a01ee1a5025a7e19537755429f8bb8d09a41025",
"input": "0x",
"nonce": "0x95e8cd",
"to": "0xfa8074696cd3bd1dacace2f25abcfa935f075e37",
"transactionIndex": "0xc1",
"value": "0x93da04abb03632a5",
"type": "0x2",
"accessList": [],
"chainId": "0x1",
"v": "0x1",
"r": "0x4634e9af78659d6c65e43fe0c3640be87cfd3b77e8096bb66d66847b5909a570",
"s": "0x25e9f8a913c97d434ca2d349f8834f63bb058b54480e7bdb5b7617c32959b304",
"yParity": "0x1"
}
]
}

Learn more about QuickNode Functions.

Sample Stream Transformation

The following code can be used in a QuickNode Stream to filter and transform the output:

Try it yourself by deploying the filtered Stream to your account.

function main(stream) {
// Extract block data from the params object
const block = stream.data ? stream.data[0] : stream[0];

// Extract metadata
const blockNo = hexToInt(block.number);

// Configure native asset details. On Ethereum, this is eth, Polygon it is matic, etc.
const asset = {
units: "eth",
decimals: 18
};

// Apply the minimum tx size to filter on
const minTxSize_dec = 5;

// Convert the tx size to the number stored onchain, with decimal places added
const minTxSize_val = decToVal(minTxSize_dec, asset);

// Extract matching transactions
const transactions = block.transactions;
const txArray_raw = transactions.filter(obj => hexToInt(obj.value) >= minTxSize_val);
const count = txArray_raw.length;

// Decode transactions into a cleaner format
const txArray_clean = [];
txArray_raw.forEach((tx, txIndex) => {
const value_clean = valToDec(hexToInt(tx.value), asset);
txArray_clean.push({
hash: tx.hash,
to: tx.to,
from: tx.from,
value: value_clean,
units: asset.units
});
});

// While debugging, it is useful to include raw tx array, only return the necessary data in prod
const returnObj = {
block: blockNo,
result: `${count} transaction(s) w/ value > ${minTxSize_dec} ${asset.units}`,
transactions_clean: txArray_clean,
transactions_raw: txArray_raw
};

return returnObj;
}

function hexToInt(hex) {
let decodedVal = hex.substring(2);
decodedVal = parseInt(decodedVal, 16);

return decodedVal;
}

function hexToStr(hex) {
let decodedStr = hex.substring(2);
decodedStr = Buffer(decodedStr, 'hex').toString();

return decodedStr;
}

function valToDec(val, asset) {
const dec = val / Math.pow(10, asset.decimals);
return dec;
}

function decToVal(dec, asset) {
const val = dec * Math.pow(10, asset.decimals);
return val;
}

Output

Resulting in the following output:

{
"block": 20187607,
"result": "1 transaction(s) w/ value > 5 eth",
"transactions_clean": [
{
"from": "0xbf0181f23e53a1bb6deec9c8c01b6db590da1b40",
"hash": "0xf8c2abfc4534eecec832367fa264dc97dccec1ae8d0424625c67950e230237a6",
"to": "0x7a250d5630b4cf539739df2c5dacb4c659f2488d",
"units": "eth",
"value": 10
}
],
"transactions_raw": [
{
"accessList": [],
"blockHash": "0x472b139d2c6222e289928a2ce6874850a156a5d34d4c0a64d14ece6e1667d2df",
"blockNumber": "0x13409d7",
"chainId": "0x1",
"from": "0xbf0181f23e53a1bb6deec9c8c01b6db590da1b40",
"gas": "0x32af7e",
"gasPrice": "0x11580ce6d",
"hash": "0xf8c2abfc4534eecec832367fa264dc97dccec1ae8d0424625c67950e230237a6",
"input": "0xf305d71900000000000000000000000076d713ef778acb0a8fa99574fb15a1c2786c49f50000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000008ac7230489e80000000000000000000000000000bf0181f23e53a1bb6deec9c8c01b6db590da1b4000000000000000000000000000000000000000000000000000000000667e3527",
"maxFeePerGas": "0x168fd314d",
"maxPriorityFeePerGas": "0x38f27c79",
"nonce": "0x3d",
"r": "0x734aa57549a899bd78811f28c580f18ac9fe6014907e017eee51e8dfe30977",
"s": "0x351ef09040f88aed41286a2bf9ad9d60d956bbaa03a13ae6c132470977bded1e",
"to": "0x7a250d5630b4cf539739df2c5dacb4c659f2488d",
"transactionIndex": "0x5d",
"type": "0x2",
"v": "0x0",
"value": "0x8ac7230489e80000",
"yParity": "0x0"
}
]
}

Learn more about modifying Stream output.

We ❤️ Feedback!

Let us know if you have any feedback or requests for new topics. We'd love to hear from you.

Share this doc