Last active
January 19, 2024 21:49
-
-
Save obycode/d8c0adc7af1cb4e961013109668c6f6c to your computer and use it in GitHub Desktop.
Block Fee Analysis
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const axios = require("axios"); | |
async function fetchTransactionsAndFeeRates(baseUrl, blockHeight) { | |
let offset = 0; | |
const limit = 50; // Batch size | |
let totalCount = 0; | |
let isFirstRequest = true; | |
let feeRates = []; | |
while (isFirstRequest || offset < totalCount) { | |
const url = `${baseUrl}/extended/v1/tx/block_height/${blockHeight}?limit=${limit}&offset=${offset}`; | |
try { | |
const response = await axios.get(url, { | |
headers: { Accept: "application/json" }, | |
maxBodyLength: Infinity, | |
}); | |
if (isFirstRequest) { | |
totalCount = response.data.total; // Assuming 'total' is the field name | |
isFirstRequest = false; | |
} | |
// Extract fee_rate from each transaction and add it to the feeRates array | |
response.data.results.forEach((tx) => { | |
if (tx.fee_rate !== undefined) { | |
feeRates.push([tx.tx_type, tx.fee_rate]); | |
} | |
}); | |
offset += limit; | |
} catch (error) { | |
if (error.response && error.response.status === 429) { | |
console.log("Rate limit hit, retrying after a delay..."); | |
await new Promise((resolve) => setTimeout(resolve, 10000)); // 10 second delay | |
} else { | |
console.error(error); | |
break; | |
} | |
} | |
} | |
return feeRates; | |
} | |
labels = [ | |
"fee < 0.0001", | |
"0.0001 <= fee < 0.001", | |
"0.001 <= fee < 0.01", | |
"0.01 <= fee < 0.1", | |
"0.1 <= fee < 1", | |
"1 <= fee < 10", | |
"10 <= fee", | |
]; | |
// Function to calculate and display the frequency distribution | |
function calculateFeeDistribution(feeRates, blockHeight) { | |
const distribution = [0, 0, 0, 0, 0, 0, 0]; | |
const distributionByType = { | |
contract_call: [0, 0, 0, 0, 0, 0, 0], | |
token_transfer: [0, 0, 0, 0, 0, 0, 0], | |
smart_contract: [0, 0, 0, 0, 0, 0, 0], | |
}; | |
const txCountByType = { | |
coinbase: 0, | |
contract_call: 0, | |
token_transfer: 0, | |
smart_contract: 0, | |
}; | |
let minFee = Number.MAX_SAFE_INTEGER; | |
// Counting the frequency of each fee rate | |
feeRates.forEach((item) => { | |
const type = item[0]; | |
const fee = item[1]; | |
txCountByType[type] += 1; | |
if (type == "coinbase") { | |
return; | |
} else { | |
minFee = Math.min(minFee, fee); | |
} | |
if (fee < 100) { | |
distribution[0] += 1; | |
distributionByType[type][0] += 1; | |
} else if (fee < 1000) { | |
distribution[1] += 1; | |
distributionByType[type][1] += 1; | |
} else if (fee < 10000) { | |
distribution[2] += 1; | |
distributionByType[type][2] += 1; | |
} else if (fee < 100000) { | |
distribution[3] += 1; | |
distributionByType[type][3] += 1; | |
} else if (fee < 1000000) { | |
distribution[4] += 1; | |
distributionByType[type][4] += 1; | |
} else if (fee < 10000000) { | |
distribution[5] += 1; | |
distributionByType[type][5] += 1; | |
} else if (fee < 10000000) { | |
distribution[6] += 1; | |
distributionByType[type][6] += 1; | |
} | |
}); | |
console.log(`Block ${blockHeight} (${feeRates.length} txs)`); | |
console.log(`Min Fee: ${minFee / 1000000} STX`); | |
console.log(`\nOverall Fee Distribution:`); | |
distribution.forEach((frequency, rate) => { | |
console.log( | |
`${labels[rate]}: ${((frequency / feeRates.length) * 100).toFixed(2)}%` | |
); | |
}); | |
console.log(`\nContract Calls`); | |
distributionByType["contract_call"].forEach((frequency, rate) => { | |
console.log( | |
`${labels[rate]}: ${( | |
(frequency / txCountByType["contract_call"]) * | |
100 | |
).toFixed(2)}%` | |
); | |
}); | |
console.log(`\nToken Transfers`); | |
distributionByType["token_transfer"].forEach((frequency, rate) => { | |
console.log( | |
`${labels[rate]}: ${( | |
(frequency / txCountByType["token_transfer"]) * | |
100 | |
).toFixed(2)}%` | |
); | |
}); | |
console.log("\nTransaction Breakdown"); | |
const totalCount = | |
txCountByType["coinbase"] + | |
txCountByType["contract_call"] + | |
txCountByType["token_transfer"] + | |
txCountByType["smart_contract"]; | |
console.log( | |
`Contract Calls: ${( | |
(txCountByType["contract_call"] / totalCount) * | |
100 | |
).toFixed(2)}%` | |
); | |
console.log( | |
`Token Transfers: ${( | |
(txCountByType["token_transfer"] / totalCount) * | |
100 | |
).toFixed(2)}%` | |
); | |
console.log( | |
`Smart Contracts: ${( | |
(txCountByType["smart_contract"] / totalCount) * | |
100 | |
).toFixed(2)}%` | |
); | |
return distribution; | |
} | |
async function analyzeFeeRates(baseUrl, blockHeight) { | |
const feeRates = await fetchTransactionsAndFeeRates(baseUrl, blockHeight); | |
const distribution = calculateFeeDistribution(feeRates, blockHeight); | |
} | |
// Check if block height is provided as a command line argument | |
if (process.argv.length < 3) { | |
console.log( | |
"Please provide a block height. Usage: node script.js [block_height]" | |
); | |
process.exit(1); | |
} | |
const blockHeight = parseInt(process.argv[2]); | |
if (isNaN(blockHeight) || blockHeight < 0) { | |
console.log( | |
"Invalid block height provided. Please provide a positive integer." | |
); | |
process.exit(1); | |
} | |
// Usage | |
const BASE_URL = "https://api.mainnet.hiro.so"; | |
analyzeFeeRates(BASE_URL, blockHeight); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment