fix(web-app): position ID, issuance earned (#96)

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>
This commit is contained in:
traddoo 2025-11-20 19:44:10 +01:00 committed by johba
parent a555a2fdd1
commit beefe22f90
6 changed files with 343 additions and 19 deletions

View file

@ -1,11 +1,10 @@
import { ref, computed, type ComputedRef, onMounted, onUnmounted } from 'vue';
import { config } from '@/wagmi';
import { type WatchEventReturnType, type Hex, toBytes } from 'viem';
import { type WatchEventReturnType, type Hex } from 'viem';
import axios from 'axios';
import { getAccount, watchChainId, watchAccount, watchContractEvent, type Config } from '@wagmi/core';
import type { WatchChainIdReturnType, WatchAccountReturnType, GetAccountReturnType } from '@wagmi/core';
import { bytesToUint256LittleEndian } from 'kraiken-lib/subgraph';
import { bigInt2Number } from '@/utils/helper';
import { getTaxRateIndexByDecimal } from '@/composables/useAdjustTaxRates';
import logger from '@/utils/logger';
@ -43,7 +42,7 @@ const activePositions = computed(() => {
return {
...obj,
positionId: formatId(obj.id as Hex),
positionId: BigInt(obj.id),
amount: bigInt2Number(obj.harbDeposit, 18),
taxRatePercentage: taxRateDecimal * 100,
taxRate: taxRateDecimal,
@ -97,7 +96,7 @@ const myClosedPositions: ComputedRef<Position[]> = computed(() => {
return {
...obj,
positionId: formatId(obj.id as Hex),
positionId: BigInt(obj.id),
amount: obj.share * 1000000,
// amount: bigInt2Number(obj.harbDeposit, 18),
taxRatePercentage: taxRateDecimal * 100,
@ -189,11 +188,8 @@ export async function loadActivePositions(chainId: number, endpointOverride?: st
};
}
function formatId(id: Hex) {
const bytes = toBytes(id);
const bigIntId = bytesToUint256LittleEndian(bytes);
return bigIntId;
}
// Position IDs are now directly converted to BigInt without transformation
// since GraphQL returns them as numeric strings
export async function loadMyClosedPositions(chainId: number, endpointOverride: string | undefined, account: GetAccountReturnType) {
const targetEndpoint = resolveGraphqlEndpoint(chainId, endpointOverride);