added csv serializer
This commit is contained in:
parent
4b86637a40
commit
5d209e5e19
6 changed files with 325 additions and 171 deletions
|
|
@ -2,7 +2,7 @@
|
|||
src = "src"
|
||||
out = "out"
|
||||
libs = ["lib"]
|
||||
fs_permissions = [{ access = "read", path = "./"}]
|
||||
fs_permissions = [{ access = "read-write", path = "./"}]
|
||||
# See more config options https://github.com/foundry-rs/foundry/tree/master/config
|
||||
|
||||
[rpc_endpoints]
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ contract BaseLineLP {
|
|||
uint256 private lastDay;
|
||||
uint256 private mintedToday;
|
||||
|
||||
mapping(Stage => TokenPosition) positions;
|
||||
mapping(Stage => TokenPosition) public positions;
|
||||
|
||||
modifier checkDeadline(uint256 deadline) {
|
||||
require(block.timestamp <= deadline, "Transaction too old");
|
||||
|
|
@ -103,27 +103,6 @@ contract BaseLineLP {
|
|||
|
||||
}
|
||||
|
||||
function createPosition(Stage positionIndex, int24 tickLower, int24 tickUpper, uint256 amount) internal {
|
||||
uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower);
|
||||
uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper);
|
||||
uint128 liquidity = LiquidityAmounts.getLiquidityForAmount1(
|
||||
sqrtRatioAX96, sqrtRatioBX96, amount
|
||||
);
|
||||
pool.mint(address(this), tickLower, tickUpper, liquidity, abi.encode(poolKey));
|
||||
// TODO: check slippage
|
||||
// read position and start tracking in storage
|
||||
bytes32 positionKey = PositionKey.compute(address(this), tickLower, tickUpper);
|
||||
(, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128,,) = pool.positions(positionKey);
|
||||
positions[positionIndex] = TokenPosition({
|
||||
liquidity: liquidity,
|
||||
tickLower: tickLower,
|
||||
tickUpper: tickUpper,
|
||||
feeGrowthInside0LastX128: feeGrowthInside0LastX128,
|
||||
feeGrowthInside1LastX128: feeGrowthInside1LastX128
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function outstanding() public view returns (uint256 _outstanding) {
|
||||
_outstanding = harb.totalSupply() - harb.balanceOf(address(pool)) - harb.balanceOf(address(this));
|
||||
}
|
||||
|
|
@ -133,17 +112,47 @@ contract BaseLineLP {
|
|||
}
|
||||
|
||||
|
||||
function ethIn(Stage s) public view returns (uint256 _ethInPosition) {
|
||||
function tokensIn(Stage s) public view returns (uint256 _ethInPosition, uint256 _harbInPosition) {
|
||||
uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(positions[s].tickLower);
|
||||
uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(positions[s].tickUpper);
|
||||
if (token0isWeth) {
|
||||
_ethInPosition = LiquidityAmounts.getAmount0ForLiquidity(
|
||||
sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity / 2
|
||||
);
|
||||
if (s == Stage.FLOOR) {
|
||||
_ethInPosition = LiquidityAmounts.getAmount0ForLiquidity(
|
||||
sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity
|
||||
);
|
||||
_harbInPosition = 0;
|
||||
} else if (s == Stage.ANCHOR) {
|
||||
_ethInPosition = LiquidityAmounts.getAmount0ForLiquidity(
|
||||
sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity / 2
|
||||
);
|
||||
_harbInPosition = LiquidityAmounts.getAmount1ForLiquidity(
|
||||
sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity / 2
|
||||
);
|
||||
} else {
|
||||
_ethInPosition = 0;
|
||||
_harbInPosition = LiquidityAmounts.getAmount1ForLiquidity(
|
||||
sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_ethInPosition = LiquidityAmounts.getAmount1ForLiquidity(
|
||||
sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity / 2
|
||||
);
|
||||
if (s == Stage.FLOOR) {
|
||||
_ethInPosition = LiquidityAmounts.getAmount1ForLiquidity(
|
||||
sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity
|
||||
);
|
||||
_harbInPosition = 0;
|
||||
} else if (s == Stage.ANCHOR) {
|
||||
_ethInPosition = LiquidityAmounts.getAmount1ForLiquidity(
|
||||
sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity / 2
|
||||
);
|
||||
_harbInPosition = LiquidityAmounts.getAmount0ForLiquidity(
|
||||
sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity / 2
|
||||
);
|
||||
} else {
|
||||
_ethInPosition = 0;
|
||||
_harbInPosition = LiquidityAmounts.getAmount0ForLiquidity(
|
||||
sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,7 +391,7 @@ contract BaseLineLP {
|
|||
|
||||
// ## set new positions
|
||||
// reduce Anchor by 10% of new ETH. It will be moved into Floor
|
||||
uint256 initialEthInAnchor = ethIn(Stage.ANCHOR);
|
||||
(uint256 initialEthInAnchor,) = tokensIn(Stage.ANCHOR);
|
||||
ethInAnchor -= (ethInAnchor - initialEthInAnchor) * 10 / LIQUIDITY_RATIO_DIVISOR;
|
||||
|
||||
|
||||
|
|
@ -440,8 +449,8 @@ contract BaseLineLP {
|
|||
// TODO: set only discovery
|
||||
return;
|
||||
}
|
||||
uint256 ethInAnchor = ethIn(Stage.ANCHOR);
|
||||
uint256 ethInFloor = ethIn(Stage.FLOOR);
|
||||
(uint256 ethInAnchor,) = tokensIn(Stage.ANCHOR);
|
||||
(uint256 ethInFloor,) = tokensIn(Stage.FLOOR);
|
||||
|
||||
// use previous ration of Floor to Anchor
|
||||
uint256 ethInNewAnchor = ethBalance / 10;
|
||||
|
|
|
|||
|
|
@ -2,29 +2,27 @@
|
|||
pragma solidity ^0.8.19;
|
||||
|
||||
import "forge-std/Test.sol";
|
||||
import "forge-std/console.sol";
|
||||
import {TwabController} from "pt-v5-twab-controller/TwabController.sol";
|
||||
import {PoolAddress, PoolKey} from "@aperture/uni-v3-lib/PoolAddress.sol";
|
||||
import "@uniswap-v3-core/interfaces/IUniswapV3Factory.sol";
|
||||
import "@uniswap-v3-core/interfaces/IUniswapV3Pool.sol";
|
||||
import "@aperture/uni-v3-lib/TickMath.sol";
|
||||
import "../src/interfaces/IWETH9.sol";
|
||||
import {WETH} from "solmate/tokens/WETH.sol";
|
||||
import "../src/Harb.sol";
|
||||
import {BaseLineLP} from "../src/BaseLineLP.sol";
|
||||
import {Stake, ExceededAvailableStake} from "../src/Stake.sol";
|
||||
import "./helpers/PoolSerializer.sol";
|
||||
|
||||
address constant TAX_POOL = address(2);
|
||||
// default fee of 1%
|
||||
uint24 constant FEE = uint24(10_000);
|
||||
|
||||
contract BaseLineLPTest is Test {
|
||||
contract BaseLineLPTest is PoolSerializer {
|
||||
uint256 mainnetFork;
|
||||
IWETH9 weth;
|
||||
Harb harb;
|
||||
IUniswapV3Factory factory;
|
||||
Stake stake;
|
||||
BaseLineLP liquidityManager;
|
||||
BaseLineLP lm;
|
||||
IUniswapV3Pool pool;
|
||||
bool token0isWeth;
|
||||
|
||||
|
|
@ -83,32 +81,32 @@ contract BaseLineLPTest is Test {
|
|||
|
||||
stake = new Stake(address(harb));
|
||||
harb.setStakingPool(address(stake));
|
||||
liquidityManager = new BaseLineLP(factoryAddress, address(weth), address(harb));
|
||||
harb.setLiquidityManager(address(liquidityManager));
|
||||
lm = new BaseLineLP(factoryAddress, address(weth), address(harb));
|
||||
harb.setLiquidityManager(address(lm));
|
||||
createCSVHeader();
|
||||
}
|
||||
|
||||
function testLP(address account) public {
|
||||
vm.assume(account != address(0));
|
||||
vm.assume(account != address(1)); // TWAB sponsorship address
|
||||
vm.assume(account != address(2)); // tax pool address
|
||||
vm.deal(account, 15 ether);
|
||||
|
||||
function test_LP() public {
|
||||
address account = makeAddr("alice");
|
||||
vm.deal(account, 20 ether);
|
||||
vm.prank(account);
|
||||
(bool sent, ) = address(liquidityManager).call{value: 10 ether}("");
|
||||
(bool sent, ) = address(lm).call{value: 10 ether}("");
|
||||
require(sent, "Failed to send Ether");
|
||||
|
||||
// Try to shift liquidity manager's state, expect failure due to initial state
|
||||
vm.expectRevert();
|
||||
liquidityManager.shift();
|
||||
lm.shift();
|
||||
|
||||
// Setup of liquidity
|
||||
liquidityManager.slide();
|
||||
|
||||
lm.slide();
|
||||
appendPossitions(lm, pool, token0isWeth);
|
||||
|
||||
// Small buy into Anchor
|
||||
vm.prank(account);
|
||||
weth.deposit{value: 5 ether}();
|
||||
weth.deposit{value: 10 ether}();
|
||||
vm.prank(account);
|
||||
weth.approve(address(this), 5 ether);
|
||||
weth.approve(address(this), 10 ether);
|
||||
pool.swap(
|
||||
account, // Recipient of the output tokens
|
||||
token0isWeth,
|
||||
|
|
@ -117,7 +115,8 @@ contract BaseLineLPTest is Test {
|
|||
abi.encode(account, int256(0.5 ether), true)
|
||||
);
|
||||
|
||||
liquidityManager.shift();
|
||||
lm.shift();
|
||||
appendPossitions(lm, pool, token0isWeth);
|
||||
|
||||
// large buy into discovery
|
||||
pool.swap(
|
||||
|
|
@ -128,12 +127,13 @@ contract BaseLineLPTest is Test {
|
|||
abi.encode(account, int256(3 ether), true)
|
||||
);
|
||||
|
||||
liquidityManager.shift();
|
||||
lm.shift();
|
||||
appendPossitions(lm, pool, token0isWeth);
|
||||
|
||||
|
||||
// sell into anchor
|
||||
vm.prank(account);
|
||||
harb.approve(address(this), 2000000 ether);
|
||||
harb.approve(address(this), 12000000 ether);
|
||||
pool.swap(
|
||||
account, // Recipient of the output tokens
|
||||
!token0isWeth,
|
||||
|
|
@ -142,24 +142,29 @@ contract BaseLineLPTest is Test {
|
|||
abi.encode(account, int256(300000 ether), false)
|
||||
);
|
||||
|
||||
liquidityManager.slide();
|
||||
lm.slide();
|
||||
appendPossitions(lm, pool, token0isWeth);
|
||||
|
||||
// large sell into floor
|
||||
harb.setLiquidityManager(address(account));
|
||||
vm.prank(account);
|
||||
harb.mint(900000 ether);
|
||||
harb.setLiquidityManager(address(liquidityManager));
|
||||
harb.mint(3600000 ether);
|
||||
harb.setLiquidityManager(address(lm));
|
||||
pool.swap(
|
||||
account, // Recipient of the output tokens
|
||||
!token0isWeth,
|
||||
int256(900000 ether),
|
||||
int256(3600000 ether),
|
||||
!token0isWeth ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1,
|
||||
abi.encode(account, int256(900000 ether), false)
|
||||
abi.encode(account, int256(3600000 ether), false)
|
||||
);
|
||||
// add to CSV
|
||||
|
||||
liquidityManager.slide();
|
||||
lm.slide();
|
||||
appendPossitions(lm, pool, token0isWeth);
|
||||
writeCsv();
|
||||
}
|
||||
|
||||
|
||||
/*//////////////////////////////////////////////////////////////
|
||||
CALLBACKS
|
||||
//////////////////////////////////////////////////////////////*/
|
||||
|
|
|
|||
111
onchain/test/helpers/PoolSerializer.sol
Normal file
111
onchain/test/helpers/PoolSerializer.sol
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "forge-std/Test.sol";
|
||||
import {BaseLineLP} from "../../src/BaseLineLP.sol";
|
||||
import "@uniswap-v3-core/interfaces/IUniswapV3Pool.sol";
|
||||
|
||||
contract PoolSerializer is Test {
|
||||
string csv;
|
||||
|
||||
// Helper function to convert uint to string
|
||||
function uintToStr(uint256 _i) internal pure returns (string memory _uintAsString) {
|
||||
if (_i == 0) {
|
||||
return "0";
|
||||
}
|
||||
uint256 j = _i;
|
||||
uint256 len;
|
||||
while (j != 0) {
|
||||
len++;
|
||||
j /= 10;
|
||||
}
|
||||
bytes memory bstr = new bytes(len);
|
||||
uint256 k = len;
|
||||
while (_i != 0) {
|
||||
k = k-1;
|
||||
uint8 temp = (48 + uint8(_i - _i / 10 * 10));
|
||||
bytes1 b1 = bytes1(temp);
|
||||
bstr[k] = b1;
|
||||
_i /= 10;
|
||||
}
|
||||
return string(bstr);
|
||||
}
|
||||
|
||||
// Helper function to convert int to string
|
||||
function intToStr(int256 _i) internal pure returns (string memory) {
|
||||
if (_i == 0) {
|
||||
return "0";
|
||||
}
|
||||
bool negative = _i < 0;
|
||||
uint256 j = uint256(negative ? -_i : _i);
|
||||
uint256 len;
|
||||
while (j != 0) {
|
||||
len++;
|
||||
j /= 10;
|
||||
}
|
||||
if (negative) {
|
||||
len++;
|
||||
}
|
||||
bytes memory bstr = new bytes(len);
|
||||
uint256 k = len;
|
||||
uint256 l = uint256(negative ? -_i : _i);
|
||||
while (l != 0) {
|
||||
k = k-1;
|
||||
uint8 temp = (48 + uint8(l - l / 10 * 10));
|
||||
bytes1 b1 = bytes1(temp);
|
||||
bstr[k] = b1;
|
||||
l /= 10;
|
||||
}
|
||||
if (negative) {
|
||||
bstr[0] = '-';
|
||||
}
|
||||
return string(bstr);
|
||||
}
|
||||
|
||||
function createCSVHeader() public {
|
||||
csv = "FLOOR liquidity, FLOOR tickLower, FLOOR tickUpper, FLOOR ETH, FLOOR HARB, ANCHOR liquidity, ANCHOR tickLower, ANCHOR tickUpper, ANCHOR ETH, ANCHOR HARB, DISCOVERY liquidity, DISCOVERY tickLower, DISCOVERY tickUpper, DISCOVERY ETH, DISCOVERY HARB, CURRENT TICK";
|
||||
}
|
||||
|
||||
function appendPossitions(BaseLineLP lm, IUniswapV3Pool pool, bool token0isWeth) public {
|
||||
(, int24 tickLower, int24 tickUpper,,) = lm.positions(BaseLineLP.Stage.FLOOR);
|
||||
(uint128 liquidity,,, uint128 tokensOwed0, uint128 tokensOwed1
|
||||
) = pool.positions(keccak256(abi.encodePacked(address(lm), tickLower, tickUpper)));
|
||||
string memory floorData = string(abi.encodePacked(
|
||||
uintToStr(liquidity), ",",
|
||||
intToStr(tickLower), ",",
|
||||
intToStr(tickUpper), ",",
|
||||
uintToStr(token0isWeth ? tokensOwed0 : tokensOwed1), ",",
|
||||
uintToStr(token0isWeth ? tokensOwed1 : tokensOwed0), ","
|
||||
));
|
||||
|
||||
(liquidity, tickLower, tickUpper,,) = lm.positions(BaseLineLP.Stage.ANCHOR);
|
||||
(uint256 ethAmount, uint256 harbAmount) = lm.tokensIn(BaseLineLP.Stage.ANCHOR);
|
||||
string memory anchorData = string(abi.encodePacked(
|
||||
uintToStr(liquidity), ",",
|
||||
intToStr(tickLower), ",",
|
||||
intToStr(tickUpper), ",",
|
||||
uintToStr(ethAmount), ",",
|
||||
uintToStr(harbAmount), ","
|
||||
));
|
||||
|
||||
(liquidity, tickLower, tickUpper,,) = lm.positions(BaseLineLP.Stage.DISCOVERY);
|
||||
(ethAmount, harbAmount) = lm.tokensIn(BaseLineLP.Stage.DISCOVERY);
|
||||
(, int24 currentTick, , , , , ) = pool.slot0();
|
||||
string memory discoveryData = string(abi.encodePacked(
|
||||
uintToStr(liquidity), ",",
|
||||
intToStr(tickLower), ",",
|
||||
intToStr(tickUpper), ",",
|
||||
uintToStr(ethAmount), ",",
|
||||
uintToStr(harbAmount), ",",
|
||||
intToStr(currentTick)
|
||||
));
|
||||
|
||||
csv = string(abi.encodePacked(csv, "\n", floorData, anchorData, discoveryData));
|
||||
}
|
||||
|
||||
function writeCsv() public {
|
||||
string memory path = "./out/positions.csv";
|
||||
vm.writeFile(path, csv);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,11 +7,6 @@ type Stats @entity {
|
|||
outstandingSupply: BigInt! # uint256
|
||||
activeSupply: BigInt! # uint256
|
||||
|
||||
totalUbiClaimed: BigInt! # field to track total UBI claimed
|
||||
ubiClaimedLastWeek: BigInt!
|
||||
ubiClaimedLastDay: BigInt! # field to track UBI claimed in the last 24
|
||||
ubiClaimedLastHour: BigInt!
|
||||
|
||||
ringBuffer: [BigInt!]! # Ring buffer to store daily totals
|
||||
ringBufferPointer: Int! # Pointer to the current day in the ring buffer
|
||||
lastUpdatedHour: Int! # The last updated day boundary (timestamp in days)
|
||||
|
|
@ -19,12 +14,22 @@ type Stats @entity {
|
|||
totalMinted: BigInt!
|
||||
mintedLastWeek: BigInt!
|
||||
mintedLastDay: BigInt!
|
||||
mintedLastHour: BigInt!
|
||||
mintNextHourProjected: BigInt!
|
||||
|
||||
totalBurned: BigInt!
|
||||
burnedLastWeek: BigInt!
|
||||
burnedLastDay: BigInt!
|
||||
burnedLastHour: BigInt!
|
||||
burnNextHourProjected: BigInt!
|
||||
|
||||
totalTaxPaid: BigInt!
|
||||
taxPaidLastWeek: BigInt!
|
||||
taxPaidLastDay: BigInt!
|
||||
taxNextHourProjected: BigInt!
|
||||
|
||||
totalUbiClaimed: BigInt!
|
||||
ubiClaimedLastWeek: BigInt!
|
||||
ubiClaimedLastDay: BigInt!
|
||||
ubiNextHourProjected: BigInt!
|
||||
}
|
||||
|
||||
enum PositionStatus {
|
||||
|
|
|
|||
|
|
@ -15,22 +15,32 @@ function getOrCreateStats(): Stats {
|
|||
stats = new Stats(Bytes.fromHexString("0x01") as Bytes);
|
||||
stats.outstandingSupply = BigInt.zero();
|
||||
stats.activeSupply = BigInt.zero();
|
||||
stats.totalUbiClaimed = BigInt.zero();
|
||||
stats.ubiClaimedLastWeek = BigInt.zero();
|
||||
stats.ubiClaimedLastDay = BigInt.zero();
|
||||
stats.ubiClaimedLastHour = BigInt.zero();
|
||||
|
||||
// Minted
|
||||
stats.totalMinted = BigInt.zero();
|
||||
stats.mintedLastWeek = BigInt.zero();
|
||||
stats.mintedLastDay = BigInt.zero();
|
||||
stats.mintedLastHour = BigInt.zero();
|
||||
stats.mintNextHourProjected = BigInt.zero();
|
||||
|
||||
// Burned
|
||||
stats.totalBurned = BigInt.zero();
|
||||
stats.burnedLastWeek = BigInt.zero();
|
||||
stats.burnedLastDay = BigInt.zero();
|
||||
stats.burnedLastHour = BigInt.zero();
|
||||
stats.burnNextHourProjected = BigInt.zero();
|
||||
|
||||
stats.ringBuffer = new Array<BigInt>(168 * 3).fill(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;
|
||||
}
|
||||
|
|
@ -38,71 +48,6 @@ function getOrCreateStats(): Stats {
|
|||
}
|
||||
|
||||
|
||||
|
||||
export function handleTransfer(event: TransferEvent): void {
|
||||
let ZERO_ADDRESS = Address.fromString("0x0000000000000000000000000000000000000000");
|
||||
|
||||
// Update Stats entity
|
||||
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 * 3) + 1; // Minted tokens are at index 1
|
||||
ringBuffer[mintBufferIndex] = ringBuffer[mintBufferIndex].plus(event.params.value);
|
||||
|
||||
// Calculate the elapsed time in the current hour
|
||||
let currentTimestamp = event.block.timestamp.toI32();
|
||||
let startOfHour = (currentTimestamp / 3600) * 3600;
|
||||
let elapsedSeconds = currentTimestamp - startOfHour;
|
||||
|
||||
// Project the current hour's total based on the average rate of minted tokens in the current hour
|
||||
let projectedTotal = ringBuffer[mintBufferIndex].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) * 3 + 1];
|
||||
stats.mintedLastHour = previousHourTotal.plus(projectedTotal).div(BigInt.fromI32(2));
|
||||
|
||||
log.info("transfer handler: Recalculated totals. projected total: {}. previous hour total: {}. medium: {}.", [
|
||||
projectedTotal.toString(),
|
||||
previousHourTotal.toString(),
|
||||
stats.burnedLastHour.toString(),
|
||||
]);
|
||||
|
||||
} 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 * 3) + 2; // Burned tokens are at index 2
|
||||
ringBuffer[burnBufferIndex] = ringBuffer[burnBufferIndex].plus(event.params.value);
|
||||
|
||||
// Calculate the elapsed time in the current hour
|
||||
let currentTimestamp = event.block.timestamp.toI32();
|
||||
let startOfHour = (currentTimestamp / 3600) * 3600;
|
||||
let elapsedSeconds = currentTimestamp - startOfHour;
|
||||
|
||||
// Project the current hour's total based on the average rate of burned tokens in the current hour
|
||||
let projectedTotal = ringBuffer[burnBufferIndex].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) * 3 + 2];
|
||||
stats.burnedLastHour = previousHourTotal.plus(projectedTotal).div(BigInt.fromI32(2));
|
||||
}
|
||||
|
||||
// Update the ring buffer in the stats entity
|
||||
stats.ringBuffer = ringBuffer;
|
||||
|
||||
// Save the updated Stats entity
|
||||
stats.save();
|
||||
}
|
||||
|
||||
export function handleUbiClaimed(event: UbiClaimedEvent): void {
|
||||
|
||||
let stats = getOrCreateStats();
|
||||
|
|
@ -114,20 +59,51 @@ export function handleUbiClaimed(event: UbiClaimedEvent): void {
|
|||
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 * 3) + 0; // UBI is at index 0
|
||||
let ubiBufferIndex = (stats.ringBufferPointer * 4) + 0; // UBI is at index 0
|
||||
ringBuffer[ubiBufferIndex] = ringBuffer[ubiBufferIndex].plus(event.params.ubiAmount);
|
||||
|
||||
// Calculate the elapsed time in the current hour
|
||||
let currentTimestamp = event.block.timestamp.toI32();
|
||||
let startOfHour = (currentTimestamp / 3600) * 3600;
|
||||
let elapsedSeconds = currentTimestamp - startOfHour;
|
||||
// Update the ring buffer in the stats entity
|
||||
stats.ringBuffer = ringBuffer;
|
||||
|
||||
// Project the current hour's total based on the average rate of UBI claims in the current hour
|
||||
let projectedTotal = ringBuffer[ubiBufferIndex].times(BigInt.fromI32(3600)).div(BigInt.fromI32(elapsedSeconds));
|
||||
// Save the updated Stats entity
|
||||
stats.save();
|
||||
}
|
||||
|
||||
// Calculate the medium between the previous hour and the projection
|
||||
let previousHourTotal = ringBuffer[((stats.ringBufferPointer + 167) % 168) * 3 + 0];
|
||||
stats.ubiClaimedLastHour = previousHourTotal.plus(projectedTotal).div(BigInt.fromI32(2));
|
||||
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;
|
||||
|
|
@ -153,7 +129,7 @@ export function handleBlock(block: ethereum.Block): void {
|
|||
stats.ringBufferPointer = (stats.ringBufferPointer + 1) % 168;
|
||||
|
||||
// Reset the new current hour in the ring buffer
|
||||
let baseIndex = stats.ringBufferPointer * 3;
|
||||
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
|
||||
|
|
@ -162,37 +138,85 @@ export function handleBlock(block: ethereum.Block): void {
|
|||
stats.lastUpdatedHour = currentHour;
|
||||
|
||||
// Recalculate the sum of the last 7 days and 24 hours
|
||||
let totalLast7Days = BigInt.zero();
|
||||
let totalMintedLast7Days = BigInt.zero();
|
||||
let totalBurnedLast7Days = BigInt.zero();
|
||||
let totalLast24Hours = BigInt.zero();
|
||||
let totalMintedLast24Hours = BigInt.zero();
|
||||
let totalBurnedLast24Hours = BigInt.zero();
|
||||
|
||||
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) * 3;
|
||||
totalLast7Days = totalLast7Days.plus(ringBuffer[index]);
|
||||
totalMintedLast7Days = totalMintedLast7Days.plus(ringBuffer[index + 1]);
|
||||
totalBurnedLast7Days = totalBurnedLast7Days.plus(ringBuffer[index + 2]);
|
||||
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) {
|
||||
totalLast24Hours = totalLast24Hours.plus(ringBuffer[index]);
|
||||
totalMintedLast24Hours = totalMintedLast24Hours.plus(ringBuffer[index + 1]);
|
||||
totalBurnedLast24Hours = totalBurnedLast24Hours.plus(ringBuffer[index + 2]);
|
||||
ubiClaimedLastDay = ubiClaimedLastDay.plus(ringBuffer[index]);
|
||||
mintedLastDay = mintedLastDay.plus(ringBuffer[index + 1]);
|
||||
burnedLastDay = burnedLastDay.plus(ringBuffer[index + 2]);
|
||||
taxPaidLastDay = taxPaidLastDay.plus(ringBuffer[index + 3]);
|
||||
}
|
||||
}
|
||||
|
||||
stats.ubiClaimedLastWeek = totalLast7Days;
|
||||
stats.mintedLastWeek = totalMintedLast7Days;
|
||||
stats.burnedLastWeek = totalBurnedLast7Days;
|
||||
stats.ubiClaimedLastDay = totalLast24Hours;
|
||||
stats.mintedLastDay = totalMintedLast24Hours;
|
||||
stats.burnedLastDay = totalBurnedLast24Hours;
|
||||
|
||||
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;
|
||||
|
||||
// Save the updated Stats entity
|
||||
stats.save();
|
||||
} 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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue