X: Moved all API files into Implementation package

Until Nenjim works better navigation in the code is just too annoying.
This commit is contained in:
2026-07-01 09:21:11 +02:00
parent 12f2612bfa
commit 2231a5d300
30 changed files with 479 additions and 29 deletions
-1
View File
@@ -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,7 @@
package com.r35157.libs.math;
import java.math.BigDecimal;
public interface UtilsDouble {
double erf(BigDecimal x);
}
@@ -0,0 +1,14 @@
package com.r35157.libs.notification;
import java.io.IOException;
public interface AddressedNotifier<
D extends NotificationDestination,
M extends NotificationMessage>
{
void push(D destination, M message) throws IOException;
default BoundNotifier<M> bind(D destination) {
return message -> push(destination, message);
}
}
@@ -0,0 +1,7 @@
package com.r35157.libs.notification;
import java.io.IOException;
public interface BoundNotifier<M extends NotificationMessage> {
void push(M message) throws IOException;
}
@@ -0,0 +1,3 @@
package com.r35157.libs.notification;
public interface NotificationDestination {}
@@ -0,0 +1,4 @@
package com.r35157.libs.notification;
public interface NotificationMessage {
}
@@ -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,16 @@
package com.r35157.libs.valuetypes.basic;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public record CurrencyType(
UUID id,
String name,
String symbol
) {
@Override
public @NotNull String toString() {
return symbol;
}
}
@@ -0,0 +1,70 @@
package com.r35157.libs.valuetypes.basic;
import org.jetbrains.annotations.NotNull;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Semantic Versioning (SemVer):
* A version number has the form MAJOR.MINOR.PATCH.
* - Increment MAJOR for incompatible API changes,
* - Increment MINOR for added functionality in a backward-compatible way,
* - Increment PATCH for backward-compatible bug fixes or improvements.
* TODO: Not the whole specification is implemented yet!
*/
public record SemanticVersion(int major, int minor, int patch) {
/**
* Creates a SemanticVersion and validates that all components are valid.
*
* @throws IllegalArgumentException if any of {@code major}, {@code minor}, or {@code patch} is negative
*/
public SemanticVersion {
initializationGuardClause(major, minor, patch);
}
public static SemanticVersion of(int major, int minor, int patch) {
return new SemanticVersion(major, minor, patch);
}
public static SemanticVersion of(int major, int minor) {
return of(major, minor, 0);
}
public static SemanticVersion of(int major) {
return of(major, 0);
}
public static SemanticVersion of(@NotNull String versionStr) {
final String s = versionStr.trim();
final Matcher m = SEMVER_REGEX.matcher(s);
if (!m.matches()) {
throw new IllegalArgumentException("Invalid semantic version: '" + versionStr + "'!");
}
try {
final int major = Integer.parseInt(m.group(1));
final int minor = m.group(2) != null ? Integer.parseInt(m.group(2)) : 0;
final int patch = m.group(3) != null ? Integer.parseInt(m.group(3)) : 0;
return of(major, minor, patch);
} catch (NumberFormatException e) {
// Happens only with overruns
throw new IllegalArgumentException("Invalid semantic version: '" + versionStr + "'!", e);
}
}
@Override
public @NotNull String toString() {
return "%d.%d.%d".formatted(major, minor, patch);
}
private void initializationGuardClause(int major, int minor, int patch) throws IllegalArgumentException {
if (major < 0) throw new IllegalArgumentException("Version element 'major' cannot be negative - was '" + major + "'!");
if (minor < 0) throw new IllegalArgumentException("Version element 'minor' cannot be negative - was '" + minor + "'!");
if (patch < 0) throw new IllegalArgumentException("Version element 'patch' cannot be negative - was '" + patch + "'!");
}
private static final Pattern SEMVER_REGEX =
Pattern.compile("^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+))?)?$");
}
@@ -0,0 +1,7 @@
package com.r35157.libs.valuetypes.basic;
public record SmtpConfiguration(
NetworkEndPoint networkEndPoint,
Credentials credentials
) {
}
@@ -0,0 +1,6 @@
package com.r35157.libs.valuetypes.basic;
public record TradingPair(
CurrencyType base, // The thing you are buying or selling.
CurrencyType quote // The currency/unit used to price the base asset.
) { }
@@ -0,0 +1,5 @@
package com.r35157.nenjim.hubd.journal;
public interface JournalManager {
Journal getJournal(String moduleName);
}
@@ -0,0 +1,4 @@
package com.r35157.nenjim.hubd.module;
public record Module() {
}
@@ -0,0 +1,5 @@
package com.r35157.libs.codec;
public interface Base58Codec {
String encode(byte[] input);
}
@@ -0,0 +1,27 @@
package com.r35157.libs.jupiter.perps;
/**
* 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 entryPrice the entry price of the position, denominated in USDC
* @param direction whether the position is long or short
* @param tradedTokenMint the mint address of the token being traded
* @param sizeUsd the size of this position in USD
* @param collateralUsd the amount of USD representing the collateral for this position
* @oaram borrowFeeUsd TODO
*/
public record JupiterPerpsPosition(
ΩJupiterPerpsPositionAccountΩ positionAccount,
ΩUSDCPriceΩ entryPrice,
JupiterPerpsPositionDirection direction,
ΩSPLMintAddressΩ tradedTokenMint,
ΩUSDCAmountΩ sizeUsd,
ΩUSDCAmountΩ collateralUsd,
ΩUSDCAmountΩ borrowFeeUsd
) {
}
@@ -0,0 +1,9 @@
package com.r35157.libs.jupiter.perps;
/**
* Direction of a Jupiter Perps position.
*/
public enum JupiterPerpsPositionDirection {
LONG,
SHORT
}
@@ -0,0 +1,45 @@
package com.r35157.libs.jupiter.perps;
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(Ω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;
}
@@ -1,11 +1,8 @@
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.Range; import com.r35157.libs.valuetypes.basic.Range;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal;
import java.util.Set; import java.util.Set;
public interface Raydium { public interface Raydium {
@@ -16,11 +13,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 +181,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.
* *
@@ -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.
* *
@@ -1,7 +1,5 @@
package com.r35157.libs.raydium; package com.r35157.libs.raydium;
import java.math.BigInteger;
public record RaydiumConcentratedPositionState( public record RaydiumConcentratedPositionState(
ΩRaydiumLiquidityPoolPositionNftIdΩ nftId, ΩRaydiumLiquidityPoolPositionNftIdΩ nftId,
ΩRaydiumLiquidityPoolConcentratedIdΩ poolId, ΩRaydiumLiquidityPoolConcentratedIdΩ poolId,
@@ -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.
* *
@@ -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.
* *
@@ -1,7 +1,5 @@
package com.r35157.libs.solana; package com.r35157.libs.solana;
import java.math.BigDecimal;
/** /**
* Represents an SPL token holding owned by a Solana address. * Represents an SPL token holding owned by a Solana address.
* *
@@ -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.
* *
@@ -0,0 +1,166 @@
package com.r35157.libs.solana;
import com.r35157.libs.solana.valuetypes.SolanaProgramDerivedAddress;
import com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram;
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
) {
}
@@ -2,8 +2,6 @@ package com.r35157.libs.valuetypes.basic;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal;
public record MoneyAmount( public record MoneyAmount(
ΩAmountΩ amount, ΩAmountΩ amount,
CurrencyType currencyType CurrencyType currencyType
@@ -0,0 +1,6 @@
package com.r35157.libs.valuetypes.basic;
public record MoneyPrice(
ΩPriceΩ price,
CurrencyType currencyType
) { }