feat: wallet P&L with average cost basis tracking (#156) (#158)

This commit is contained in:
johba 2026-02-19 16:22:23 +01:00
parent 76b2635e63
commit 66106077ba
4 changed files with 139 additions and 3 deletions

View file

@ -48,6 +48,8 @@ function formatTokenAmount(rawWei: string, decimals = 18): number {
export function useWalletDashboard(address: Ref<string>) {
const holderBalance = ref<string>('0');
const holderTotalEthSpent = ref<string>('0');
const holderTotalTokensAcquired = ref<string>('0');
const stats = ref<WalletStats | null>(null);
const positions = ref<WalletPosition[]>([]);
const loading = ref(false);
@ -78,6 +80,8 @@ export function useWalletDashboard(address: Ref<string>) {
holders(address: "${addr}") {
address
balance
totalEthSpent
totalTokensAcquired
}
statss(where: { id: "0x01" }) {
items {
@ -122,6 +126,8 @@ export function useWalletDashboard(address: Ref<string>) {
const holder = res.data?.data?.holders;
holderBalance.value = holder?.balance ?? '0';
holderTotalEthSpent.value = holder?.totalEthSpent ?? '0';
holderTotalTokensAcquired.value = holder?.totalTokensAcquired ?? '0';
const statsItems = res.data?.data?.statss?.items;
stats.value = Array.isArray(statsItems) && statsItems.length > 0 ? (statsItems[0] as WalletStats) : null;
@ -158,6 +164,31 @@ export function useWalletDashboard(address: Ref<string>) {
return balance * floorPriceEth;
});
// Cost basis & P&L
const avgCostBasis = computed(() => {
const spent = formatTokenAmount(holderTotalEthSpent.value);
const acquired = formatTokenAmount(holderTotalTokensAcquired.value);
if (acquired === 0) return 0;
return spent / acquired;
});
const currentPriceEth = computed(() => {
if (!stats.value?.currentPriceWei) return 0;
return formatTokenAmount(stats.value.currentPriceWei);
});
const unrealizedPnlEth = computed(() => {
const basis = avgCostBasis.value;
if (basis === 0) return 0;
return (currentPriceEth.value - basis) * balanceKrk.value;
});
const unrealizedPnlPercent = computed(() => {
const basis = avgCostBasis.value;
if (basis === 0) return 0;
return (currentPriceEth.value / basis - 1) * 100;
});
const activePositions = computed(() => positions.value.filter(p => p.status === 'Active'));
const closedPositions = computed(() => positions.value.filter(p => p.status === 'Closed'));
@ -180,6 +211,10 @@ export function useWalletDashboard(address: Ref<string>) {
balanceKrk,
ethBacking,
floorValue,
avgCostBasis,
currentPriceEth,
unrealizedPnlEth,
unrealizedPnlPercent,
stats,
positions,
activePositions,