Comprehensive Java implementations for popular Solana programs π
Built with SolanaJ for seamless Solana blockchain integration
π― Complete Program Coverage - Support for all major Solana DeFi protocols
β‘ High Performance - Optimized for low latency and high throughput
π οΈ Production Ready - Battle-tested in production environments
π Well Documented - Comprehensive examples and javadocs
π Actively Maintained - Regular updates with latest program changes
π§ͺ Fully Tested - Extensive test coverage with real mainnet data
Add the full library to your pom.xml:
<dependency>
<groupId>com.mmorrell</groupId>
<artifactId>solanaj-programs</artifactId>
<version>1.34.0</version>
</dependency>Or include individual modules:
<!-- Phoenix DEX -->
<dependency>
<groupId>com.mmorrell</groupId>
<artifactId>phoenix</artifactId>
<version>1.34.0</version>
</dependency>
<!-- OpenBook v2 -->
<dependency>
<groupId>com.mmorrell</groupId>
<artifactId>openbook</artifactId>
<version>1.34.0</version>
</dependency>
<!-- Bonfida Name Service -->
<dependency>
<groupId>com.mmorrell</groupId>
<artifactId>bonfida</artifactId>
<version>1.34.0</version>
</dependency>
<!-- Pyth Oracle -->
<dependency>
<groupId>com.mmorrell</groupId>
<artifactId>pyth</artifactId>
<version>1.34.0</version>
</dependency>
<!-- Metaplex -->
<dependency>
<groupId>com.mmorrell</groupId>
<artifactId>metaplex</artifactId>
<version>1.34.0</version>
</dependency>
<!-- Jupiter -->
<dependency>
<groupId>com.mmorrell</groupId>
<artifactId>jupiter</artifactId>
<version>1.34.0</version>
</dependency>
<!-- Mango -->
<dependency>
<groupId>com.mmorrell</groupId>
<artifactId>mango</artifactId>
<version>1.34.0</version>
</dependency>
<!-- Serum -->
<dependency>
<groupId>com.mmorrell</groupId>
<artifactId>serum</artifactId>
<version>1.34.0</version>
</dependency>Add to your build.gradle:
dependencies {
// Full library
implementation 'com.mmorrell:solanaj-programs:1.34.0'
// Or individual modules
implementation 'com.mmorrell:phoenix:1.34.0'
implementation 'com.mmorrell:openbook:1.34.0'
implementation 'com.mmorrell:bonfida:1.34.0'
implementation 'com.mmorrell:pyth:1.34.0'
implementation 'com.mmorrell:metaplex:1.34.0'
implementation 'com.mmorrell:jupiter:1.34.0'
implementation 'com.mmorrell:mango:1.34.0'
implementation 'com.mmorrell:serum:1.34.0'
}Or with Gradle Kotlin DSL (build.gradle.kts):
dependencies {
// Full library
implementation("com.mmorrell:solanaj-programs:1.34.0")
// Or individual modules
implementation("com.mmorrell:phoenix:1.34.0")
implementation("com.mmorrell:openbook:1.34.0")
implementation("com.mmorrell:bonfida:1.34.0")
implementation("com.mmorrell:pyth:1.34.0")
implementation("com.mmorrell:metaplex:1.34.0")
implementation("com.mmorrell:jupiter:1.34.0")
implementation("com.mmorrell:mango:1.34.0")
implementation("com.mmorrell:serum:1.34.0")
}| Program | Description | Module |
|---|---|---|
| π₯ Phoenix | High-performance DEX with CLOB | phoenix |
| π OpenBook v2 | Community-driven fork of Serum v4 | openbook |
| β‘ Serum v3 | Original Serum DEX | serum |
| π₯ Mango | Decentralized perpetuals and margin trading | mango |
| π Pyth | High-fidelity oracle network | pyth |
| π Jupiter | Liquidity aggregator | jupiter |
| π¦ Bonfida | Solana Name Service (.sol domains) | bonfida |
| π¨ Metaplex | NFT metadata standard | metaplex |
| πͺ Magic Eden | NFT marketplace integration | magiceden |
Bonfida provides the Solana Name Service (SNS), enabling human-readable .sol domains and Twitter handle resolution.
import org.p2p.solanaj.core.PublicKey;
import com.mmorrell.bonfida.manager.NamingManager;
import org.p2p.solanaj.rpc.RpcClient;
RpcClient client = new RpcClient("https://api.mainnet-beta.solana.com");
NamingManager namingManager = new NamingManager(client);
PublicKey skynetPubkey = new PublicKey("GUfCR9mK6azb9vcpsxgXyj7XRPAKJd4KMHTTVvtncGgp");
String twitterHandle = namingManager.getTwitterHandle(skynetPubkey);
System.out.println("Twitter Handle: @" + twitterHandle);
// Output: Twitter Handle: @skynetcapPublicKey publicKey = namingManager.getPublicKeyBySolDomain("skynet");
System.out.println("skynet.sol = " + publicKey.toBase58());
// Output: skynet.sol = GUfCR9mK6azb9vcpsxgXyj7XRPAKJd4KMHTTVvtncGgpPublicKey ownerPubkey = new PublicKey("GUfCR9mK6azb9vcpsxgXyj7XRPAKJd4KMHTTVvtncGgp");
Optional<String> domainName = namingManager.getDomainNameByPubkey(ownerPubkey);
domainName.ifPresent(domain -> {
System.out.println("Domain: " + domain + ".sol");
});
// Output: Domain: skynet.solList<String> domains = Arrays.asList("bonfida", "skynet", "solanafm");
Map<String, PublicKey> resolved = new HashMap<>();
for (String domain : domains) {
try {
PublicKey pubkey = namingManager.getPublicKeyBySolDomain(domain);
resolved.put(domain, pubkey);
System.out.println(domain + ".sol -> " + pubkey.toBase58());
} catch (Exception e) {
System.err.println("Failed to resolve: " + domain);
}
}Metaplex provides the standard for NFT metadata on Solana.
import org.p2p.solanaj.core.PublicKey;
import com.mmorrell.metaplex.manager.MetaplexManager;
import com.mmorrell.metaplex.model.Metadata;
RpcClient client = new RpcClient("https://api.mainnet-beta.solana.com");
MetaplexManager metaplexManager = new MetaplexManager(client);
PublicKey tokenMint = new PublicKey("3uejHm24sWmniGA5m4j4S1DVuGqzYBR5DJpevND4mivq");
Optional<Metadata> metadata = metaplexManager.getTokenMetadata(tokenMint);
metadata.ifPresent(meta -> {
System.out.println("Name: " + meta.getName());
System.out.println("Symbol: " + meta.getSymbol());
System.out.println("URI: " + meta.getUri());
System.out.println("Creators: " + meta.getCreators());
});List<PublicKey> mints = Arrays.asList(
new PublicKey("TokenMint1..."),
new PublicKey("TokenMint2..."),
new PublicKey("TokenMint3...")
);
Map<PublicKey, Metadata> metadataMap = new HashMap<>();
for (PublicKey mint : mints) {
metaplexManager.getTokenMetadata(mint).ifPresent(meta -> {
metadataMap.put(mint, meta);
System.out.println(mint.toBase58() + ": " + meta.getSymbol());
});
}PublicKey nftMint = new PublicKey("YourNFTMint...");
Optional<Metadata> metadata = metaplexManager.getTokenMetadata(nftMint);
metadata.ifPresent(meta -> {
if (meta.getCollection() != null) {
System.out.println("Collection: " + meta.getCollection().getKey().toBase58());
System.out.println("Verified: " + meta.getCollection().isVerified());
}
});OpenBook v2 is the community-driven successor to Serum, providing a fully on-chain central limit order book (CLOB).
import com.mmorrell.openbook.manager.OpenBookManager;
import com.mmorrell.openbook.model.OpenBookMarket;
import org.p2p.solanaj.rpc.RpcClient;
RpcClient client = new RpcClient("https://api.mainnet-beta.solana.com");
OpenBookManager openBookManager = new OpenBookManager(client);
// SOL/USDC market
PublicKey marketId = PublicKey.valueOf("8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6");
Optional<OpenBookMarket> marketOpt = openBookManager.getMarket(marketId, false, true);
marketOpt.ifPresent(market -> {
System.out.println("=== SOL/USDC Market ===");
// Best bid/ask
if (!market.getBidOrders().isEmpty()) {
var bestBid = market.getBidOrders().get(0);
System.out.println("Best Bid: $" + bestBid.getPrice() + " x " + bestBid.getSize());
}
if (!market.getAskOrders().isEmpty()) {
var bestAsk = market.getAskOrders().get(0);
System.out.println("Best Ask: $" + bestAsk.getPrice() + " x " + bestAsk.getSize());
}
// All bids
System.out.println("\nπ Bids:");
market.getBidOrders().forEach(order -> {
System.out.printf(" $%.2f x %.3f from %s\n",
order.getPrice(),
order.getSize(),
order.getTrader().toBase58().substring(0, 8) + "...");
});
// All asks
System.out.println("\nπ Asks:");
market.getAskOrders().forEach(order -> {
System.out.printf(" $%.2f x %.3f from %s\n",
order.getPrice(),
order.getSize(),
order.getTrader().toBase58().substring(0, 8) + "...");
});
});List<PublicKey> markets = openBookManager.getOpenBookMarkets();
System.out.println("Total OpenBook Markets: " + markets.size());
markets.forEach(marketPubkey -> {
System.out.println("Market: " + marketPubkey.toBase58());
});import com.mmorrell.openbook.model.OpenBookEventHeap;
PublicKey marketId = PublicKey.valueOf("8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6");
Optional<OpenBookEventHeap> eventHeap = openBookManager.getEventHeap(marketId);
eventHeap.ifPresent(heap -> {
System.out.println("=== Market Events ===");
heap.getOutEvents().forEach(event -> {
System.out.println("Event: " + event.toString());
});
heap.getFillEvents().forEach(fill -> {
System.out.printf("Fill: Maker=%s, Taker=%s, Price=%.2f, Size=%.4f\n",
fill.getMaker().toBase58().substring(0, 8),
fill.getTaker().toBase58().substring(0, 8),
fill.getPrice(),
fill.getQuantity()
);
});
});import org.p2p.solanaj.core.Account;
PublicKey marketId = PublicKey.valueOf("8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6");
Account crankerAccount = Account.fromJson(readKeyFile());
Optional<String> txId = openBookManager.consumeEvents(
crankerAccount,
marketId,
10 // Max events to consume
);
txId.ifPresentOrElse(
tx -> System.out.println("β
Cranked events: " + tx),
() -> System.out.println("βΉοΈ No events to consume")
);Optional<OpenBookMarket> marketOpt = openBookManager.getMarket(marketId, false, true);
marketOpt.ifPresent(market -> {
if (!market.getBidOrders().isEmpty() && !market.getAskOrders().isEmpty()) {
double bestBid = market.getBidOrders().get(0).getPrice();
double bestAsk = market.getAskOrders().get(0).getPrice();
double spread = bestAsk - bestBid;
double spreadBps = (spread / bestBid) * 10000;
System.out.printf("Spread: $%.4f (%.2f bps)\n", spread, spreadBps);
}
});Phoenix is a high-performance DEX with ultra-low latency and advanced order types.
import com.mmorrell.phoenix.manager.PhoenixManager;
import com.mmorrell.phoenix.model.PhoenixMarket;
import org.p2p.solanaj.rpc.Cluster;
RpcClient client = new RpcClient(Cluster.MAINNET);
PhoenixManager phoenixManager = new PhoenixManager(client);
MetaplexManager metaplexManager = new MetaplexManager(client);
// SOL/USDC Phoenix market
PublicKey solUsdcMarket = new PublicKey("4DoNfFBfF7UokCC2FQzriy7yHK6DY6NVdYpuekQ5pRgg");
Optional<PhoenixMarket> marketOpt = phoenixManager.getMarket(solUsdcMarket, false);
marketOpt.ifPresent(market -> {
var header = market.getPhoenixMarketHeader();
// Get token metadata
metaplexManager.getTokenMetadata(header.getBaseMintKey())
.ifPresent(meta -> System.out.println("Base: " + meta.getSymbol()));
metaplexManager.getTokenMetadata(header.getQuoteMintKey())
.ifPresent(meta -> System.out.println("Quote: " + meta.getSymbol()));
System.out.println("\nπ Order Book:");
// Top 5 bids
System.out.println("\nπ’ Best Bids:");
market.getBidListNormalized().stream().limit(5).forEach(order -> {
System.out.printf(" %.4f @ $%.2f (Trader: %s)\n",
order.getSize(),
order.getPrice(),
order.getTrader().toBase58().substring(0, 8));
});
// Top 5 asks
System.out.println("\nπ΄ Best Asks:");
market.getAskListNormalized().stream().limit(5).forEach(order -> {
System.out.printf(" %.4f @ $%.2f (Trader: %s)\n",
order.getSize(),
order.getPrice(),
order.getTrader().toBase58().substring(0, 8));
});
});List<PhoenixMarket> markets = phoenixManager.getPhoenixMarkets();
System.out.println("Total Phoenix Markets: " + markets.size());
markets.forEach(market -> {
System.out.println("\n=== Market: " + market.getMarketId().toBase58() + " ===");
// Get best bid/ask
market.getBestBid().ifPresent(bid ->
System.out.printf("Best Bid: $%.4f\n", bid.getFirst().getPrice())
);
market.getBestAsk().ifPresent(ask ->
System.out.printf("Best Ask: $%.4f\n", ask.getFirst().getPrice())
);
// Calculate depth
double bidDepth = market.getBidListNormalized().stream()
.mapToDouble(order -> order.getSize() * order.getPrice())
.sum();
double askDepth = market.getAskListNormalized().stream()
.mapToDouble(order -> order.getSize() * order.getPrice())
.sum();
System.out.printf("Bid Depth: $%.2f | Ask Depth: $%.2f\n", bidDepth, askDepth);
});import com.mmorrell.phoenix.PhoenixProgram;
import com.mmorrell.phoenix.model.LimitOrderPacketRecord;
import org.p2p.solanaj.core.Transaction;
PublicKey marketId = new PublicKey("4DoNfFBfF7UokCC2FQzriy7yHK6DY6NVdYpuekQ5pRgg");
Account trader = Account.fromJson(readKeyFile());
// Get market to calculate order params
PhoenixMarket market = phoenixManager.getMarket(marketId, false).get();
// Create limit order
LimitOrderPacketRecord order = LimitOrderPacketRecord.builder()
.side((byte) 0) // 0 = bid, 1 = ask
.priceInTicks(market.getBestBid().get().getFirst().getPriceInTicks() - 100)
.numBaseLots(50L) // Size in lots
.clientOrderId(new byte[16]) // Unique order ID
.matchLimit(0)
.selfTradeBehavior((byte) 1) // Cancel provide
.useOnlyDepositedFunds(false)
.build();
Transaction tx = new Transaction();
tx.addInstruction(
PhoenixProgram.placeLimitOrder(
marketId,
trader.getPublicKey(),
baseTokenAccount,
quoteTokenAccount,
market.getPhoenixMarketHeader().getBaseVaultKey(),
market.getPhoenixMarketHeader().getQuoteVaultKey(),
order
)
);
String signature = client.getApi().sendTransaction(tx, trader);
System.out.println("Order placed: " + signature);import com.mmorrell.phoenix.model.CancelOrderParams;
// Cancel specific order by ID
CancelOrderParams cancelParams = CancelOrderParams.builder()
.sideToCancel((byte) 0) // 0 = bid, 1 = ask
.orderId(12345L) // Order ID from market state
.build();
tx.addInstruction(
PhoenixProgram.cancelOrder(
marketId,
trader.getPublicKey(),
cancelParams
)
);import com.mmorrell.phoenix.model.PhoenixMarket;
import org.p2p.solanaj.rpc.types.AccountInfo;
PublicKey marketId = new PublicKey("4DoNfFBfF7UokCC2FQzriy7yHK6DY6NVdYpuekQ5pRgg");
AccountInfo accountInfo = client.getApi().getAccountInfo(
marketId,
Map.of("commitment", "processed")
);
byte[] data = accountInfo.getDecodedData();
PhoenixMarket market = PhoenixMarket.readPhoenixMarket(data);
System.out.println("Market deserialized!");
System.out.println("Tick size: " + market.getPhoenixMarketHeader().getRawBaseUnitsPerBaseUnit());Pyth Network provides high-fidelity, high-frequency market data for DeFi applications.
import com.mmorrell.pyth.manager.PythManager;
import com.mmorrell.pyth.model.*;
RpcClient client = new RpcClient("https://api.mainnet-beta.solana.com");
PythManager pythManager = new PythManager(client);
// Pyth mapping account (contains all products)
PublicKey mappingAccount = new PublicKey("AHtgzX45WTKfkPG53L6WYhGEXwQkN1BVknET3sVsLL8J");
MappingAccount mapping = pythManager.getMappingAccount(mappingAccount);
System.out.println("=== Pyth Price Feeds ===\n");
for (PublicKey productKey : mapping.getProductAccountKeys()) {
ProductAccount product = pythManager.getProductAccount(productKey);
PriceDataAccount priceData = pythManager.getPriceDataAccount(
product.getPriceAccountKey()
);
String symbol = product.getProductAttributes().get("description");
double price = priceData.getAggregatePriceInfo().getPrice();
long confidence = priceData.getAggregatePriceInfo().getConfidence();
System.out.printf("%s: $%.2f (Β±$%d)\n", symbol, price, confidence);
}// SOL/USD price feed
PublicKey solUsdFeed = new PublicKey("H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG");
PriceDataAccount priceData = pythManager.getPriceDataAccount(solUsdFeed);
System.out.println("=== SOL/USD ===");
System.out.println("Price: $" + priceData.getAggregatePriceInfo().getPrice());
System.out.println("Confidence: $" + priceData.getAggregatePriceInfo().getConfidence());
System.out.println("Status: " + priceData.getAggregatePriceInfo().getStatus());
System.out.println("Slot: " + priceData.getLastSlot());
// EMA (Exponential Moving Average)
System.out.println("EMA Price: $" + priceData.getEma().getPrice());
System.out.println("EMA Confidence: $" + priceData.getEma().getConfidence());Map<String, List<ProductAccount>> assetsByClass = new HashMap<>();
MappingAccount mapping = pythManager.getMappingAccount(mappingAccount);
for (PublicKey productKey : mapping.getProductAccountKeys()) {
ProductAccount product = pythManager.getProductAccount(productKey);
String assetType = product.getProductAttributes().get("asset_type");
assetsByClass.computeIfAbsent(assetType, k -> new ArrayList<>()).add(product);
}
// Print crypto prices
assetsByClass.get("Crypto").forEach(product -> {
PriceDataAccount price = pythManager.getPriceDataAccount(product.getPriceAccountKey());
System.out.printf("%s: $%.2f\n",
product.getProductAttributes().get("description"),
price.getAggregatePriceInfo().getPrice()
);
});PublicKey btcUsdFeed = new PublicKey("GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU");
// Poll every 5 seconds
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(() -> {
try {
PriceDataAccount priceData = pythManager.getPriceDataAccount(btcUsdFeed);
double price = priceData.getAggregatePriceInfo().getPrice();
System.out.printf("[%s] BTC/USD: $%.2f\n",
LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME),
price
);
} catch (Exception e) {
System.err.println("Error fetching price: " + e.getMessage());
}
}, 0, 5, TimeUnit.SECONDS);Jupiter is Solana's leading swap aggregator, finding the best routes across all DEXes.
import com.mmorrell.jupiter.manager.JupiterManager;
import com.mmorrell.jupiter.model.JupiterCustody;
RpcClient client = new RpcClient("https://api.mainnet-beta.solana.com");
JupiterManager jupiterManager = new JupiterManager(client);
// Example: Get custody account information
PublicKey custodyAccount = new PublicKey("YourCustodyAccountHere");
Optional<JupiterCustody> custody = jupiterManager.getCustody(custodyAccount);
custody.ifPresent(c -> {
System.out.println("Jupiter Custody:");
System.out.println(" Pool: " + c.getPool().toBase58());
System.out.println(" Mint: " + c.getMint().toBase58());
System.out.println(" Token Account: " + c.getTokenAccount().toBase58());
});π‘ Note: Jupiter primarily provides HTTP APIs for swap routing. This module focuses on on-chain program interactions. For swap quotes and routing, use Jupiter's API.
Mango Markets provides decentralized perpetual futures and margin trading.
import com.mmorrell.mango.manager.MangoManager;
import com.mmorrell.mango.model.*;
RpcClient client = new RpcClient("https://api.mainnet-beta.solana.com");
MangoManager mangoManager = new MangoManager(client);
// Read Mango market accounts and positions
PublicKey mangoAccount = new PublicKey("YourMangoAccountHere");
// Get account data (example - specific methods depend on Mango version)
byte[] accountData = client.getApi().getAccountInfo(mangoAccount).getDecodedData();
System.out.println("Mango account data loaded");
// Parse according to Mango account structureπ‘ Note: Mango has multiple versions (v3, v4). Refer to specific module documentation for version-specific usage.
The original Serum DEX - deprecated but still used by some markets.
import com.mmorrell.serum.manager.SerumManager;
import com.mmorrell.serum.model.Market;
RpcClient client = new RpcClient("https://api.mainnet-beta.solana.com");
SerumManager serumManager = new SerumManager(client);
PublicKey marketAddress = new PublicKey("9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT");
Market market = serumManager.getMarket(marketAddress);
System.out.println("=== Serum Market ===");
System.out.println("Bids: " + market.getBidOrderBook().getOrders().size() + " orders");
System.out.println("Asks: " + market.getAskOrderBook().getOrders().size() + " orders");
// Get best bid/ask
if (!market.getBidOrderBook().getOrders().isEmpty()) {
var bestBid = market.getBidOrderBook().getOrders().get(0);
System.out.printf("Best Bid: $%.2f x %.4f\n", bestBid.getPrice(), bestBid.getSize());
}
if (!market.getAskOrderBook().getOrders().isEmpty()) {
var bestAsk = market.getAskOrderBook().getOrders().get(0);
System.out.printf("Best Ask: $%.2f x %.4f\n", bestAsk.getPrice(), bestAsk.getSize());
}Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
If this project has been helpful to you, consider supporting its development!
Solana Address: skynet.sol
You can send SOL or any SPL tokens to support continued development and maintenance. Every contribution is greatly appreciated! π
- GitHub: skynetcap/solanaj-programs
- Maven Central: com.mmorrell:solanaj-programs
- SolanaJ Core: github.com/skynetcap/solanaj
Built with β€οΈ for the Solana ecosystem
β Star us on GitHub if this project helped you!