From 2231a5d3005b78aa8ebf73c09c309a0ed9d0b437e2a1f379bed6d8eda7de228a Mon Sep 17 00:00:00 2001 From: Minimons Date: Wed, 1 Jul 2026 09:21:11 +0200 Subject: [PATCH] X: Moved all API files into Implementation package Until Nenjim works better navigation in the code is just too annoying. --- build.gradle.kts | 1 - .../com/r35157/libs/math/UtilsDouble.java | 7 + .../libs/notification/AddressedNotifier.java | 14 ++ .../libs/notification/BoundNotifier.java | 7 + .../notification/NotificationDestination.java | 3 + .../notification/NotificationMessage.java | 4 + .../valuetypes/WellKnownCurrencyTypes.java | 52 ++++++ .../libs/valuetypes/basic/CurrencyType.java | 16 ++ .../valuetypes/basic/SemanticVersion.java | 70 ++++++++ .../valuetypes/basic/SmtpConfiguration.java | 7 + .../libs/valuetypes/basic/TradingPair.java | 6 + .../nenjim/hubd/journal/JournalManager.java | 5 + .../com/r35157/nenjim/hubd/module/Module.java | 4 + .../com/r35157/libs/codec/Base58Codec.tjava | 5 + .../jupiter/perps/JupiterPerpsPosition.tjava | 27 +++ .../perps/JupiterPerpsPositionDirection.tjava | 9 + .../jupiter/perps/JupiterPerpsService.tjava | 45 +++++ .../com/r35157/libs/raydium/Raydium.tjava | 9 +- .../raydium/RaydiumConcentratedPoolInfo.tjava | 2 - .../RaydiumConcentratedPoolState.tjava | 2 - .../RaydiumConcentratedPositionState.tjava | 2 - ...RaydiumLiquidityPoolPositionStandard.tjava | 2 - .../raydium/RaydiumLiquidityPoolPrice.tjava | 12 +- .../RaydiumLiquidityPoolTokenAmounts.tjava | 2 - .../r35157/libs/solana/SPLTokenHolding.tjava | 2 - .../r35157/libs/solana/SPLTokenSupply.tjava | 2 - .../r35157/libs/solana/SolanaBlockChain.tjava | 166 ++++++++++++++++++ .../SolanaProgramAccountMemcmpFilter.tjava | 17 ++ .../libs/valuetypes/basic/MoneyAmount.tjava | 2 - .../libs/valuetypes/basic/MoneyPrice.tjava | 6 + 30 files changed, 479 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/r35157/libs/math/UtilsDouble.java create mode 100644 src/main/java/com/r35157/libs/notification/AddressedNotifier.java create mode 100644 src/main/java/com/r35157/libs/notification/BoundNotifier.java create mode 100644 src/main/java/com/r35157/libs/notification/NotificationDestination.java create mode 100644 src/main/java/com/r35157/libs/notification/NotificationMessage.java create mode 100644 src/main/java/com/r35157/libs/solana/valuetypes/WellKnownCurrencyTypes.java create mode 100644 src/main/java/com/r35157/libs/valuetypes/basic/CurrencyType.java create mode 100644 src/main/java/com/r35157/libs/valuetypes/basic/SemanticVersion.java create mode 100644 src/main/java/com/r35157/libs/valuetypes/basic/SmtpConfiguration.java create mode 100644 src/main/java/com/r35157/libs/valuetypes/basic/TradingPair.java create mode 100644 src/main/java/com/r35157/nenjim/hubd/journal/JournalManager.java create mode 100644 src/main/java/com/r35157/nenjim/hubd/module/Module.java create mode 100644 src/main/tjava/com/r35157/libs/codec/Base58Codec.tjava create mode 100644 src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPosition.tjava create mode 100644 src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPositionDirection.tjava create mode 100644 src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsService.tjava create mode 100644 src/main/tjava/com/r35157/libs/solana/SolanaBlockChain.tjava create mode 100644 src/main/tjava/com/r35157/libs/solana/SolanaProgramAccountMemcmpFilter.tjava create mode 100644 src/main/tjava/com/r35157/libs/valuetypes/basic/MoneyPrice.tjava diff --git a/build.gradle.kts b/build.gradle.kts index c0b0f7c..ade0647 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -44,7 +44,6 @@ dependencies { runtimeOnly("org.apache.logging.log4j:log4j-core: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.fazecast:jSerialComm:2.11.4") implementation("com.google.code.gson:gson:2.14.0") diff --git a/src/main/java/com/r35157/libs/math/UtilsDouble.java b/src/main/java/com/r35157/libs/math/UtilsDouble.java new file mode 100644 index 0000000..dcc3d05 --- /dev/null +++ b/src/main/java/com/r35157/libs/math/UtilsDouble.java @@ -0,0 +1,7 @@ +package com.r35157.libs.math; + +import java.math.BigDecimal; + +public interface UtilsDouble { + double erf(BigDecimal x); +} diff --git a/src/main/java/com/r35157/libs/notification/AddressedNotifier.java b/src/main/java/com/r35157/libs/notification/AddressedNotifier.java new file mode 100644 index 0000000..05ff801 --- /dev/null +++ b/src/main/java/com/r35157/libs/notification/AddressedNotifier.java @@ -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 bind(D destination) { + return message -> push(destination, message); + } +} \ No newline at end of file diff --git a/src/main/java/com/r35157/libs/notification/BoundNotifier.java b/src/main/java/com/r35157/libs/notification/BoundNotifier.java new file mode 100644 index 0000000..c2f2e0e --- /dev/null +++ b/src/main/java/com/r35157/libs/notification/BoundNotifier.java @@ -0,0 +1,7 @@ +package com.r35157.libs.notification; + +import java.io.IOException; + +public interface BoundNotifier { + void push(M message) throws IOException; +} \ No newline at end of file diff --git a/src/main/java/com/r35157/libs/notification/NotificationDestination.java b/src/main/java/com/r35157/libs/notification/NotificationDestination.java new file mode 100644 index 0000000..ec80aaa --- /dev/null +++ b/src/main/java/com/r35157/libs/notification/NotificationDestination.java @@ -0,0 +1,3 @@ +package com.r35157.libs.notification; + +public interface NotificationDestination {} diff --git a/src/main/java/com/r35157/libs/notification/NotificationMessage.java b/src/main/java/com/r35157/libs/notification/NotificationMessage.java new file mode 100644 index 0000000..3778b62 --- /dev/null +++ b/src/main/java/com/r35157/libs/notification/NotificationMessage.java @@ -0,0 +1,4 @@ +package com.r35157.libs.notification; + +public interface NotificationMessage { +} diff --git a/src/main/java/com/r35157/libs/solana/valuetypes/WellKnownCurrencyTypes.java b/src/main/java/com/r35157/libs/solana/valuetypes/WellKnownCurrencyTypes.java new file mode 100644 index 0000000..7c88278 --- /dev/null +++ b/src/main/java/com/r35157/libs/solana/valuetypes/WellKnownCurrencyTypes.java @@ -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. + * + *

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.

+ */ +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; +} \ No newline at end of file diff --git a/src/main/java/com/r35157/libs/valuetypes/basic/CurrencyType.java b/src/main/java/com/r35157/libs/valuetypes/basic/CurrencyType.java new file mode 100644 index 0000000..dd51822 --- /dev/null +++ b/src/main/java/com/r35157/libs/valuetypes/basic/CurrencyType.java @@ -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; + } +} diff --git a/src/main/java/com/r35157/libs/valuetypes/basic/SemanticVersion.java b/src/main/java/com/r35157/libs/valuetypes/basic/SemanticVersion.java new file mode 100644 index 0000000..d8cc612 --- /dev/null +++ b/src/main/java/com/r35157/libs/valuetypes/basic/SemanticVersion.java @@ -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+))?)?$"); +} diff --git a/src/main/java/com/r35157/libs/valuetypes/basic/SmtpConfiguration.java b/src/main/java/com/r35157/libs/valuetypes/basic/SmtpConfiguration.java new file mode 100644 index 0000000..b577cd1 --- /dev/null +++ b/src/main/java/com/r35157/libs/valuetypes/basic/SmtpConfiguration.java @@ -0,0 +1,7 @@ +package com.r35157.libs.valuetypes.basic; + +public record SmtpConfiguration( + NetworkEndPoint networkEndPoint, + Credentials credentials +) { +} \ No newline at end of file diff --git a/src/main/java/com/r35157/libs/valuetypes/basic/TradingPair.java b/src/main/java/com/r35157/libs/valuetypes/basic/TradingPair.java new file mode 100644 index 0000000..c028ff6 --- /dev/null +++ b/src/main/java/com/r35157/libs/valuetypes/basic/TradingPair.java @@ -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. +) { } diff --git a/src/main/java/com/r35157/nenjim/hubd/journal/JournalManager.java b/src/main/java/com/r35157/nenjim/hubd/journal/JournalManager.java new file mode 100644 index 0000000..761cf0f --- /dev/null +++ b/src/main/java/com/r35157/nenjim/hubd/journal/JournalManager.java @@ -0,0 +1,5 @@ +package com.r35157.nenjim.hubd.journal; + +public interface JournalManager { + Journal getJournal(String moduleName); +} diff --git a/src/main/java/com/r35157/nenjim/hubd/module/Module.java b/src/main/java/com/r35157/nenjim/hubd/module/Module.java new file mode 100644 index 0000000..ec7899f --- /dev/null +++ b/src/main/java/com/r35157/nenjim/hubd/module/Module.java @@ -0,0 +1,4 @@ +package com.r35157.nenjim.hubd.module; + +public record Module() { +} diff --git a/src/main/tjava/com/r35157/libs/codec/Base58Codec.tjava b/src/main/tjava/com/r35157/libs/codec/Base58Codec.tjava new file mode 100644 index 0000000..e3bc6ab --- /dev/null +++ b/src/main/tjava/com/r35157/libs/codec/Base58Codec.tjava @@ -0,0 +1,5 @@ +package com.r35157.libs.codec; + +public interface Base58Codec { + String encode(byte[] input); +} diff --git a/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPosition.tjava b/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPosition.tjava new file mode 100644 index 0000000..1f59275 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPosition.tjava @@ -0,0 +1,27 @@ +package com.r35157.libs.jupiter.perps; + +/** + * Represents a Jupiter Perps position. + * + *

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.

+ * + * @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 +) { +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPositionDirection.tjava b/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPositionDirection.tjava new file mode 100644 index 0000000..05c4066 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsPositionDirection.tjava @@ -0,0 +1,9 @@ +package com.r35157.libs.jupiter.perps; + +/** + * Direction of a Jupiter Perps position. + */ +public enum JupiterPerpsPositionDirection { + LONG, + SHORT +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsService.tjava b/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsService.tjava new file mode 100644 index 0000000..c513c2d --- /dev/null +++ b/src/main/tjava/com/r35157/libs/jupiter/perps/JupiterPerpsService.tjava @@ -0,0 +1,45 @@ +package com.r35157.libs.jupiter.perps; + +import java.io.IOException; +import java.util.Set; + +/** + * Service for reading Jupiter Perps data. + * + *

This service is read-only. It does not open, close, modify, or sign transactions + * for Jupiter Perpetual Contracts.

+ * + *

NOTICE: The first supported operation is reading a known Jupiter Perps position account + * and returning its decoded position data.

+ */ +public interface JupiterPerpsService { + /** + * Reads a Jupiter Perps position from a known position account. + * + *

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.

+ * + * @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. + * + *

This method returns decoded Jupiter Perps position objects. It does not return + * raw Solana accounts or account ids.

+ * + * @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 getOpenPositions(ΩSolanaWalletIdΩ owner) + throws IOException, InterruptedException; +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/raydium/Raydium.tjava b/src/main/tjava/com/r35157/libs/raydium/Raydium.tjava index 9e56d6d..3f4fd36 100644 --- a/src/main/tjava/com/r35157/libs/raydium/Raydium.tjava +++ b/src/main/tjava/com/r35157/libs/raydium/Raydium.tjava @@ -1,11 +1,8 @@ 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 java.io.IOException; -import java.math.BigDecimal; import java.util.Set; public interface Raydium { @@ -16,11 +13,11 @@ public interface Raydium { * to any Raydium liquidity pool supported by the implementation.

* * @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 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. @@ -184,7 +181,7 @@ public interface Raydium { * @param decimalPlaces the number decimal places in the resulting price currency * @return the price range represented by the concentrated liquidity position */ - Range calculateConcentratedPositionPriceRange( + Range<ΩPriceΩ> calculateConcentratedPositionPriceRange( RaydiumConcentratedPositionState positionState, RaydiumConcentratedPoolInfo poolInfo, int decimalPlaces diff --git a/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPoolInfo.tjava b/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPoolInfo.tjava index 4f8683f..ce67d0e 100644 --- a/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPoolInfo.tjava +++ b/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPoolInfo.tjava @@ -1,7 +1,5 @@ package com.r35157.libs.raydium; -import java.math.BigDecimal; - /** * Represents basic information about a Raydium concentrated liquidity pool. * diff --git a/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPoolState.tjava b/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPoolState.tjava index 97ebca3..bc39f40 100644 --- a/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPoolState.tjava +++ b/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPoolState.tjava @@ -1,7 +1,5 @@ package com.r35157.libs.raydium; -import java.math.BigInteger; - /** * Represents raw on-chain state for a Raydium concentrated liquidity pool. * diff --git a/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPositionState.tjava b/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPositionState.tjava index ccc5496..f343148 100644 --- a/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPositionState.tjava +++ b/src/main/tjava/com/r35157/libs/raydium/RaydiumConcentratedPositionState.tjava @@ -1,7 +1,5 @@ package com.r35157.libs.raydium; -import java.math.BigInteger; - public record RaydiumConcentratedPositionState( ΩRaydiumLiquidityPoolPositionNftIdΩ nftId, ΩRaydiumLiquidityPoolConcentratedIdΩ poolId, diff --git a/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolPositionStandard.tjava b/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolPositionStandard.tjava index 2991e8f..0343ce3 100644 --- a/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolPositionStandard.tjava +++ b/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolPositionStandard.tjava @@ -1,7 +1,5 @@ package com.r35157.libs.raydium; -import java.math.BigDecimal; - /** * Represents a standard Raydium liquidity pool position. * diff --git a/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolPrice.tjava b/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolPrice.tjava index e44309e..24bd54d 100644 --- a/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolPrice.tjava +++ b/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolPrice.tjava @@ -1,18 +1,18 @@ 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. * - *

The 'poolId' identifies the Raydium liquidity pool for which the current token price applies. - * The 'price' represents the price value returned or calculated for that pool.

+ *

The pool id identifies the Raydium liquidity pool for which the price applies. + * The amount contains the price value returned or calculated for that pool.

* * @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( ΩRaydiumLiquidityPoolIdΩ poolId, - AssetPrice price + MoneyAmount amount ) { } \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolTokenAmounts.tjava b/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolTokenAmounts.tjava index c229b1e..8d9e8ce 100644 --- a/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolTokenAmounts.tjava +++ b/src/main/tjava/com/r35157/libs/raydium/RaydiumLiquidityPoolTokenAmounts.tjava @@ -1,7 +1,5 @@ package com.r35157.libs.raydium; -import java.math.BigDecimal; - /** * Represents token amounts for a Raydium liquidity pool or liquidity position. * diff --git a/src/main/tjava/com/r35157/libs/solana/SPLTokenHolding.tjava b/src/main/tjava/com/r35157/libs/solana/SPLTokenHolding.tjava index 9a082ee..e87631b 100644 --- a/src/main/tjava/com/r35157/libs/solana/SPLTokenHolding.tjava +++ b/src/main/tjava/com/r35157/libs/solana/SPLTokenHolding.tjava @@ -1,7 +1,5 @@ package com.r35157.libs.solana; -import java.math.BigDecimal; - /** * Represents an SPL token holding owned by a Solana address. * diff --git a/src/main/tjava/com/r35157/libs/solana/SPLTokenSupply.tjava b/src/main/tjava/com/r35157/libs/solana/SPLTokenSupply.tjava index f858e7d..054bc0a 100644 --- a/src/main/tjava/com/r35157/libs/solana/SPLTokenSupply.tjava +++ b/src/main/tjava/com/r35157/libs/solana/SPLTokenSupply.tjava @@ -1,7 +1,5 @@ package com.r35157.libs.solana; -import java.math.BigDecimal; - /** * Represents the total supply of an SPL token mint. * diff --git a/src/main/tjava/com/r35157/libs/solana/SolanaBlockChain.tjava b/src/main/tjava/com/r35157/libs/solana/SolanaBlockChain.tjava new file mode 100644 index 0000000..2125338 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/SolanaBlockChain.tjava @@ -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. + * + *

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.

+ * + *

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.

+ */ +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. + * + *

Lamports are the smallest unit of native SOL.

+ * + * @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. + * + *

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.

+ * + * @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. + * + *

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.

+ * + * // 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. + * + *

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.

+ * + * @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 seeds + ); + + /** + * Fetches account information for a Solana account address. + * + *

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.

+ * + * @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. + * + *

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.

+ * + * @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. + * + *

The supplied token program identifies which SPL token program owns the mint, + * for example the original SPL Token Program or the Token-2022 Program.

+ * + * @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. + * + *

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.

+ * + *

The initial supported filter type is {@link SolanaProgramAccountMemcmpFilter}, which + * matches bytes at a specific offset in the account data.

+ * + * @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 getProgramAccounts( + ΩSolanaProgramIdΩ programId, + Set filters + ) throws IOException, InterruptedException; +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/solana/SolanaProgramAccountMemcmpFilter.tjava b/src/main/tjava/com/r35157/libs/solana/SolanaProgramAccountMemcmpFilter.tjava new file mode 100644 index 0000000..eb523be --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/SolanaProgramAccountMemcmpFilter.tjava @@ -0,0 +1,17 @@ +package com.r35157.libs.solana; + +/** + * Filter used when fetching accounts owned by a Solana program. + * + *

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.

+ * + * @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 +) { +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/valuetypes/basic/MoneyAmount.tjava b/src/main/tjava/com/r35157/libs/valuetypes/basic/MoneyAmount.tjava index 4685432..d3d26ea 100644 --- a/src/main/tjava/com/r35157/libs/valuetypes/basic/MoneyAmount.tjava +++ b/src/main/tjava/com/r35157/libs/valuetypes/basic/MoneyAmount.tjava @@ -2,8 +2,6 @@ package com.r35157.libs.valuetypes.basic; import org.jetbrains.annotations.NotNull; -import java.math.BigDecimal; - public record MoneyAmount( ΩAmountΩ amount, CurrencyType currencyType diff --git a/src/main/tjava/com/r35157/libs/valuetypes/basic/MoneyPrice.tjava b/src/main/tjava/com/r35157/libs/valuetypes/basic/MoneyPrice.tjava new file mode 100644 index 0000000..bf9e663 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/valuetypes/basic/MoneyPrice.tjava @@ -0,0 +1,6 @@ +package com.r35157.libs.valuetypes.basic; + +public record MoneyPrice( + ΩPriceΩ price, + CurrencyType currencyType +) { }