harb/subgraph/harb/src/harb.ts
2024-05-29 17:26:19 +02:00

222 lines
7.9 KiB
TypeScript

import {
Approval as ApprovalEvent,
EIP712DomainChanged as EIP712DomainChangedEvent,
Transfer as TransferEvent,
UbiClaimed as UbiClaimedEvent
} from "../generated/Harb/Harb";
import { BigInt, Bytes, ethereum, Address, log } from "@graphprotocol/graph-ts";
import { Stats } from "../generated/schema"
// Helper function to get or create Stats entity
function getOrCreateStats(): Stats {
let stats = Stats.load(Bytes.fromHexString("0x01") as Bytes);
if (stats == null) {
stats = new Stats(Bytes.fromHexString("0x01") as Bytes);
stats.outstandingSupply = BigInt.zero();
stats.activeSupply = BigInt.zero();
// Minted
stats.totalMinted = BigInt.zero();
stats.mintedLastWeek = BigInt.zero();
stats.mintedLastDay = BigInt.zero();
stats.mintNextHourProjected = BigInt.zero();
// Burned
stats.totalBurned = BigInt.zero();
stats.burnedLastWeek = BigInt.zero();
stats.burnedLastDay = BigInt.zero();
stats.burnNextHourProjected = BigInt.zero();
// Tax paid
stats.totalTaxPaid = BigInt.zero();
stats.taxPaidLastWeek = BigInt.zero();
stats.taxPaidLastDay = BigInt.zero();
stats.taxNextHourProjected = BigInt.zero();
// UBI claimed
stats.totalUbiClaimed = BigInt.zero();
stats.ubiClaimedLastWeek = BigInt.zero();
stats.ubiClaimedLastDay = BigInt.zero();
stats.ubiNextHourProjected = BigInt.zero();
stats.ringBuffer = new Array<BigInt>(168 * 4).fill(BigInt.zero());
stats.ringBufferPointer = 0;
stats.lastUpdatedHour = 0;
}
return stats;
}
export function handleUbiClaimed(event: UbiClaimedEvent): void {
let stats = getOrCreateStats();
// Get a copy of the ring buffer
let ringBuffer = stats.ringBuffer;
// Update total UBI claimed
stats.totalUbiClaimed = stats.totalUbiClaimed.plus(event.params.ubiAmount);
// Add the UBI amount to the current hour's total in the ring buffer
let ubiBufferIndex = (stats.ringBufferPointer * 4) + 0; // UBI is at index 0
ringBuffer[ubiBufferIndex] = ringBuffer[ubiBufferIndex].plus(event.params.ubiAmount);
// Update the ring buffer in the stats entity
stats.ringBuffer = ringBuffer;
// Save the updated Stats entity
stats.save();
}
export function handleTransfer(event: TransferEvent): void {
let ZERO_ADDRESS = Address.fromString("0x0000000000000000000000000000000000000000");
let TAX_POOL_ADDR = Address.fromString("0x0000000000000000000000000000000000000002");
let stats = getOrCreateStats();
// Get a copy of the ring buffer
let ringBuffer = stats.ringBuffer;
// Determine if it's a mint or burn event
if (event.params.from == ZERO_ADDRESS) {
// Mint event
stats.totalMinted = stats.totalMinted.plus(event.params.value);
// Add the minted amount to the current hour's total in the ring buffer
let mintBufferIndex = (stats.ringBufferPointer * 4) + 1; // Minted tokens are at index 1
ringBuffer[mintBufferIndex] = ringBuffer[mintBufferIndex].plus(event.params.value);
} else if (event.params.to == ZERO_ADDRESS) {
// Burn event
stats.totalBurned = stats.totalBurned.plus(event.params.value);
// Add the burned amount to the current hour's total in the ring buffer
let burnBufferIndex = (stats.ringBufferPointer * 4) + 2; // Burned tokens are at index 2
ringBuffer[burnBufferIndex] = ringBuffer[burnBufferIndex].plus(event.params.value);
} else if (event.params.to == TAX_POOL_ADDR) {
// Tax paid event
stats.totalTaxPaid = stats.totalTaxPaid.plus(event.params.value);
// Add the burned amount to the current hour's total in the ring buffer
let taxBufferIndex = (stats.ringBufferPointer * 4) + 3; // tax paid is at index 3
ringBuffer[taxBufferIndex] = ringBuffer[taxBufferIndex].plus(event.params.value);
}
// Update the ring buffer in the stats entity
stats.ringBuffer = ringBuffer;
// Save the updated Stats entity
stats.save();
}
// Block handler to aggregate stats
export function handleBlock(block: ethereum.Block): void {
// Update Stats entity
let stats = getOrCreateStats();
// Get a copy of the ring buffer
let ringBuffer = stats.ringBuffer;
// Calculate the current hour
let currentHour = block.timestamp.toI32() / 3600;
// Check if we've moved to a new hour
if (currentHour > stats.lastUpdatedHour) {
// Move the ring buffer pointer forward
stats.ringBufferPointer = (stats.ringBufferPointer + 1) % 168;
// Reset the new current hour in the ring buffer
let baseIndex = stats.ringBufferPointer * 4;
ringBuffer[baseIndex] = BigInt.zero(); // UBI claimed
ringBuffer[baseIndex + 1] = BigInt.zero(); // Minted tokens
ringBuffer[baseIndex + 2] = BigInt.zero(); // Burned tokens
// Update the last updated hour
stats.lastUpdatedHour = currentHour;
// Recalculate the sum of the last 7 days and 24 hours
let mintedLastWeek = BigInt.zero();
let burnedLastWeek = BigInt.zero();
let taxPaidLastWeek = BigInt.zero();
let ubiClaimedLastWeek = BigInt.zero();
let mintedLastDay = BigInt.zero();
let burnedLastDay = BigInt.zero();
let taxPaidLastDay = BigInt.zero();
let ubiClaimedLastDay = BigInt.zero();
for (let i = 0; i < 168; i++) {
let index = ((stats.ringBufferPointer - i + 168) % 168) * 4;
ubiClaimedLastWeek = ubiClaimedLastWeek.plus(ringBuffer[index]);
mintedLastWeek = mintedLastWeek.plus(ringBuffer[index + 1]);
burnedLastWeek = burnedLastWeek.plus(ringBuffer[index + 2]);
taxPaidLastWeek = taxPaidLastWeek.plus(ringBuffer[index + 3]);
if (i < 24) {
ubiClaimedLastDay = ubiClaimedLastDay.plus(ringBuffer[index]);
mintedLastDay = mintedLastDay.plus(ringBuffer[index + 1]);
burnedLastDay = burnedLastDay.plus(ringBuffer[index + 2]);
taxPaidLastDay = taxPaidLastDay.plus(ringBuffer[index + 3]);
}
}
stats.mintedLastWeek = mintedLastWeek;
stats.burnedLastWeek = burnedLastWeek;
stats.taxPaidLastWeek = taxPaidLastWeek;
stats.ubiClaimedLastWeek = ubiClaimedLastWeek;
stats.mintedLastDay = mintedLastDay;
stats.burnedLastDay = burnedLastDay;
stats.taxPaidLastDay = taxPaidLastDay;
stats.ubiClaimedLastDay = ubiClaimedLastDay;
// Update the ring buffer in the stats entity
stats.ringBuffer = ringBuffer;
} else {
// update projected stats with every block
// Calculate the elapsed time in the current hour
let currentTimestamp = block.timestamp.toI32();
let startOfHour = (currentTimestamp / 3600) * 3600;
let elapsedSeconds = currentTimestamp - startOfHour;
for (var i = 0; i <= 3; i++) {
let bufferIndex = (stats.ringBufferPointer * 4) + i;
// Project the current hour's total based on the average rate of burned tokens in the current hour
let projectedTotal = ringBuffer[bufferIndex].times(BigInt.fromI32(3600)).div(BigInt.fromI32(elapsedSeconds));
// Calculate the medium between the previous hour and the projection
let previousHourTotal = ringBuffer[((stats.ringBufferPointer - 1 + 168) % 168) * 4 + i];
log.info("projecting stats : {} projected total: {}. previous hour Total: {}. medium: {}", [
i.toString(),
projectedTotal.toString(),
previousHourTotal.toString(),
previousHourTotal.plus(projectedTotal).div(BigInt.fromI32(2)).toString(),
]);
let medium = previousHourTotal.plus(projectedTotal).div(BigInt.fromI32(2));
if (i == 0) {
stats.ubiNextHourProjected = (medium > BigInt.zero()) ? medium : stats.ubiClaimedLastWeek.div(BigInt.fromI32(7));
} else if (i == 1) {
stats.mintNextHourProjected = (medium > BigInt.zero()) ? medium : stats.mintedLastWeek.div(BigInt.fromI32(7));
} else if (i == 2) {
stats.burnNextHourProjected = (medium > BigInt.zero()) ? medium : stats.burnedLastWeek.div(BigInt.fromI32(7));
} else if (i == 3) {
stats.taxNextHourProjected = (medium > BigInt.zero()) ? medium : stats.taxPaidLastWeek.div(BigInt.fromI32(7));
}
}
}
// Save the updated Stats entity
stats.save();
}