Mess
This commit is contained in:
@@ -44,7 +44,6 @@ dependencies {
|
|||||||
runtimeOnly("org.apache.logging.log4j:log4j-core:2.26.0")
|
runtimeOnly("org.apache.logging.log4j:log4j-core:2.26.0")
|
||||||
runtimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl:2.26.0")
|
runtimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl:2.26.0")
|
||||||
|
|
||||||
implementation("com.r35157.nenjim:hubd-api:0.1-dev")
|
|
||||||
implementation("com.fasterxml.jackson.core:jackson-databind:2.18.6")
|
implementation("com.fasterxml.jackson.core:jackson-databind:2.18.6")
|
||||||
implementation("com.fazecast:jSerialComm:2.11.4")
|
implementation("com.fazecast:jSerialComm:2.11.4")
|
||||||
implementation("com.google.code.gson:gson:2.14.0")
|
implementation("com.google.code.gson:gson:2.14.0")
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package com.r35157.libs.solana.valuetypes;
|
||||||
|
|
||||||
|
import com.r35157.libs.valuetypes.basic.CurrencyType;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines well-known currency types used by the Solana integration.
|
||||||
|
*
|
||||||
|
* <p>Each enum value wraps a {@link CurrencyType} with a stable identifier and a
|
||||||
|
* human-readable currency name. These predefined values are intended for common
|
||||||
|
* currencies that the Solana-related modules need to reference consistently.</p>
|
||||||
|
*/
|
||||||
|
public enum WellKnownCurrencyTypes {
|
||||||
|
/**
|
||||||
|
* Native Solana currency.
|
||||||
|
*/
|
||||||
|
SOLANA(new CurrencyType(
|
||||||
|
UUID.fromString("019e0116-fce5-792f-a647-fa6da4dffec5"),
|
||||||
|
"Solana",
|
||||||
|
"SOL")
|
||||||
|
),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syrup USDC token currency.
|
||||||
|
*/
|
||||||
|
SYRUPUSDC(new CurrencyType(
|
||||||
|
UUID.fromString("019e1d51-0600-7956-8231-f3b7058a91c2"),
|
||||||
|
"SyrupUSDC",
|
||||||
|
"SyrupUSDC")
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a well-known currency type entry.
|
||||||
|
*
|
||||||
|
* @param currencyType the currency type represented by this enum value
|
||||||
|
*/
|
||||||
|
WellKnownCurrencyTypes(CurrencyType currencyType) {
|
||||||
|
this.currencyType = currencyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currency type represented by this enum value.
|
||||||
|
*
|
||||||
|
* @return the represented currency type
|
||||||
|
*/
|
||||||
|
public CurrencyType getCurrencyType() {
|
||||||
|
return currencyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final CurrencyType currencyType;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.r35157.libs.codec;
|
||||||
|
|
||||||
|
public interface Base58Codec {
|
||||||
|
String encode(byte[] input);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.r35157.libs.jupiter.perps;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import com.r35157.libs.valuetypes.basic.MoneyAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a Jupiter Perps position.
|
||||||
|
*
|
||||||
|
* <p>A Jupiter Perps position is represented on-chain by a Solana account owned by
|
||||||
|
* the Jupiter Perps program. This record contains the public API view of such a
|
||||||
|
* position.</p>
|
||||||
|
*
|
||||||
|
* @param positionAccount the Solana account address of the Jupiter Perps position
|
||||||
|
* @param tradedTokenMint the mint address of the token being traded
|
||||||
|
* @param direction whether the position is long or short
|
||||||
|
* @param value the amount the position is worth if closed now
|
||||||
|
* @param size the leveraged amount used to open the contracts
|
||||||
|
* @param pnl the amount in usd in profit or loss on this position
|
||||||
|
* @param pnlPercent the profit and loss represented as a percentage
|
||||||
|
* @param leverage
|
||||||
|
* @param entryPrice the entry price of the position, denominated in USDC
|
||||||
|
* @param marketPrice the current spot price of the token
|
||||||
|
* @param collateral the amount of USD representing the collateral for this position
|
||||||
|
* @param totalFees the total amount of fees (TODO: is that including pending/due fees)
|
||||||
|
* @param borrowFeesDue the amount of USD that is currently outstanding
|
||||||
|
* @param closeFeePending the fee in USD for closing the account (TODO: multiple accounts - when adding collateral?)
|
||||||
|
* @param accountRent refundable amount locked for Solana account renting
|
||||||
|
*/
|
||||||
|
public record JupiterPerpsPosition(
|
||||||
|
ΩJupiterPerpsPositionAccountΩ positionAccount,
|
||||||
|
ΩSPLMintAddressΩ tradedTokenMint,
|
||||||
|
JupiterPerpsPositionDirection direction,
|
||||||
|
ΩUSDCAmountΩ value,
|
||||||
|
ΩUSDCAmountΩ size,
|
||||||
|
ΩUSDCAmountΩ pnl,
|
||||||
|
BigDecimal pnlPercent,
|
||||||
|
BigDecimal leverage,
|
||||||
|
ΩUSDCPriceΩ entryPrice,
|
||||||
|
ΩUSDCPriceΩ marketPrice,
|
||||||
|
ΩUSDCAmountΩ collateral,
|
||||||
|
ΩUSDCAmountΩ totalFees,
|
||||||
|
ΩUSDCAmountΩ borrowFeesDue,
|
||||||
|
ΩUSDCAmountΩ closeFeePending,
|
||||||
|
ΩSolanaAmountΩ accountRent
|
||||||
|
) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.r35157.libs.jupiter.perps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direction of a Jupiter Perps position.
|
||||||
|
*/
|
||||||
|
public enum JupiterPerpsPositionDirection {
|
||||||
|
LONG,
|
||||||
|
SHORT
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.r35157.libs.jupiter.perps;
|
||||||
|
|
||||||
|
import com.r35157.libs.solana.SolanaAccountInfo;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for reading Jupiter Perps data.
|
||||||
|
*
|
||||||
|
* <p>This service is read-only. It does not open, close, modify, or sign transactions
|
||||||
|
* for Jupiter Perpetual Contracts.</p>
|
||||||
|
*
|
||||||
|
* <p>NOTICE: The first supported operation is reading a known Jupiter Perps position account
|
||||||
|
* and returning its decoded position data.</p>
|
||||||
|
*/
|
||||||
|
public interface JupiterPerpsService {
|
||||||
|
/**
|
||||||
|
* Reads a Jupiter Perps position from a known position account.
|
||||||
|
*
|
||||||
|
* <p>The supplied account must be the Solana account that stores the Jupiter Perps
|
||||||
|
* position state. It is not the wallet address, token account, custody account, pool
|
||||||
|
* account, or position request account.</p>
|
||||||
|
*
|
||||||
|
* @param positionAccount the Solana account address of the Jupiter Perps position
|
||||||
|
* @return the decoded Jupiter Perps position
|
||||||
|
* @throws IOException if the position account could not be fetched or decoded
|
||||||
|
* @throws InterruptedException if the calling thread is interrupted while fetching
|
||||||
|
* the position account
|
||||||
|
JupiterPerpsPosition getPosition(@NotNull SolanaAccountInfo accountInfo)
|
||||||
|
throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
JupiterPerpsPosition getPosition(ΩJupiterPerpsPositionAccountΩ positionAccount)
|
||||||
|
throws IOException, InterruptedException;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds open Jupiter Perps positions owned by a wallet.
|
||||||
|
*
|
||||||
|
* <p>This method returns decoded Jupiter Perps position objects. It does not return
|
||||||
|
* raw Solana accounts or account ids.</p>
|
||||||
|
*
|
||||||
|
* @param owner the wallet address that owns the Jupiter Perps positions
|
||||||
|
* @return the open Jupiter Perps positions owned by the wallet
|
||||||
|
* @throws IOException if the position accounts could not be fetched or decoded
|
||||||
|
* @throws InterruptedException if the calling thread is interrupted while fetching positions
|
||||||
|
*/
|
||||||
|
Set<JupiterPerpsPosition> getOpenPositions(ΩSolanaWalletIdΩ owner)
|
||||||
|
throws IOException, InterruptedException;
|
||||||
|
}
|
||||||
+51
-31
@@ -4,47 +4,67 @@ import com.r35157.libs.codec.Base58Codec;
|
|||||||
import com.r35157.libs.codec.impl.ref.Base58CodecImpl;
|
import com.r35157.libs.codec.impl.ref.Base58CodecImpl;
|
||||||
import com.r35157.libs.solana.SolanaAccountInfo;
|
import com.r35157.libs.solana.SolanaAccountInfo;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
class AnchorIdlJupiterPerpsCustodyDecoder {
|
import static com.r35157.libs.jupiter.perps.impl.anchoridl.DecodingPrimitives.*;
|
||||||
|
|
||||||
ΩSPLMintAddressΩ decodeMint(
|
public class AnchorIdlJupiterPerpsCustodyDecoder {
|
||||||
SolanaAccountInfo custodyAccountInfo
|
|
||||||
) {
|
|
||||||
byte[] data = Base64.getDecoder().decode(custodyAccountInfo.dataBase64());
|
|
||||||
|
|
||||||
if (data.length < MINT_OFFSET + PUBLIC_KEY_LENGTH) {
|
public CustodyAccountInfo decode(SolanaAccountInfo custodyAccountInfo) {
|
||||||
throw new IllegalArgumentException(
|
byte[] data = decodeIdl(custodyAccountInfo);
|
||||||
"Jupiter Perps custody account data is too short: " + data.length
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return readPublicKey(data, MINT_OFFSET);
|
CustodyAccountInfo cai = new CustodyAccountInfo(
|
||||||
}
|
decodeMintAddress(data),
|
||||||
|
decodeCumulativeInterestRate(data)
|
||||||
private ΩSPLMintAddressΩ readPublicKey(
|
|
||||||
byte[] data,
|
|
||||||
int offset
|
|
||||||
) {
|
|
||||||
byte[] publicKeyBytes = new byte[PUBLIC_KEY_LENGTH];
|
|
||||||
|
|
||||||
System.arraycopy(
|
|
||||||
data,
|
|
||||||
offset,
|
|
||||||
publicKeyBytes,
|
|
||||||
0,
|
|
||||||
PUBLIC_KEY_LENGTH
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return base58.encode(publicKeyBytes);
|
return cai;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] decodeIdl(SolanaAccountInfo custodyAccountInfo) {
|
||||||
|
byte[] data = base64.decode(custodyAccountInfo.dataBase64());
|
||||||
|
|
||||||
|
if (data.length < CUMULATIVE_INTEREST_RATE_OFFSET + U128_LENGTH) {
|
||||||
|
String errMsg = "Jupiter Perps custody account data is too short: " + data.length;
|
||||||
|
throw new IllegalArgumentException(errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ΩSPLMintAddressΩ decodeMintAddress(byte[] data) {
|
||||||
|
byte[] mintAddressBytes = readPublicKey(data, MINT_OFFSET);
|
||||||
|
ΩSPLMintAddressΩ mintAddress = base58.encode(mintAddressBytes);
|
||||||
|
|
||||||
|
return mintAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigInteger decodeCumulativeInterestRate(byte[] data) {
|
||||||
|
byte[] bytes = readU128(data, CUMULATIVE_INTEREST_RATE_OFFSET);
|
||||||
|
BigInteger cumulativeInterestRate = new BigInteger(1, bytes);
|
||||||
|
|
||||||
|
return cumulativeInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offsets:
|
||||||
|
// 8 discriminator
|
||||||
|
// +32 pool
|
||||||
|
// +32 mint
|
||||||
|
// +32 token_account
|
||||||
|
// +1 decimals
|
||||||
|
// +1 is_stable
|
||||||
|
// +45 oracle
|
||||||
|
// +48 pricing
|
||||||
|
// +7 permissions
|
||||||
|
// +8 target_ratio_bps
|
||||||
|
// +48 assets
|
||||||
|
|
||||||
private static final int ANCHOR_DISCRIMINATOR_LENGTH = 8;
|
private static final int ANCHOR_DISCRIMINATOR_LENGTH = 8;
|
||||||
private static final int PUBLIC_KEY_LENGTH = 32;
|
private static final int MINT_OFFSET = ANCHOR_DISCRIMINATOR_LENGTH + PUBLIC_KEY_LENGTH;
|
||||||
|
private static final int FUNDING_RATE_STATE_OFFSET = 262;
|
||||||
private static final int MINT_OFFSET =
|
private static final int CUMULATIVE_INTEREST_RATE_OFFSET = FUNDING_RATE_STATE_OFFSET;
|
||||||
ANCHOR_DISCRIMINATOR_LENGTH
|
|
||||||
+ PUBLIC_KEY_LENGTH; // pool
|
|
||||||
|
|
||||||
private static final Base58Codec base58 = new Base58CodecImpl();
|
private static final Base58Codec base58 = new Base58CodecImpl();
|
||||||
|
private static final Base64.Decoder base64 = Base64.getDecoder();
|
||||||
}
|
}
|
||||||
+58
-12
@@ -7,17 +7,15 @@ import com.r35157.libs.jupiter.perps.JupiterPerpsPositionDirection;
|
|||||||
import com.r35157.libs.solana.SolanaAccountInfo;
|
import com.r35157.libs.solana.SolanaAccountInfo;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
class AnchorIdlJupiterPerpsPositionDecoder {
|
public class AnchorIdlJupiterPerpsPositionDecoder {
|
||||||
|
|
||||||
JupiterPerpsPosition decode(
|
public JupiterPerpsPositionInfo decode(SolanaAccountInfo accountInfo) {
|
||||||
ΩJupiterPerpsPositionAccountΩ positionAccount,
|
|
||||||
SolanaAccountInfo accountInfo,
|
|
||||||
ΩSPLMintAddressΩ tradedTokenMint
|
|
||||||
) {
|
|
||||||
byte[] data = Base64.getDecoder().decode(accountInfo.dataBase64());
|
byte[] data = Base64.getDecoder().decode(accountInfo.dataBase64());
|
||||||
|
|
||||||
if (data.length < PRICE_OFFSET + U64_LENGTH) {
|
if (data.length < PRICE_OFFSET + U64_LENGTH) {
|
||||||
@@ -56,19 +54,34 @@ class AnchorIdlJupiterPerpsPositionDecoder {
|
|||||||
.valueOf(rawSizeUsd)
|
.valueOf(rawSizeUsd)
|
||||||
.movePointLeft(6);
|
.movePointLeft(6);
|
||||||
|
|
||||||
JupiterPerpsPosition pos = new JupiterPerpsPosition(
|
JupiterPerpsPositionInfo posInfo = new JupiterPerpsPositionInfo(
|
||||||
positionAccount,
|
|
||||||
entryPrice,
|
entryPrice,
|
||||||
direction,
|
direction,
|
||||||
tradedTokenMint,
|
|
||||||
sizeUsd,
|
sizeUsd,
|
||||||
collateralUsd
|
collateralUsd
|
||||||
);
|
);
|
||||||
|
|
||||||
return pos;
|
return posInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
ΩSolanaAddressΩ decodeCustodyAccount(SolanaAccountInfo accountInfo) {
|
|
||||||
|
public BigInteger decodeCumulativeInterestSnapshot(SolanaAccountInfo accountInfo) {
|
||||||
|
byte[] data = Base64.getDecoder().decode(accountInfo.dataBase64());
|
||||||
|
|
||||||
|
if (data.length < CUMULATIVE_INTEREST_SNAPSHOT_OFFSET + U128_LENGTH) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Jupiter Perps position account data is too short: " + data.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger value = readU128(
|
||||||
|
data,
|
||||||
|
CUMULATIVE_INTEREST_SNAPSHOT_OFFSET
|
||||||
|
);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ΩSolanaAddressΩ decodeCustodyAccount(SolanaAccountInfo accountInfo) {
|
||||||
byte[] data = Base64.getDecoder().decode(accountInfo.dataBase64());
|
byte[] data = Base64.getDecoder().decode(accountInfo.dataBase64());
|
||||||
|
|
||||||
if (data.length < CUSTODY_OFFSET + PUBLIC_KEY_LENGTH) {
|
if (data.length < CUSTODY_OFFSET + PUBLIC_KEY_LENGTH) {
|
||||||
@@ -83,6 +96,23 @@ class AnchorIdlJupiterPerpsPositionDecoder {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ΩSolanaAddressΩ decodeCollateralCustodyAccount(
|
||||||
|
SolanaAccountInfo accountInfo
|
||||||
|
) {
|
||||||
|
byte[] data = Base64.getDecoder().decode(accountInfo.dataBase64());
|
||||||
|
|
||||||
|
if (data.length < COLLATERAL_CUSTODY_OFFSET + PUBLIC_KEY_LENGTH) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Jupiter Perps position account data is too short: " + data.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return readPublicKey(
|
||||||
|
data,
|
||||||
|
COLLATERAL_CUSTODY_OFFSET
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private JupiterPerpsPositionDirection decodeDirection(
|
private JupiterPerpsPositionDirection decodeDirection(
|
||||||
byte rawSide
|
byte rawSide
|
||||||
) {
|
) {
|
||||||
@@ -115,11 +145,25 @@ class AnchorIdlJupiterPerpsPositionDecoder {
|
|||||||
return base58.encode(publicKeyBytes);
|
return base58.encode(publicKeyBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static BigInteger readU128(
|
||||||
|
byte[] data,
|
||||||
|
int offset
|
||||||
|
) {
|
||||||
|
byte[] bytes = new byte[U128_LENGTH];
|
||||||
|
|
||||||
|
for (int i = 0; i < U128_LENGTH; i++) {
|
||||||
|
bytes[i] = data[offset + U128_LENGTH - 1 - i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BigInteger(1, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
private static final int ANCHOR_DISCRIMINATOR_LENGTH = 8;
|
private static final int ANCHOR_DISCRIMINATOR_LENGTH = 8;
|
||||||
private static final int PUBLIC_KEY_LENGTH = 32;
|
private static final int PUBLIC_KEY_LENGTH = 32;
|
||||||
private static final int I64_LENGTH = 8;
|
|
||||||
private static final int SIDE_ENUM_LENGTH = 1;
|
private static final int SIDE_ENUM_LENGTH = 1;
|
||||||
|
private static final int I64_LENGTH = 8;
|
||||||
private static final int U64_LENGTH = 8;
|
private static final int U64_LENGTH = 8;
|
||||||
|
private static final int U128_LENGTH = 16;
|
||||||
|
|
||||||
private static final int OWNER_OFFSET = ANCHOR_DISCRIMINATOR_LENGTH;
|
private static final int OWNER_OFFSET = ANCHOR_DISCRIMINATOR_LENGTH;
|
||||||
private static final int POOL_OFFSET = OWNER_OFFSET + PUBLIC_KEY_LENGTH;
|
private static final int POOL_OFFSET = OWNER_OFFSET + PUBLIC_KEY_LENGTH;
|
||||||
@@ -131,6 +175,8 @@ class AnchorIdlJupiterPerpsPositionDecoder {
|
|||||||
private static final int PRICE_OFFSET = SIDE_OFFSET + SIDE_ENUM_LENGTH;
|
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 SIZE_USD_OFFSET = PRICE_OFFSET + U64_LENGTH;
|
||||||
private static final int COLLATERAL_USD_OFFSET = SIZE_USD_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 Base58Codec base58 = new Base58CodecImpl();
|
private static final Base58Codec base58 = new Base58CodecImpl();
|
||||||
}
|
}
|
||||||
+52
-14
@@ -5,8 +5,12 @@ import com.r35157.libs.jupiter.perps.JupiterPerpsService;
|
|||||||
import com.r35157.libs.solana.SolanaAccountInfo;
|
import com.r35157.libs.solana.SolanaAccountInfo;
|
||||||
import com.r35157.libs.solana.SolanaBlockChain;
|
import com.r35157.libs.solana.SolanaBlockChain;
|
||||||
import com.r35157.libs.solana.SolanaProgramAccountMemcmpFilter;
|
import com.r35157.libs.solana.SolanaProgramAccountMemcmpFilter;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -20,26 +24,47 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService {
|
|||||||
this.custodyDecoder = new AnchorIdlJupiterPerpsCustodyDecoder();
|
this.custodyDecoder = new AnchorIdlJupiterPerpsCustodyDecoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
@Override
|
@Override
|
||||||
public JupiterPerpsPosition getPosition(ΩJupiterPerpsPositionAccountΩ positionAccount)
|
public JupiterPerpsPosition getPosition(@NotNull SolanaAccountInfo accountInfo)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException
|
||||||
SolanaAccountInfo accountInfo = solanaBlockChain.getAccountInfo(positionAccount);
|
{
|
||||||
|
guard(accountInfo);
|
||||||
|
|
||||||
if (accountInfo == null) {
|
JupiterPerpsPositionInfo posInfo = positionDecoder.decode(accountInfo);
|
||||||
throw new IllegalArgumentException("Jupiter Perps position account does not exist: " + positionAccount);
|
ΩUSDCAmountΩ sizeUsd = posInfo.sizeUsd();
|
||||||
}
|
|
||||||
|
|
||||||
if (!JUPITER_PERPS_PROGRAM_ID.equals(accountInfo.owner())) {
|
CustodyAccountInfo cai = custodyDecoder.decode(custodyAccountInfo);
|
||||||
throw new IllegalArgumentException(
|
BigInteger cumulativeInterestSnapshot = positionDecoder.decodeCumulativeInterestSnapshot(positionAccountInfo);
|
||||||
"Account is not owned by Jupiter Perps program: " + positionAccount
|
ΩUSDCAmountΩ borrowFeePendingUsd = calculateBorrowFeeUsd(
|
||||||
|
cumulativeInterestSnapshot,
|
||||||
|
sizeUsd
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
ΩSPLMintAddressΩ tradedTokenMint = getTradedTokenMint(accountInfo);
|
JupiterPerpsPosition pos = new JupiterPerpsPosition(
|
||||||
JupiterPerpsPosition pos = positionDecoder.decode(positionAccount, accountInfo, tradedTokenMint);
|
accountInfo,
|
||||||
|
posInfo.entryPrice(),
|
||||||
|
posInfo.direction(),
|
||||||
|
sizeUsd,
|
||||||
|
posInfo.collateralUsd(),
|
||||||
|
cai.mintAddress(),
|
||||||
|
borrowFeePendingUsd
|
||||||
|
);
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
private void guard(SolanaAccountInfo accountInfo) {
|
||||||
|
ΩSolanaProgramIdΩ owner = accountInfo.owner();
|
||||||
|
if (!JUPITER_PERPS_PROGRAM_ID.equals(owner)) {
|
||||||
|
String errorMsg = "Account '" + accountInfo.address() + "' is not owned by Jupiter Perps program ("
|
||||||
|
+ JUPITER_PERPS_PROGRAM_ID + "), instead it is owned by '"
|
||||||
|
+ owner
|
||||||
|
+ "'";
|
||||||
|
throw new IllegalArgumentException(errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<JupiterPerpsPosition> getOpenPositions(ΩSolanaWalletIdΩ owner)
|
public Set<JupiterPerpsPosition> getOpenPositions(ΩSolanaWalletIdΩ owner)
|
||||||
@@ -73,7 +98,20 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService {
|
|||||||
return Set.copyOf(positions);
|
return Set.copyOf(positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ΩSPLMintAddressΩ getTradedTokenMint(SolanaAccountInfo positionAccountInfo)
|
private BigDecimal calculateBorrowFeeUsd(
|
||||||
|
BigInteger cumulativeInterestSnapshot,
|
||||||
|
ΩUSDCAmountΩ sizeUsd
|
||||||
|
) {
|
||||||
|
BigInteger difference = currentCumulativeInterestRate.subtract(cumulativeInterestSnapshot);
|
||||||
|
BigDecimal borrowFeeUsd =
|
||||||
|
new BigDecimal(difference)
|
||||||
|
.multiply(sizeUsd)
|
||||||
|
.divide(BigDecimal.valueOf(1_000_000_000L), 6, RoundingMode.CEILING);
|
||||||
|
|
||||||
|
return borrowFeeUsd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*private ΩSPLMintAddressΩ getTradedTokenMint(SolanaAccountInfo positionAccountInfo)
|
||||||
throws IOException, InterruptedException
|
throws IOException, InterruptedException
|
||||||
{
|
{
|
||||||
ΩSolanaAddressΩ custodyAccount = positionDecoder.decodeCustodyAccount(positionAccountInfo);
|
ΩSolanaAddressΩ custodyAccount = positionDecoder.decodeCustodyAccount(positionAccountInfo);
|
||||||
@@ -87,7 +125,7 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService {
|
|||||||
|
|
||||||
ΩSPLMintAddressΩ mintAddress = custodyDecoder.decodeMint(custodyAccountInfo);
|
ΩSPLMintAddressΩ mintAddress = custodyDecoder.decodeMint(custodyAccountInfo);
|
||||||
return mintAddress;
|
return mintAddress;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private static final ΩJupiterPerpsProgramIdΩ JUPITER_PERPS_PROGRAM_ID =
|
private static final ΩJupiterPerpsProgramIdΩ JUPITER_PERPS_PROGRAM_ID =
|
||||||
"PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu";
|
"PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu";
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.r35157.libs.jupiter.perps.impl.anchoridl;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
public record CustodyAccountInfo(
|
||||||
|
ΩSPLMintAddressΩ mintAddress,
|
||||||
|
BigInteger currentCumulativeInterestRate
|
||||||
|
) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.r35157.libs.jupiter.perps.impl.anchoridl;
|
||||||
|
|
||||||
|
public class DecodingPrimitives {
|
||||||
|
|
||||||
|
public static byte[] readU128(byte[] data, int offset) {
|
||||||
|
byte[] bytes = new byte[U128_LENGTH];
|
||||||
|
|
||||||
|
for (int i = 0; i < U128_LENGTH; i++) {
|
||||||
|
bytes[i] = data[offset + U128_LENGTH - 1 - i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] readPublicKey(byte[] data, int offset) {
|
||||||
|
byte[] publicKeyBytes = new byte[PUBLIC_KEY_LENGTH];
|
||||||
|
|
||||||
|
System.arraycopy(
|
||||||
|
data,
|
||||||
|
offset,
|
||||||
|
publicKeyBytes,
|
||||||
|
0,
|
||||||
|
PUBLIC_KEY_LENGTH
|
||||||
|
);
|
||||||
|
|
||||||
|
return publicKeyBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int U128_LENGTH = 16;
|
||||||
|
public static final int PUBLIC_KEY_LENGTH = 32;
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package com.r35157.libs.jupiter.perps.impl.anchoridl;
|
||||||
|
|
||||||
|
import com.r35157.libs.jupiter.perps.JupiterPerpsPositionDirection;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public record JupiterPerpsPositionInfo(
|
||||||
|
ΩUSDCPriceΩ entryPrice,
|
||||||
|
JupiterPerpsPositionDirection direction,
|
||||||
|
ΩUSDCAmountΩ sizeUsd,
|
||||||
|
ΩUSDCAmountΩ collateralUsd
|
||||||
|
) {}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.r35157.libs.raydium;
|
package com.r35157.libs.raydium;
|
||||||
|
|
||||||
import com.r35157.libs.valuetypes.basic.AssetPrice;
|
|
||||||
import com.r35157.libs.valuetypes.basic.MoneyAmount;
|
import com.r35157.libs.valuetypes.basic.MoneyAmount;
|
||||||
import com.r35157.libs.valuetypes.basic.Range;
|
import com.r35157.libs.valuetypes.basic.Range;
|
||||||
|
|
||||||
@@ -16,11 +15,11 @@ public interface Raydium {
|
|||||||
* to any Raydium liquidity pool supported by the implementation.</p>
|
* to any Raydium liquidity pool supported by the implementation.</p>
|
||||||
*
|
*
|
||||||
* @param poolId the Raydium liquidity pool id
|
* @param poolId the Raydium liquidity pool id
|
||||||
* @return the current pool price
|
* @return the current pool price expressed as a Solana amount
|
||||||
* @throws IOException if the price could not be fetched or the response could not be parsed
|
* @throws IOException if the price could not be fetched or the response could not be parsed
|
||||||
* @throws InterruptedException if the calling thread is interrupted while fetching the price
|
* @throws InterruptedException if the calling thread is interrupted while fetching the price
|
||||||
*/
|
*/
|
||||||
AssetPrice fetchPoolPrice(ΩRaydiumLiquidityPoolIdΩ poolId) throws IOException, InterruptedException;
|
ΩSolanaAmountΩ fetchPoolPrice(ΩRaydiumLiquidityPoolIdΩ poolId) throws IOException, InterruptedException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the Raydium liquidity pool ids where the supplied Solana owner address has positions.
|
* Fetches the Raydium liquidity pool ids where the supplied Solana owner address has positions.
|
||||||
@@ -184,7 +183,7 @@ public interface Raydium {
|
|||||||
* @param decimalPlaces the number decimal places in the resulting price currency
|
* @param decimalPlaces the number decimal places in the resulting price currency
|
||||||
* @return the price range represented by the concentrated liquidity position
|
* @return the price range represented by the concentrated liquidity position
|
||||||
*/
|
*/
|
||||||
Range<AssetPrice> calculateConcentratedPositionPriceRange(
|
Range<ΩPriceΩ> calculateConcentratedPositionPriceRange(
|
||||||
RaydiumConcentratedPositionState positionState,
|
RaydiumConcentratedPositionState positionState,
|
||||||
RaydiumConcentratedPoolInfo poolInfo,
|
RaydiumConcentratedPoolInfo poolInfo,
|
||||||
int decimalPlaces
|
int decimalPlaces
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.r35157.libs.raydium;
|
package com.r35157.libs.raydium;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents basic information about a Raydium concentrated liquidity pool.
|
* Represents basic information about a Raydium concentrated liquidity pool.
|
||||||
*
|
*
|
||||||
@@ -19,6 +17,9 @@ import java.math.BigDecimal;
|
|||||||
* @param mintBDecimals the number of decimals used by token B
|
* @param mintBDecimals the number of decimals used by token B
|
||||||
* @param priceEstimate the pool price estimate as reported by Raydium
|
* @param priceEstimate the pool price estimate as reported by Raydium
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
public record RaydiumConcentratedPoolInfo(
|
public record RaydiumConcentratedPoolInfo(
|
||||||
ΩRaydiumLiquidityPoolConcentratedIdΩ poolId,
|
ΩRaydiumLiquidityPoolConcentratedIdΩ poolId,
|
||||||
ΩSPLMintAddressΩ mintA,
|
ΩSPLMintAddressΩ mintA,
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.r35157.libs.raydium;
|
package com.r35157.libs.raydium;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents raw on-chain state for a Raydium concentrated liquidity pool.
|
* Represents raw on-chain state for a Raydium concentrated liquidity pool.
|
||||||
*
|
*
|
||||||
@@ -23,6 +21,9 @@ import java.math.BigInteger;
|
|||||||
* @param sqrtPriceX64 the current square-root price in Q64.64 fixed-point format
|
* @param sqrtPriceX64 the current square-root price in Q64.64 fixed-point format
|
||||||
* @param tickCurrent the current Raydium liquidity tick index
|
* @param tickCurrent the current Raydium liquidity tick index
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
public record RaydiumConcentratedPoolState(
|
public record RaydiumConcentratedPoolState(
|
||||||
ΩRaydiumLiquidityPoolConcentratedIdΩ poolId,
|
ΩRaydiumLiquidityPoolConcentratedIdΩ poolId,
|
||||||
ΩRaydiumLiquidityΩ liquidity,
|
ΩRaydiumLiquidityΩ liquidity,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.r35157.libs.raydium;
|
package com.r35157.libs.raydium;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
public record RaydiumConcentratedPositionState(
|
public record RaydiumConcentratedPositionState(
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.r35157.libs.raydium;
|
package com.r35157.libs.raydium;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a standard Raydium liquidity pool position.
|
* Represents a standard Raydium liquidity pool position.
|
||||||
*
|
*
|
||||||
@@ -19,6 +17,9 @@ import java.math.BigDecimal;
|
|||||||
* @param lpTokenAccount the SPL token account holding the liquidity pool tokens
|
* @param lpTokenAccount the SPL token account holding the liquidity pool tokens
|
||||||
* @param lpTokenAmount the amount of liquidity pool tokens held in the SPL token account
|
* @param lpTokenAmount the amount of liquidity pool tokens held in the SPL token account
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
public record RaydiumLiquidityPoolPositionStandard(
|
public record RaydiumLiquidityPoolPositionStandard(
|
||||||
ΩRaydiumLiquidityPoolPositionIdΩ positionId,
|
ΩRaydiumLiquidityPoolPositionIdΩ positionId,
|
||||||
ΩRaydiumLiquidityPoolPositionMintIdΩ lpMintId,
|
ΩRaydiumLiquidityPoolPositionMintIdΩ lpMintId,
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
package com.r35157.libs.raydium;
|
package com.r35157.libs.raydium;
|
||||||
|
|
||||||
import com.r35157.libs.valuetypes.basic.AssetPrice;
|
import com.r35157.libs.valuetypes.basic.MoneyAmount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the current price of the tokens in a Raydium liquidity pool.
|
* Represents the price of a Raydium liquidity pool.
|
||||||
*
|
*
|
||||||
* <p>The 'poolId' identifies the Raydium liquidity pool for which the current token price applies.
|
* <p>The pool id identifies the Raydium liquidity pool for which the price applies.
|
||||||
* The 'price' represents the price value returned or calculated for that pool.</p>
|
* The amount contains the price value returned or calculated for that pool.</p>
|
||||||
*
|
*
|
||||||
* @param poolId the Raydium liquidity pool id that the price belongs to
|
* @param poolId the Raydium liquidity pool id that the price belongs to
|
||||||
* @param price the price for a token in the liquidity pool
|
* @param amount the price amount for the liquidity pool
|
||||||
*/
|
*/
|
||||||
public record RaydiumLiquidityPoolPrice(
|
public record RaydiumLiquidityPoolPrice(
|
||||||
ΩRaydiumLiquidityPoolIdΩ poolId,
|
ΩRaydiumLiquidityPoolIdΩ poolId,
|
||||||
AssetPrice price
|
MoneyAmount amount
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.r35157.libs.raydium;
|
package com.r35157.libs.raydium;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents token amounts for a Raydium liquidity pool or liquidity position.
|
* Represents token amounts for a Raydium liquidity pool or liquidity position.
|
||||||
*
|
*
|
||||||
@@ -18,6 +16,9 @@ import java.math.BigDecimal;
|
|||||||
* @param mintB the SPL mint address of token B
|
* @param mintB the SPL mint address of token B
|
||||||
* @param amountB the amount of token B
|
* @param amountB the amount of token B
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
public record RaydiumLiquidityPoolTokenAmounts(
|
public record RaydiumLiquidityPoolTokenAmounts(
|
||||||
ΩRaydiumLiquidityPoolIdΩ poolId,
|
ΩRaydiumLiquidityPoolIdΩ poolId,
|
||||||
ΩSPLMintAddressΩ mintA,
|
ΩSPLMintAddressΩ mintA,
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.r35157.libs.solana;
|
package com.r35157.libs.solana;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the total supply of an SPL token mint.
|
* Represents the total supply of an SPL token mint.
|
||||||
*
|
*
|
||||||
@@ -14,6 +12,9 @@ import java.math.BigDecimal;
|
|||||||
* @param decimals the number of decimals used by the token mint
|
* @param decimals the number of decimals used by the token mint
|
||||||
* @param programId the SPL token program id for the mint
|
* @param programId the SPL token program id for the mint
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
public record SPLTokenSupply(
|
public record SPLTokenSupply(
|
||||||
ΩSPLMintAddressΩ mintAddress,
|
ΩSPLMintAddressΩ mintAddress,
|
||||||
ΩAmountΩ uiAmount,
|
ΩAmountΩ uiAmount,
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
package com.r35157.libs.solana;
|
||||||
|
|
||||||
|
import com.r35157.libs.solana.valuetypes.SolanaProgramDerivedAddress;
|
||||||
|
import com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram;
|
||||||
|
import com.r35157.libs.valuetypes.basic.MoneyAmount;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides read-oriented access to the Solana blockchain.
|
||||||
|
*
|
||||||
|
* <p>This interface exposes the Solana operations needed by higher-level
|
||||||
|
* integrations. It can fetch native SOL balances, SPL token holdings, NFT-like
|
||||||
|
* token holding candidates, account information and program derived addresses.</p>
|
||||||
|
*
|
||||||
|
* <p>The interface is intentionally generic and does not contain Raydium-specific
|
||||||
|
* logic. Higher-level integrations are expected to interpret Solana accounts,
|
||||||
|
* token holdings and derived addresses according to their own domain rules.</p>
|
||||||
|
*/
|
||||||
|
public interface SolanaBlockChain {
|
||||||
|
/**
|
||||||
|
* Fetches the native SOL balance for a Solana address.
|
||||||
|
*
|
||||||
|
* @param address the Solana address to inspect
|
||||||
|
* @return the native SOL balance for the address
|
||||||
|
* @throws IOException if the balance could not be fetched or parsed
|
||||||
|
* @throws InterruptedException if the calling thread is interrupted while fetching the balance
|
||||||
|
*/
|
||||||
|
ΩSolanaAmountΩ getBalanceInSolana(ΩSolanaAddressΩ address) throws IOException, InterruptedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the native SOL balance for a Solana address in lamports.
|
||||||
|
*
|
||||||
|
* <p>Lamports are the smallest unit of native SOL.</p>
|
||||||
|
*
|
||||||
|
* @param address the Solana address to inspect
|
||||||
|
* @return the native SOL balance for the address in lamports
|
||||||
|
* @throws IOException if the balance could not be fetched or parsed
|
||||||
|
* @throws InterruptedException if the calling thread is interrupted while fetching the balance
|
||||||
|
*/
|
||||||
|
ΩlamportsΩ getBalanceInLamport(ΩSolanaAddressΩ address) throws IOException, InterruptedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches SPL token holdings owned by a Solana address for a specific token program.
|
||||||
|
*
|
||||||
|
* <p>The supplied token program decides which token accounts are inspected. For example,
|
||||||
|
* callers may query the original SPL Token Program or the Token-2022 Program depending
|
||||||
|
* on which token accounts they need to discover.</p>
|
||||||
|
*
|
||||||
|
* @param ownerAddress the Solana owner address whose token holdings should be inspected
|
||||||
|
* @param splProgramId the SPL token program to query
|
||||||
|
* @return a map of SPL mint addresses to token holding information
|
||||||
|
* @throws IOException if the token holdings could not be fetched or parsed
|
||||||
|
* @throws InterruptedException if the calling thread is interrupted while fetching token holdings
|
||||||
|
*/
|
||||||
|
Map<ΩSPLMintAddressΩ, SPLTokenHolding> getSPLTokenHoldings(
|
||||||
|
ΩSolanaAddressΩ ownerAddress,
|
||||||
|
SolanaSPLTokenProgram splProgramId
|
||||||
|
) throws IOException, InterruptedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches NFT-like token mint address candidates owned by a Solana address for a specific token program.
|
||||||
|
*
|
||||||
|
* <p>This method identifies token holdings that look like NFTs within the supplied token
|
||||||
|
* program. A returned address is only a candidate. Higher-level integrations are responsible
|
||||||
|
* for deciding whether the returned address has domain-specific meaning.</p>
|
||||||
|
*
|
||||||
|
* // TODO This method currently identifies candidates from the owner's token holdings only.
|
||||||
|
* // A token with zero decimals and an owner balance of one is not guaranteed to be a real NFT,
|
||||||
|
* // because the mint's total supply may still be greater than one. A future implementation
|
||||||
|
* // should verify the mint supply, for example by using Solana getTokenSupply, before treating
|
||||||
|
* // the result as a confirmed NFT.
|
||||||
|
*
|
||||||
|
* @param ownerAddress the Solana owner address whose NFT-like holdings should be inspected
|
||||||
|
* @param splProgram the SPL token program to query
|
||||||
|
* @return the NFT-like Solana mint address candidates owned by the address
|
||||||
|
* @throws IOException if the NFT candidate addresses could not be fetched or parsed
|
||||||
|
* @throws InterruptedException if the calling thread is interrupted while fetching NFT candidate addresses
|
||||||
|
*/
|
||||||
|
Set<ΩSolanaNFTAddressΩ> getSolanaNFTCandidateAddresses(
|
||||||
|
ΩSolanaAddressΩ ownerAddress,
|
||||||
|
SolanaSPLTokenProgram splProgram
|
||||||
|
) throws IOException, InterruptedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a Solana program derived address for a program id and a set of seeds.
|
||||||
|
*
|
||||||
|
* <p>The seeds describe the logical inputs used to derive the address. The implementation
|
||||||
|
* is responsible for converting each seed into the byte representation required by Solana.</p>
|
||||||
|
*
|
||||||
|
* @param programId the Solana program id used to derive the address
|
||||||
|
* @param seeds the seeds used when deriving the program address
|
||||||
|
* @return the derived Solana address together with its bump value
|
||||||
|
*/
|
||||||
|
SolanaProgramDerivedAddress findProgramAddress(
|
||||||
|
ΩSolanaProgramIdΩ programId,
|
||||||
|
List<SolanaProgramAddressSeed> seeds
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches account information for a Solana account address.
|
||||||
|
*
|
||||||
|
* <p>If the account does not exist, this method returns {@code null}. If the account exists,
|
||||||
|
* the returned value contains the account address, the owning Solana program id and the
|
||||||
|
* account data encoded as Base64.</p>
|
||||||
|
*
|
||||||
|
* @param accountAddress the Solana account address to inspect
|
||||||
|
* @return account information, or {@code null} if the account does not exist
|
||||||
|
* @throws IOException if the account information could not be fetched or parsed
|
||||||
|
* @throws InterruptedException if the calling thread is interrupted while fetching account information
|
||||||
|
*/
|
||||||
|
SolanaAccountInfo getAccountInfo(ΩSolanaAddressΩ accountAddress)
|
||||||
|
throws IOException, InterruptedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a raw 32-byte Solana address into its textual Solana address representation.
|
||||||
|
*
|
||||||
|
* <p>This method is intended for callers that have obtained raw Solana address bytes from
|
||||||
|
* account data and need the normal string representation used elsewhere in the API.</p>
|
||||||
|
*
|
||||||
|
* @param addressBytes the raw 32-byte Solana address
|
||||||
|
* @return the encoded Solana address
|
||||||
|
* @throws IllegalArgumentException if the supplied byte array is not a valid Solana address length
|
||||||
|
*/
|
||||||
|
ΩSolanaAddressΩ encodeSolanaAddress(byte[] addressBytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the total supply of an SPL token mint for a specific token program.
|
||||||
|
*
|
||||||
|
* <p>The supplied token program identifies which SPL token program owns the mint,
|
||||||
|
* for example the original SPL Token Program or the Token-2022 Program.</p>
|
||||||
|
*
|
||||||
|
* @param mintAddress the SPL mint address whose supply should be fetched
|
||||||
|
* @param splProgram the SPL token program to query
|
||||||
|
* @return the SPL token supply for the mint
|
||||||
|
* @throws IOException if the token supply could not be fetched or parsed
|
||||||
|
* @throws InterruptedException if the calling thread is interrupted while fetching token supply
|
||||||
|
*/
|
||||||
|
SPLTokenSupply getSPLTokenSupply(
|
||||||
|
ΩSPLMintAddressΩ mintAddress,
|
||||||
|
SolanaSPLTokenProgram splProgram
|
||||||
|
) throws IOException, InterruptedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches accounts owned by a Solana program using server-side account data filters.
|
||||||
|
*
|
||||||
|
* <p>This method uses Solana's {@code getProgramAccounts} RPC call. The supplied filters
|
||||||
|
* are sent to the RPC node, so matching is performed server-side instead of fetching all
|
||||||
|
* accounts owned by the program and filtering them locally.</p>
|
||||||
|
*
|
||||||
|
* <p>The initial supported filter type is {@link SolanaProgramAccountMemcmpFilter}, which
|
||||||
|
* matches bytes at a specific offset in the account data.</p>
|
||||||
|
*
|
||||||
|
* @param programId the Solana program id that owns the accounts to search
|
||||||
|
* @param filters the memcmp filters to apply when searching program accounts
|
||||||
|
* @return the matching program accounts
|
||||||
|
* @throws IOException if the program accounts could not be fetched or parsed
|
||||||
|
* @throws InterruptedException if the calling thread is interrupted while fetching program accounts
|
||||||
|
*/
|
||||||
|
Set<SolanaAccountInfo> getProgramAccounts(
|
||||||
|
ΩSolanaProgramIdΩ programId,
|
||||||
|
Set<SolanaProgramAccountMemcmpFilter> filters
|
||||||
|
) throws IOException, InterruptedException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.r35157.libs.solana;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter used when fetching accounts owned by a Solana program.
|
||||||
|
*
|
||||||
|
* <p>The initial supported filter type is {@code memcmp}, which asks the
|
||||||
|
* Solana RPC node to only return accounts where the account data at a specific
|
||||||
|
* byte offset matches a base58 encoded value.</p>
|
||||||
|
*
|
||||||
|
* @param offset the byte offset in the account data where comparison starts
|
||||||
|
* @param bytes the base58 encoded bytes to match
|
||||||
|
*/
|
||||||
|
public record SolanaProgramAccountMemcmpFilter(
|
||||||
|
int offset,
|
||||||
|
String bytes
|
||||||
|
) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.r35157.libs.valuetypes.basic;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public record MoneyPrice(
|
||||||
|
ΩPriceΩ price,
|
||||||
|
CurrencyType currencyType
|
||||||
|
) { }
|
||||||
@@ -5,34 +5,44 @@ import com.r35157.libs.jupiter.perps.JupiterPerpsService;
|
|||||||
import com.r35157.libs.jupiter.perps.impl.anchoridl.AnchorIdlJupiterPerpsServiceImpl;
|
import com.r35157.libs.jupiter.perps.impl.anchoridl.AnchorIdlJupiterPerpsServiceImpl;
|
||||||
import com.r35157.libs.solana.SolanaBlockChain;
|
import com.r35157.libs.solana.SolanaBlockChain;
|
||||||
import com.r35157.libs.solana.impl.ref.SolanaBlockChainImpl;
|
import com.r35157.libs.solana.impl.ref.SolanaBlockChainImpl;
|
||||||
import com.r35157.nenjim.hubd.ctx.Context;
|
|
||||||
import com.r35157.nenjim.hubd.NenjimHub;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import java.lang.management.ClassLoadingMXBean;
|
|
||||||
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.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
// TODO: Consider if we really need a Main class or we just need to move the main method to NenjimHubImpl?
|
// TODO: Consider if we really need a Main class or we just need to move the main method to NenjimHubImpl?
|
||||||
static void main(String[] args) throws Exception {
|
static void main(String[] args) throws Exception {
|
||||||
NenjimHubImpl nenjimHub = new NenjimHubImpl();
|
//NenjimHubImpl nenjimHub = new NenjimHubImpl();
|
||||||
|
|
||||||
/*
|
|
||||||
SolanaBlockChain sbc = new SolanaBlockChainImpl();
|
SolanaBlockChain sbc = new SolanaBlockChainImpl();
|
||||||
JupiterPerpsService jupiter = new AnchorIdlJupiterPerpsServiceImpl(sbc);
|
JupiterPerpsService jupiter = new AnchorIdlJupiterPerpsServiceImpl(sbc);
|
||||||
ΩSolanaWalletIdΩ walletId = "vj98roDZ7744EBfxyuDFkKpEGCsKQLr7K8UFRumJNHf";
|
ΩSolanaWalletIdΩ walletId = "vj98roDZ7744EBfxyuDFkKpEGCsKQLr7K8UFRumJNHf";
|
||||||
|
|
||||||
Set<JupiterPerpsPosition> positions = jupiter.getOpenPositions(walletId);
|
Set<JupiterPerpsPosition> positions = jupiter.getOpenPositions(walletId);
|
||||||
|
|
||||||
|
for (JupiterPerpsPosition position : positions) {
|
||||||
|
System.out.println(" PositionAccount: " + position.positionAccount());
|
||||||
|
System.out.println(" Token mint: " + position.tradedTokenMint());
|
||||||
|
System.out.println(" Direction: " + position.direction());
|
||||||
|
System.out.println(" Value: " + position.value());
|
||||||
|
System.out.println(" Size $: " + position.size());
|
||||||
|
System.out.println(" PnL: " + position.pnl() + " " + position.pnlPercent());
|
||||||
|
System.out.println(" Leverage: " + position.leverage() + "x");
|
||||||
|
System.out.println(" Entry price: " + position.entryPrice());
|
||||||
|
System.out.println(" Market price: " + position.marketPrice());
|
||||||
|
System.out.println(" Collateral: " + position.collateral());
|
||||||
|
System.out.println(" Totals fees: " + position.totalFees());
|
||||||
|
System.out.println(" Borrow Fees Due: " + position.borrowFeesDue());
|
||||||
|
System.out.println(" Close Fees Pending: " + position.closeFeePending());
|
||||||
|
System.out.println("Amount locked for account rent (SOL): " + position.accountRent());
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
int a=0;
|
int a=0;
|
||||||
*/
|
//nenjimHub.awaitShutdown();
|
||||||
nenjimHub.awaitShutdown();
|
|
||||||
|
|
||||||
/* try {
|
/* try {
|
||||||
log.info("Auto-starting 2 Nenjim application(s)...");
|
log.info("Auto-starting 2 Nenjim application(s)...");
|
||||||
|
|||||||
Reference in New Issue
Block a user