From 27c161bb6b348ef65a44853cc05214272bf1c7f0 Mon Sep 17 00:00:00 2001 From: Minimons Date: Mon, 6 Jul 2026 19:42:05 +0200 Subject: [PATCH] 22: Investigate and expose borrowFeeUsd in JupiterPerpsPosition --- .../jupiter/perps/JupiterPerpsPosition.tjava | 4 +- .../AnchorIdlJupiterPerpsCustodyDecoder.tjava | 14 ++-- ...AnchorIdlJupiterPerpsPositionDecoder.tjava | 43 ++++++++---- .../AnchorIdlJupiterPerpsServiceImpl.tjava | 70 ++++++++++++++++--- .../impl/anchoridl/DecodingPrimitives.tjava | 5 +- .../anchoridl/JupiterCustodyAccountInfo.tjava | 2 +- .../anchoridl/JupiterPerpsPositionInfo.tjava | 7 +- .../r35157/nenjim/hubd/impl/ref/Main.tjava | 14 +++- 8 files changed, 123 insertions(+), 36 deletions(-) diff --git a/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPosition.tjava b/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPosition.tjava index c47fbf6..80feaeb 100644 --- a/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPosition.tjava +++ b/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPosition.tjava @@ -31,8 +31,8 @@ public record JupiterPerpsPosition( ΩJupiterPerpsPositionAccountΩ positionAccount, ΩSPLMintAddressΩ tradedTokenMint, JupiterPerpsPositionDirection direction, - ΩUSDCAmountΩ value, - ΩUSDCAmountΩ size, + ΩUSDCAmountΩ positionValue, + ΩUSDCAmountΩ positionSize, ΩUSDCAmountΩ pnl, BigDecimal pnlPercent, BigDecimal leverage, diff --git a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsCustodyDecoder.tjava b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsCustodyDecoder.tjava index 5bc1c7d..3a7a50e 100644 --- a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsCustodyDecoder.tjava +++ b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsCustodyDecoder.tjava @@ -17,7 +17,7 @@ class AnchorIdlJupiterPerpsCustodyDecoder { ΩJupiterPerpsPostionIdlΩ idl = decodeIdl(encodedCustodyAccountInfo); JupiterCustodyAccountInfo cai = new JupiterCustodyAccountInfo( - readPublicKey(idl, MINT_OFFSET), + decodePublicKey(idl, MINT_OFFSET), decodeCumulativeInterestRate(idl) ); @@ -35,15 +35,15 @@ class AnchorIdlJupiterPerpsCustodyDecoder { return idl; } - private BigInteger decodeCumulativeInterestRate(byte[] data) { - byte[] bytes = readU128(data, CUMULATIVE_INTEREST_RATE_OFFSET); - BigInteger cumulativeInterestRate = new BigInteger(1, bytes); + private @NotNull ΩJupiterCumulativeInterestRateΩ decodeCumulativeInterestRate(ΩJupiterPerpsCustodyAccountIdlΩ idl) { + byte[] bytes = readU128(idl, CUMULATIVE_INTEREST_RATE_OFFSET); + ΩJupiterCumulativeInterestRateΩ cumulativeInterestRate = new ΩJupiterCumulativeInterestRateΩ(1, bytes); return cumulativeInterestRate; } // Offsets: - // 8 discriminator + // 8 discriminator // +32 pool // +32 mint // +32 token_account @@ -55,8 +55,8 @@ class AnchorIdlJupiterPerpsCustodyDecoder { // +8 target_ratio_bps // +48 assets - private static final int ANCHOR_DISCRIMINATOR_LENGTH = 8; - private static final int MINT_OFFSET = ANCHOR_DISCRIMINATOR_LENGTH + PUBLIC_KEY_LENGTH; + private static final int DISCRIMINATOR_LENGTH = 8; + private static final int MINT_OFFSET = DISCRIMINATOR_LENGTH + PUBLIC_KEY_LENGTH; private static final int FUNDING_RATE_STATE_OFFSET = 262; private static final int CUMULATIVE_INTEREST_RATE_OFFSET = FUNDING_RATE_STATE_OFFSET; diff --git a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsPositionDecoder.tjava b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsPositionDecoder.tjava index fefde85..e719e21 100644 --- a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsPositionDecoder.tjava +++ b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsPositionDecoder.tjava @@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.math.BigDecimal; +import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Base64; @@ -21,47 +22,63 @@ class AnchorIdlJupiterPerpsPositionDecoder { JupiterPerpsPositionDirection direction = decodeDirection(idl); - long rawEntryPrice = ByteBuffer + ΩjupiterRawEntryPriceUsdΩ rawEntryPrice = ByteBuffer .wrap(idl, PRICE_OFFSET, U64_LENGTH) .order(ByteOrder.LITTLE_ENDIAN) .getLong(); - ΩUSDCPriceΩ entryPrice = BigDecimal + ΩUSDCPriceΩ entryPrice = ΩUSDCPriceΩ .valueOf(rawEntryPrice) .movePointLeft(6); - long rawCollateralUsd = ByteBuffer + ΩjupiterRawCollateralUsdΩ rawCollateralUsd = ByteBuffer .wrap(idl, COLLATERAL_USD_OFFSET, U64_LENGTH) .order(ByteOrder.LITTLE_ENDIAN) .getLong(); - ΩUSDCAmountΩ collateralUsd = BigDecimal + ΩUSDCAmountΩ collateral = ΩUSDCAmountΩ .valueOf(rawCollateralUsd) .movePointLeft(6); - long rawSizeUsd = ByteBuffer + ΩjupiterRawSizeUsdΩ rawSizeUsd = ByteBuffer .wrap(idl, SIZE_USD_OFFSET, U64_LENGTH) .order(ByteOrder.LITTLE_ENDIAN) .getLong(); - ΩUSDCAmountΩ sizeUsd = BigDecimal + ΩUSDCAmountΩ positionSize = ΩUSDCAmountΩ .valueOf(rawSizeUsd) .movePointLeft(6); - ΩJupiterCustodyAccountAddressΩ custodyAccountAddress = readPublicKey(idl, CUSTODY_OFFSET); + ΩJupiterPerpsCustodyAccountAddressΩ custodyAccountAddress = + decodePublicKey(idl, CUSTODY_OFFSET); + + ΩJupiterPerpsCollateralCustodyAccountAddressΩ collateralCustodyAccountAddress = + decodePublicKey(idl, COLLATERAL_CUSTODY_OFFSET); + + ΩJupiterCumulativeInterestSnapshotΩ cumulativeInterestSnapshot = decodeCumulativeInterestSnapshot(idl); JupiterPerpsPositionInfo posInfo = new JupiterPerpsPositionInfo( entryPrice, direction, - sizeUsd, - collateralUsd, - custodyAccountAddress + positionSize, + collateral, + custodyAccountAddress, + collateralCustodyAccountAddress, + cumulativeInterestSnapshot ); return posInfo; } - ΩJupiterCustodyAccountAddressΩ decodeCustodyAccountAddress(SolanaAccountInfo accountInfo) { + private @NotNull ΩJupiterCumulativeInterestSnapshotΩ decodeCumulativeInterestSnapshot(ΩJupiterPerpsPostionIdlΩ idl) { + byte[] bytes = readU128(idl, CUMULATIVE_INTEREST_SNAPSHOT_OFFSET); + ΩJupiterCumulativeInterestSnapshotΩ cumulativeInterestSnapshot + = new ΩJupiterCumulativeInterestSnapshotΩ(1, bytes); + + return cumulativeInterestSnapshot; + } + + ΩJupiterPerpsCustodyAccountAddressΩ decodeCustodyAccountAddress(SolanaAccountInfo accountInfo) { byte[] data = base64.decode(accountInfo.data()); if (data.length < CUSTODY_OFFSET + PUBLIC_KEY_LENGTH) { @@ -69,7 +86,7 @@ class AnchorIdlJupiterPerpsPositionDecoder { throw new IllegalArgumentException(errorMsg); } - ΩJupiterCustodyAccountAddressΩ addr = readPublicKey(data, CUSTODY_OFFSET); + ΩJupiterPerpsCustodyAccountAddressΩ addr = decodePublicKey(data, CUSTODY_OFFSET); return addr; } @@ -117,6 +134,8 @@ class AnchorIdlJupiterPerpsPositionDecoder { private static final int PRICE_OFFSET = SIDE_OFFSET + SIDE_ENUM_LENGTH; private static final int SIZE_USD_OFFSET = PRICE_OFFSET + U64_LENGTH; private static final int COLLATERAL_USD_OFFSET = SIZE_USD_OFFSET + U64_LENGTH; + private static final int REALISED_PNL_USD_OFFSET = COLLATERAL_USD_OFFSET + U64_LENGTH; + private static final int CUMULATIVE_INTEREST_SNAPSHOT_OFFSET = REALISED_PNL_USD_OFFSET + I64_LENGTH; private static final Base64.Decoder base64 = Base64.getDecoder(); } \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsServiceImpl.tjava b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsServiceImpl.tjava index c1a9d75..622eeb4 100644 --- a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsServiceImpl.tjava +++ b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/AnchorIdlJupiterPerpsServiceImpl.tjava @@ -12,6 +12,8 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; import java.util.HashSet; import java.util.Set; @@ -48,7 +50,7 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService { if(perpsPositionInfo == null) { pos = null; } else { - ΩJupiterCustodyAccountAddressΩ custodyAccountAddress = positionDecoder.decodeCustodyAccountAddress(accountInfo); + ΩJupiterPerpsCustodyAccountAddressΩ custodyAccountAddress = positionDecoder.decodeCustodyAccountAddress(accountInfo); ΩJupiterCustodyAccountInfoEncodedΩ encodedCustodyAccountInfo = solanaBlockChain.getAccountInfo(custodyAccountAddress); if (encodedCustodyAccountInfo == null) { @@ -59,13 +61,31 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService { JupiterCustodyAccountInfo custodyAccountInfo = custodyDecoder.decode(encodedCustodyAccountInfo); ΩSPLMintAddressΩ mintAddress = custodyAccountInfo.mintAddress(); + ΩJupiterPerpsCollateralCustodyAccountAddressΩ collateralCustodyAccountAddress = + perpsPositionInfo.collateralCustodyAccountAddress(); + + ΩJupiterCustodyAccountInfoEncodedΩ encodedCollateralCustodyAccountInfo = + solanaBlockChain.getAccountInfo(collateralCustodyAccountAddress); + + JupiterCustodyAccountInfo collateralCustodyAccountInfo = + custodyDecoder.decode(encodedCollateralCustodyAccountInfo); + + ΩJupiterPostionInterestΩ positionInterest = + collateralCustodyAccountInfo.currentCumulativeInterestRate() + .subtract(perpsPositionInfo.cumulativeInterestSnapshot()); + + ΩUSDCAmountΩ borrowFeesDue = + calculateBorrowFeesDue( + positionInterest, + perpsPositionInfo.positionSize() + ); + ΩUSDCAmountΩ value = ZERO; // TODO - Dummy ΩUSDCAmountΩ pnl = ZERO; // TODO - Dummy BigDecimal pnlPercent = ZERO; // TODO - Dummy BigDecimal leverage = ZERO; // TODO - Dummy ΩUSDCPriceΩ marketPrice = ZERO; // TODO - Dummy ΩUSDCAmountΩ totalFees = ZERO; // TODO - Dummy - ΩUSDCAmountΩ borrowFeesDue = ZERO; // TODO - Dummy ΩUSDCAmountΩ closeFeePending = ZERO; // TODO - Dummy ΩSolanaAmountΩ accountRent = new MoneyAmount(ZERO, WellKnownCurrencyTypes.SOLANA.getCurrencyType()); // TODO - Dummy @@ -74,7 +94,7 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService { mintAddress, perpsPositionInfo.direction(), value, - perpsPositionInfo.size(), + perpsPositionInfo.positionSize(), pnl, pnlPercent, leverage, @@ -115,12 +135,13 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService { } JupiterPerpsPositionInfo perpsPositionInfo = positionDecoder.decode(accountInfo); - if(perpsPositionInfo == null || perpsPositionInfo.size().compareTo(ZERO) == 0) { + if(perpsPositionInfo == null || perpsPositionInfo.positionSize().compareTo(ZERO) == 0) { continue; } - ΩJupiterCustodyAccountAddressΩ custodyAccountAddress = perpsPositionInfo.custodyAccountAddress(); - ΩJupiterCustodyAccountInfoEncodedΩ encodedCustodyAccountInfo = solanaBlockChain.getAccountInfo(custodyAccountAddress); + ΩJupiterPerpsCustodyAccountAddressΩ custodyAccountAddress = perpsPositionInfo.custodyAccountAddress(); + ΩJupiterCustodyAccountInfoEncodedΩ encodedCustodyAccountInfo + = solanaBlockChain.getAccountInfo(custodyAccountAddress); if (encodedCustodyAccountInfo == null) { String errorMsg = "Jupiter Perps custody account does not exist: " + custodyAccountAddress; @@ -130,13 +151,31 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService { JupiterCustodyAccountInfo custodyAccountInfo = custodyDecoder.decode(encodedCustodyAccountInfo); ΩSPLMintAddressΩ mintAddress = custodyAccountInfo.mintAddress(); + ΩJupiterPerpsCollateralCustodyAccountAddressΩ collateralCustodyAccountAddress = + perpsPositionInfo.collateralCustodyAccountAddress(); + + ΩJupiterCustodyAccountInfoEncodedΩ encodedCollateralCustodyAccountInfo = + solanaBlockChain.getAccountInfo(collateralCustodyAccountAddress); + + JupiterCustodyAccountInfo collateralCustodyAccountInfo = + custodyDecoder.decode(encodedCollateralCustodyAccountInfo); + + ΩJupiterPostionInterestΩ positionInterest = + collateralCustodyAccountInfo.currentCumulativeInterestRate() + .subtract(perpsPositionInfo.cumulativeInterestSnapshot()); + + ΩUSDCAmountΩ borrowFeesDue = + calculateBorrowFeesDue( + positionInterest, + perpsPositionInfo.positionSize() + ); + ΩUSDCAmountΩ value = ZERO; // TODO - Dummy ΩUSDCAmountΩ pnl = ZERO; // TODO - Dummy BigDecimal pnlPercent = ZERO; // TODO - Dummy BigDecimal leverage = ZERO; // TODO - Dummy ΩUSDCPriceΩ marketPrice = ZERO; // TODO - Dummy ΩUSDCAmountΩ totalFees = ZERO; // TODO - Dummy - ΩUSDCAmountΩ borrowFeesDue = ZERO; // TODO - Dummy ΩUSDCAmountΩ closeFeePending = ZERO; // TODO - Dummy ΩSolanaAmountΩ accountRent = new MoneyAmount(ZERO, WellKnownCurrencyTypes.SOLANA.getCurrencyType()); // TODO - Dummy @@ -145,7 +184,7 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService { mintAddress, perpsPositionInfo.direction(), value, - perpsPositionInfo.size(), + perpsPositionInfo.positionSize(), pnl, pnlPercent, leverage, @@ -164,6 +203,21 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService { return Set.copyOf(positions); } + private static ΩUSDCAmountΩ calculateBorrowFeesDue( + ΩJupiterPostionInterestΩ positionInterest, + ΩUSDCAmountΩ size + ) { + ΩUSDCAmountΩ fees = new BigDecimal(positionInterest) + .multiply(size) + .divide( + BigDecimal.valueOf(RATE_POWER), + 6, + RoundingMode.CEILING + ); + return fees; + } + + private static final long RATE_POWER = 1_000_000_000L; private static final ΩJupiterPerpsProgramIdΩ JUPITER_PERPS_PROGRAM_ID = "PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu"; private static final int POSITION_OWNER_OFFSET = 8; diff --git a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/DecodingPrimitives.tjava b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/DecodingPrimitives.tjava index 7c35b6d..e47fd1e 100644 --- a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/DecodingPrimitives.tjava +++ b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/DecodingPrimitives.tjava @@ -2,6 +2,9 @@ package com.r35157.libs.jupiter.perps.impl.anchoridl; import com.r35157.libs.codec.Base58Codec; import com.r35157.libs.codec.impl.ref.Base58CodecImpl; +import org.jetbrains.annotations.NotNull; + +import java.math.BigInteger; public class DecodingPrimitives { @@ -15,7 +18,7 @@ public class DecodingPrimitives { return bytes; } - public static ΩSolanaAddressΩ readPublicKey(byte[] data, int offset) { + public static @NotNull ΩSolanaAddressΩ decodePublicKey(ΩJupiterPerpsPostionIdlΩ data, int offset) { byte[] bytes = new byte[PUBLIC_KEY_LENGTH]; System.arraycopy( diff --git a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/JupiterCustodyAccountInfo.tjava b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/JupiterCustodyAccountInfo.tjava index b44f805..ce81e0f 100644 --- a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/JupiterCustodyAccountInfo.tjava +++ b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/JupiterCustodyAccountInfo.tjava @@ -4,6 +4,6 @@ import java.math.BigInteger; public record JupiterCustodyAccountInfo( ΩSPLMintAddressΩ mintAddress, - BigInteger currentCumulativeInterestRate + ΩJupiterCumulativeInterestRateΩ currentCumulativeInterestRate ) { } diff --git a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/JupiterPerpsPositionInfo.tjava b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/JupiterPerpsPositionInfo.tjava index d7a8912..ceb04fa 100644 --- a/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/JupiterPerpsPositionInfo.tjava +++ b/src/main/tjava/com/r35157/libs/jupiter/perps/impl/anchoridl/JupiterPerpsPositionInfo.tjava @@ -3,12 +3,15 @@ package com.r35157.libs.jupiter.perps.impl.anchoridl; import com.r35157.libs.jupiter.perps.JupiterPerpsPositionDirection; import java.math.BigDecimal; +import java.math.BigInteger; public record JupiterPerpsPositionInfo( ΩUSDCPriceΩ entryPrice, JupiterPerpsPositionDirection direction, - ΩUSDCAmountΩ size, + ΩUSDCAmountΩ positionSize, ΩUSDCAmountΩ collateral, - ΩJupiterCustodyAccountAddressΩ custodyAccountAddress + ΩJupiterPerpsCustodyAccountAddressΩ custodyAccountAddress, + ΩJupiterPerpsCollateralCustodyAccountAddressΩ collateralCustodyAccountAddress, + ΩJupiterCumulativeInterestSnapshotΩ cumulativeInterestSnapshot ) { } diff --git a/src/main/tjava/com/r35157/nenjim/hubd/impl/ref/Main.tjava b/src/main/tjava/com/r35157/nenjim/hubd/impl/ref/Main.tjava index e7bf5f9..a917777 100644 --- a/src/main/tjava/com/r35157/nenjim/hubd/impl/ref/Main.tjava +++ b/src/main/tjava/com/r35157/nenjim/hubd/impl/ref/Main.tjava @@ -15,6 +15,8 @@ import java.lang.management.ManagementFactory; import com.r35157.nenjim.hubd.ctx.ContextManager; import com.r35157.nenjim.hubd.journal.JournalManager; import com.r35157.nenjim.hubd.impl.ref.JournalManagerImpl; + +import java.math.BigDecimal; import java.nio.file.Files; import java.nio.file.Path; import java.util.Set; @@ -28,10 +30,16 @@ public class Main { SolanaBlockChain sbc = new SolanaBlockChainImpl(); JupiterPerpsService jupiter = new AnchorIdlJupiterPerpsServiceImpl(sbc); ΩSolanaWalletIdΩ walletId = "vj98roDZ7744EBfxyuDFkKpEGCsKQLr7K8UFRumJNHf"; - Set positions = jupiter.getOpenPositions(walletId); - int a=0; + //Set positions = jupiter.getOpenPositions(walletId); - nenjimHub.awaitShutdown(); + while(true) { + String addr = "2z2oExdggoRPCcojntHrGbRiDWeJgVSRbasfMbPfprQi"; + JupiterPerpsPosition pos = jupiter.getPosition(addr); + ΩUSDCAmountΩ a = pos.borrowFeesDue(); + int i = 0; + } + + // nenjimHub.awaitShutdown(); /* try { log.info("Auto-starting 2 Nenjim application(s)...");