Bug #1: Position ID Transformation Issue (#95) Problem: Frontend applied incorrect byte conversion to position IDs, causing transactions to fail with "NoPermission" errors. Root Cause: formatId() function did little-endian byte conversion on already-correct numeric strings from GraphQL. Fix: Direct conversion BigInt(obj.id) instead of formatId(obj.id as Hex) in usePositions.ts. Result: Users can now successfully stake/unstake positions. --- Bug #2: Issuance Earned Calculation Error (#97) Problem: Frontend showed negative "Issuance Earned" values (e.g., -4,991 KRK) due to wrong mathematical formula. Root Cause: Formula calculated position.totalSupplyInit - currentTotalSupply (always negative when supply increases). Fix: Correct formula (currentTotalSupply - position.totalSupplyInit) × position.share in Vue components. Result: Shows realistic positive earnings and enables proper economic monitoring. Co-authored-by: steve <steve@harberg.dev> Co-authored-by: openhands <openhands@all-hands.dev> Reviewed-on: https://codeberg.org/johba/harb/pulls/96 Co-authored-by: traddoo <traddoo@noreply.codeberg.org> Co-committed-by: traddoo <traddoo@noreply.codeberg.org>
78 lines
2.7 KiB
TypeScript
78 lines
2.7 KiB
TypeScript
/**
|
|
* Position profit calculations for Harberger staking.
|
|
*
|
|
* Positions earn profit through their proportional share of new token issuance.
|
|
* This aligns with the Harberger tax economic model where stakers earn from protocol growth.
|
|
*/
|
|
|
|
/**
|
|
* Calculate profit for an active position.
|
|
*
|
|
* Active positions earn their proportional share of all new tokens minted
|
|
* since the position was created.
|
|
*
|
|
* @param totalSupplyInit - Total token supply when position was created
|
|
* @param currentTotalSupply - Current total token supply
|
|
* @param positionShare - Position's proportional share (0-1)
|
|
* @returns Profit in token units (not wei)
|
|
*/
|
|
export function calculateActivePositionProfit(totalSupplyInit: bigint, currentTotalSupply: bigint, positionShare: number): number {
|
|
if (totalSupplyInit < 0n || currentTotalSupply < 0n) {
|
|
throw new Error('Supply values must be non-negative');
|
|
}
|
|
|
|
if (positionShare < 0 || positionShare > 1) {
|
|
throw new Error('Position share must be between 0 and 1');
|
|
}
|
|
|
|
if (currentTotalSupply < totalSupplyInit) {
|
|
// If supply decreased (shouldn't happen in normal operation), return 0
|
|
return 0;
|
|
}
|
|
|
|
// Convert to token units (assuming 18 decimals)
|
|
const initSupply = Number(totalSupplyInit) / 1e18;
|
|
const currentSupply = Number(currentTotalSupply) / 1e18;
|
|
|
|
// Calculate new issuance since position creation
|
|
const newIssuance = currentSupply - initSupply;
|
|
|
|
// Position earns its share of new issuance
|
|
return newIssuance * positionShare;
|
|
}
|
|
|
|
/**
|
|
* Calculate profit for a closed position.
|
|
*
|
|
* Closed positions earned their proportional share of all new tokens minted
|
|
* during the position's lifetime (from creation to closure).
|
|
*
|
|
* @param totalSupplyInit - Total token supply when position was created
|
|
* @param totalSupplyEnd - Total token supply when position was closed
|
|
* @param positionShare - Position's proportional share (0-1)
|
|
* @returns Profit in token units (not wei)
|
|
*/
|
|
export function calculateClosedPositionProfit(totalSupplyInit: bigint, totalSupplyEnd: bigint, positionShare: number): number {
|
|
if (totalSupplyInit < 0n || totalSupplyEnd < 0n) {
|
|
throw new Error('Supply values must be non-negative');
|
|
}
|
|
|
|
if (positionShare < 0 || positionShare > 1) {
|
|
throw new Error('Position share must be between 0 and 1');
|
|
}
|
|
|
|
if (totalSupplyEnd < totalSupplyInit) {
|
|
// If supply decreased during position lifetime, return 0
|
|
return 0;
|
|
}
|
|
|
|
// Convert to token units (assuming 18 decimals)
|
|
const initSupply = Number(totalSupplyInit) / 1e18;
|
|
const endSupply = Number(totalSupplyEnd) / 1e18;
|
|
|
|
// Calculate new issuance during position lifetime
|
|
const newIssuance = endSupply - initSupply;
|
|
|
|
// Position earned its share of new issuance
|
|
return newIssuance * positionShare;
|
|
}
|