Published
Edited
Jan 4, 2022
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
/*
benchmark("graph2", () => {
if (blocks.length > 0) {
const baseFee66 = baseFeeAtPercentile(66);
return Plot.plot({
height: 200,
marginLeft: 50,
x: {
label: "base fee per gas (gwei) →"
},
y: {
type: "sqrt",
label: "↑ frequency"
},
marks: [
Plot.ruleY([0]),
Plot.rectY(baseFeePerGasBins, {
x1: (d) => d.threshold.start,
x2: (d) => d.threshold.end,
y: (d) => d.size,
fill: colors.blue,
fillOpacity: 0.25
}),
Plot.ruleX([largestBaseFeePerGasBin], {
x: (d) =>
d.threshold.start + (d.threshold.end - d.threshold.start) / 2
}),
Plot.text([largestBaseFeePerGasBin], {
x: (d) => d.threshold.start + 120,
y: (d) => d.size - 2000,
text: (d) =>
`most popular: ${Math.round(d.threshold.start)}–${Math.round(
d.threshold.end + 1
)} gwei`
}),
Plot.ruleX([baseFee66], {
stroke: colors.red
}),
Plot.text([baseFee66], {
fill: colors.red,
x: (d) => d + 90,
y: () => largestBaseFeePerGasBin.size - 6000,
text: () => `66th percentile: ${formatBaseFeePerGas(baseFee66)} gwei`
})
]
});
} else {
return html``;
}
})
*/
Insert cell
Insert cell
/*
{
const tableableBlocks = _.sortBy(blocks, "time").reduce((array, block) => {
return array.concat([
{
Number: block.number,
"Base Fee Per Gas": block.baseFeePerGas,
Time: block.time,
"Time Since Previous":
array.length > 0
? `${
(block.time.getTime() -
array[array.length - 1].Time.getTime()) /
60 /
1000
} s`
: null
}
]);
}, []);
return Inputs.table(tableableBlocks);
}
*/
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// baseFeesAtKeyPercentiles = {
// const allBaseFeesPerGas = blocks
// .map((block) => block.baseFeePerGas)
// .sort((a, b) => a - b);
// return [10, 20, 30, 40, 50, 60, 70, 80, 90, 95].reduce((obj, percentile) => {
// const index = Math.floor(allBaseFeesPerGas.length * (percentile / 100)) - 1;
// return { ...obj, [percentile]: allBaseFeesPerGas[index] };
// }, {});
// }
Insert cell
baseFeeAtPercentile = (percentile) => {
const allBaseFeesPerGas = blocks
.map((block) => block.baseFeePerGas)
.sort((a, b) => a - b);
const index = Math.floor(allBaseFeesPerGas.length * (percentile / 100));
return allBaseFeesPerGas[index];
}
Insert cell
networkCongestion = {
const latestBaseFeePerGas = lastBlock?.baseFeePerGas;
const sortedBaseFeesPerGas = blocks
.map((block) => block.baseFeePerGas)
.sort((a, b) => a - b);
const indexOfBaseFeeNearestToLatest = sortedBaseFeesPerGas.findIndex(
(baseFeePerGas) => baseFeePerGas >= latestBaseFeePerGas
);
return indexOfBaseFeeNearestToLatest !== -1
? indexOfBaseFeeNearestToLatest / (sortedBaseFeesPerGas.length - 1)
: null;
}
Insert cell
Insert cell
Insert cell
Insert cell
baseFeePerGasBins = {
// Partition into percentiles
// Source: <https://observablehq.com/@d3/d3-bin>
/*
const bin = d3
.bin()
.thresholds((data, min, max) =>
d3.range(10).map((t) => min + (t / 10) * (max - min))
)
.value((d) => d.baseFeePerGas);
const bins = bin(blocks);
// console.log("bins", bins);
return bins.map((bin) => {
const threshold = { start: bin.x0, end: bin.x1 };
const size = bin.length;
return { threshold, size };
});
*/

const allBaseFeesPerGas = blocks
.map((block) => block.baseFeePerGas)
.sort((a, b) => a - b);
const chunkRequests = _.uniqBy(
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100].map((percentile) => {
const index = Math.floor(allBaseFeesPerGas.length * (percentile / 100));
return { percentile, index };
}),
"index"
);
// console.log(
// "allBaseFeesPerGas",
// allBaseFeesPerGas,
// "chunkRequests",
// chunkRequests
// );
const bins = [];
for (let i = 0; i < chunkRequests.length - 1; i++) {
const [chunkRequest, nextChunkRequest] = [
chunkRequests[i],
chunkRequests[i + 1]
];
const chunk = allBaseFeesPerGas.slice(
chunkRequest.index,
nextChunkRequest.index
);
bins.push({
threshold: {
start: chunk[0],
end: chunk[chunk.length - 1]
},
size: chunk.length
});
}
return bins;

/*
const minBaseFeePerGas = _.min(baseFeesPerGas);
const maxBaseFeePerGas = _.max(baseFeesPerGas);
const size
const binThresholds = _.range(
0,
Math.floor(maxBaseFeePerGas / binSize) * binSize,
binSize
);
const initialBins = binThresholds.reduce((bins, threshold) => {
return { ...bins, [threshold]: 0 };
}, {});
const bins = blocks.reduce((bins, block) => {
const nearestThreshold =
Math.floor(block.baseFeePerGas / binSize) * binSize;
return { ...bins, [nearestThreshold]: bins[nearestThreshold] + 1 };
}, initialBins);

return binThresholds.map((threshold) => {
return {
threshold: { start: threshold, end: threshold + binSize - 1 },
size: bins[threshold]
};
});
*/
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// chunkRequests = {
// const chunkRequests = [];
// for (
// let newestBlock = newestBlockNumber;
// newestBlock > oldestBlockNumberToRequest;
// newestBlock -= numberOfBlocksPerEthFeeHistoryRequest
// ) {
// const distanceToEnd = newestBlock - oldestBlockNumberToRequest;
// const blockCount =
// distanceToEnd < numberOfBlocksPerEthFeeHistoryRequest
// ? distanceToEnd
// : numberOfBlocksPerEthFeeHistoryRequest;
// chunkRequests.push({ blockCount, newestBlock });
// }
// return chunkRequests;
// }
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// db.blocks.reverse().limit(100).toArray()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
formatPercentile = (number) => {
const percentage = Math.round(number * 100);
const percentageAsString = percentage.toString();
let suffix;
switch (percentageAsString[percentageAsString.length - 1]) {
case "1":
suffix = "st";
break;
case "2":
suffix = "nd";
break;
case "3":
suffix = "rd";
break;
default:
suffix = "th";
break;
}
return `${percentage}${suffix}`;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
isDisabled = false
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// secret("foo", { label: "something else" })
Insert cell
// secret("foo2", { label: "something else", type: "textarea" })
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Plot.plot({
// width,
// height: 200,
// x: {
// domain: [
// new Date(latestBlock.time.getTime() - 60 * 60 * 24 * 1 * 1000),
// latestBlock.time
// ],
// nice: true,
// label: "time (in your tz) →"
// },
// y: {
// grid: true,
// label: "↑ base fee per gas (gwei)"
// },
// marks: [
// Plot.ruleY([0]),
// Plot.line(blocks, {
// x: "time",
// y: "baseFeePerGas",
// stroke: colors.blue,
// strokeOpacity: 0.25
// }),
// Plot.line(
// blocks,
// Plot.windowY({
// x: "time",
// y: "baseFeePerGas",
// reduce: "mean",
// k: 50,
// anchor: "end",
// stroke: colors.blue
// })
// )
// ]
// })
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more