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/tjava/com/r35157/libs/solana/SPLTokenHolding.tjava b/src/main/tjava/com/r35157/libs/solana/SPLTokenHolding.tjava new file mode 100644 index 0000000..9a082ee --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/SPLTokenHolding.tjava @@ -0,0 +1,30 @@ +package com.r35157.libs.solana; + +import java.math.BigDecimal; + +/** + * Represents an SPL token holding owned by a Solana address. + * + *

The holding describes one SPL token account and the token mint it belongs to. + * The amount is represented both as a UI amount and as the raw on-chain amount, + * together with the number of decimals used by the token mint.

+ * + *

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

+ * + * @param tokenAccount the SPL token account holding the token balance + * @param mintAddress the SPL mint address of the token + * @param uiAmount the human-readable token amount + * @param rawAmount the raw on-chain token amount before decimal conversion + * @param decimals the number of decimals used by the token mint + * @param programId the SPL token program id that owns the token account + */ +public record SPLTokenHolding( + ΩSPLTokenAccountΩ tokenAccount, + ΩSPLMintAddressΩ mintAddress, + ΩAmountΩ uiAmount, + ΩRawAmountΩ rawAmount, + ΩamountDecimalsΩ decimals, + ΩSPLProgramIdΩ programId +) { +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/solana/SPLTokenSupply.tjava b/src/main/tjava/com/r35157/libs/solana/SPLTokenSupply.tjava new file mode 100644 index 0000000..f858e7d --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/SPLTokenSupply.tjava @@ -0,0 +1,24 @@ +package com.r35157.libs.solana; + +import java.math.BigDecimal; + +/** + * Represents the total supply of an SPL token mint. + * + *

The supply is represented both as a UI amount and as the raw on-chain amount, + * together with the number of decimals used by the token mint.

+ * + * @param mintAddress the SPL mint address whose supply was fetched + * @param uiAmount the human-readable token supply + * @param rawAmount the raw on-chain token supply before decimal conversion + * @param decimals the number of decimals used by the token mint + * @param programId the SPL token program id for the mint + */ +public record SPLTokenSupply( + ΩSPLMintAddressΩ mintAddress, + ΩAmountΩ uiAmount, + ΩRawAmountΩ rawAmount, + ΩamountDecimalsΩ decimals, + ΩSPLProgramIdΩ programId +) { +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/solana/SolanaAccountInfo.tjava b/src/main/tjava/com/r35157/libs/solana/SolanaAccountInfo.tjava new file mode 100644 index 0000000..ad51767 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/SolanaAccountInfo.tjava @@ -0,0 +1,24 @@ +package com.r35157.libs.solana; + +/** + * Represents basic information about a Solana account. + * + *

The address identifies the account that was queried. The owner identifies + * the Solana program that owns the account. The account data is represented as + * a Base64 encoded string, matching the encoding returned by the Solana RPC + * account-info response.

+ * + *

For normal wallet/system accounts, the data may be empty. Program-owned + * accounts, token accounts, mint accounts and application-specific state + * accounts may contain encoded account data.

+ * + * @param address the Solana account address + * @param owner the Solana program id that owns the account + * @param dataBase64 the account data encoded as Base64, or an empty string if the account has no data + */ +public record SolanaAccountInfo( + ΩSolanaAddressΩ address, + ΩSolanaProgramIdΩ owner, + String dataBase64 +) { +} \ No newline at end of file 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..4e22891 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/SolanaBlockChain.tjava @@ -0,0 +1,146 @@ +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. + * + *

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; +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/solana/SolanaConstants.tjava b/src/main/tjava/com/r35157/libs/solana/SolanaConstants.tjava new file mode 100644 index 0000000..4bedf26 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/SolanaConstants.tjava @@ -0,0 +1,19 @@ +package com.r35157.libs.solana; + +/** + * Contains Solana-related constants used by the Solana integration. + * + *

This class is intended for shared constants that are part of the public + * Solana API surface or are useful across Solana-related modules.

+ */ +public class SolanaConstants { + /** + * The default Solana JSON-RPC endpoint used by the integration. + */ + public static final String RPC_URL = "https://api.mainnet.solana.com"; + + /** + * The SPL mint address for Syrup USDC on Solana. + */ + public static final String SPL_TOKEN_SYRUPUSDC = "AvZZF1YaZDziPY2RCK4oJrRVrbN3mTD9NL24hPeaZeUj"; +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/solana/SolanaProgramAddressSeed.tjava b/src/main/tjava/com/r35157/libs/solana/SolanaProgramAddressSeed.tjava new file mode 100644 index 0000000..6f15eb1 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/SolanaProgramAddressSeed.tjava @@ -0,0 +1,51 @@ +package com.r35157.libs.solana; + +/** + * Represents a seed used when deriving a Solana program derived address. + * + *

A seed has a kind and a textual value. The kind tells the Solana + * implementation how the value should be converted to bytes before it is used + * in program address derivation.

+ * + *

This keeps callers from having to perform encoding or decoding themselves. + * For example, a caller can provide a UTF-8 seed or a Solana address seed, and + * the implementation decides how each seed is converted to the byte format + * required by Solana.

+ * + * @param kind the kind of seed + * @param value the textual seed value + */ +public record SolanaProgramAddressSeed( + SolanaProgramAddressSeedKind kind, + String value +) { + /** + * Creates a UTF-8 seed. + * + * @param value the text value to encode as UTF-8 + * @return a program address seed representing the supplied UTF-8 text + */ + public static SolanaProgramAddressSeed utf8(String value) { + return new SolanaProgramAddressSeed( + SolanaProgramAddressSeedKind.UTF8, + value + ); + } + + /** + * Creates a Solana address seed. + * + *

The supplied address is represented textually here. The implementation + * deriving the program address is responsible for decoding the address into + * its raw Solana address bytes.

+ * + * @param address the Solana address to use as a seed + * @return a program address seed representing the supplied Solana address + */ + public static SolanaProgramAddressSeed solanaAddress(ΩSolanaAddressΩ address) { + return new SolanaProgramAddressSeed( + SolanaProgramAddressSeedKind.SOLANA_ADDRESS, + address + ); + } +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/solana/SolanaProgramAddressSeedKind.tjava b/src/main/tjava/com/r35157/libs/solana/SolanaProgramAddressSeedKind.tjava new file mode 100644 index 0000000..a544850 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/SolanaProgramAddressSeedKind.tjava @@ -0,0 +1,21 @@ +package com.r35157.libs.solana; + +/** + * Defines how a Solana program address seed should be converted to bytes. + * + *

Program derived addresses are calculated from byte seeds. This enum allows + * callers to describe the meaning of a seed without doing the byte conversion + * themselves.

+ */ +public enum SolanaProgramAddressSeedKind { + /** + * A seed that should be encoded as UTF-8 text. + */ + UTF8, + + /** + * A seed that represents a Solana address and should be decoded from its + * textual Solana address representation to raw address bytes. + */ + SOLANA_ADDRESS +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/solana/valuetypes/SolanaProgramDerivedAddress.tjava b/src/main/tjava/com/r35157/libs/solana/valuetypes/SolanaProgramDerivedAddress.tjava new file mode 100644 index 0000000..f56ef8c --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/valuetypes/SolanaProgramDerivedAddress.tjava @@ -0,0 +1,17 @@ +package com.r35157.libs.solana.valuetypes; + +/** + * Represents a Solana program derived address and its bump value. + * + *

A program derived address is a Solana address generated deterministically + * from a program id and a set of seeds. The bump value is the extra seed value + * used to find a valid program derived address for those inputs.

+ * + * @param address the derived Solana address + * @param bump the bump value used when deriving the address + */ +public record SolanaProgramDerivedAddress( + ΩSolanaAddressΩ address, + int bump +) { +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/solana/valuetypes/economic/SolanaSPLToken.tjava b/src/main/tjava/com/r35157/libs/solana/valuetypes/economic/SolanaSPLToken.tjava new file mode 100644 index 0000000..1461b30 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/valuetypes/economic/SolanaSPLToken.tjava @@ -0,0 +1,21 @@ +package com.r35157.libs.solana.valuetypes.economic; + +import com.r35157.libs.valuetypes.basic.CurrencyType; + +/** + * Represents an SPL token known to the Solana integration. + * + *

The currency type describes the economic identity of the token, while the + * mint address identifies the SPL token mint on Solana. The token address is the + * Solana address associated with the token in this model.

+ * + * @param currencyType the currency type represented by this SPL token + * @param mintAddress the SPL mint address of the token + * @param tokenAddress the Solana address associated with the token + */ +public record SolanaSPLToken ( + CurrencyType currencyType, + ΩSPLMintAddressΩ mintAddress, + ΩSolanaAddressΩ tokenAddress +) { +} \ No newline at end of file diff --git a/src/main/tjava/com/r35157/libs/solana/valuetypes/economic/SolanaSPLTokenProgram.tjava b/src/main/tjava/com/r35157/libs/solana/valuetypes/economic/SolanaSPLTokenProgram.tjava new file mode 100644 index 0000000..9171c50 --- /dev/null +++ b/src/main/tjava/com/r35157/libs/solana/valuetypes/economic/SolanaSPLTokenProgram.tjava @@ -0,0 +1,44 @@ +package com.r35157.libs.solana.valuetypes.economic; + +/** + * Represents a Solana SPL token program supported by this integration. + * + *

Solana has more than one token program. The original SPL Token Program is + * used by many existing tokens, while the Token-2022 Program supports newer token + * functionality and extensions.

+ * + *

The program address is used when querying token accounts owned by a wallet, + * for example when discovering SPL token holdings or NFT-like token holdings + * under a specific token program.

+ */ +public enum SolanaSPLTokenProgram { + /** + * The original Solana SPL Token Program. + */ + SPL_TOKEN_PROGRAM("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), + + /** + * The Solana Token-2022 Program. + */ + TOKEN_2022_PROGRAM("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"); + + /** + * Creates a Solana SPL token program entry. + * + * @param address the Solana program address for the token program + */ + SolanaSPLTokenProgram(ΩSPLProgramIdΩ address) { + this.address = address; + } + + /** + * Returns the Solana program address for this token program. + * + * @return the SPL token program address + */ + public ΩSPLProgramIdΩ getAddress() { + return address; + } + + private final ΩSPLProgramIdΩ address; +} \ No newline at end of file