Libraries
Programs
Get Started
Utilities
Libraries
Programs
Native Solana Program Utilities and Clients.
GitHub Repository
Dependencies
- java.net.http
- systems.comodal.json_iterator
- software.sava.core
- software.sava.rpc
Program Clients
Provides convenience methods for creating common instructions.
Typical Transaction Flow
Signer signer = ...; // load private key
var feePayer = AccountMeta.createFeePayer(signer.publicKey());
var programClient = NativeProgramClient.createClient();
var programAccountClient = programClient.createAccountClient(feePayer);
try (var httpClient = HttpClient.newHttpClient()) {
var rpcClient = SolanaRpcClient.createClient(
SolanaNetwork.MAIN_NET.getEndpoint(),
httpClient
);
// Create relevant instructions
List<Instruction> instructions = List.of();
var simulationTransaction = programAccountClient.createTransaction(
ComputeBudgetProgram.MAX_COMPUTE_BUDGET,
0, // compute unite price
instructions
);
// Apply a user provided fee or fetch an estimate from a service such as Helius' Fee API.
long microLamportComputeUnitPrice = 1234;
var simulationResult = rpcClient.simulateTransaction(simulationTransaction).join();
var transaction = programAccountClient.createTransaction(
simulationResult.unitsConsumed().getAsInt(),
microLamportComputeUnitPrice,
instructions
);
transaction.setRecentBlockHash(simulationResult.replacementBlockHash().blockhash());
transaction.sign(signer);
var base64Encoded = transaction.base64EncodeToString();
var sig = rpcClient.sendTransaction(base64Encoded).join();
System.out.println(sig);
}
Transfer SOL
var transferFrom = PublicKey.fromBase58Encoded("");
var feePayer = AccountMeta.createFeePayer(transferFrom);
var programClient = NativeProgramClient.createClient();
var programAccountClient = programClient.createAccountClient(feePayer);
var transferTo = PublicKey.fromBase58Encoded("");
var transferIx = programAccountClient.transferSolLamports(transferTo, 42);
Create, Initialize & Delegate Stake Account
long stakeLamports = LamportDecimal.fromBigDecimal(BigDecimal.ONE).longValue();
var stakeAuthority = PublicKey.fromBase58Encoded("");
var feePayer = AccountMeta.createFeePayer(stakeAuthority);
var validatorVoteAccount = PublicKey.fromBase58Encoded("");
var programClient = NativeProgramClient.createClient();
var programAccountClient = programClient.createAccountClient(feePayer);
try (var httpClient = HttpClient.newHttpClient()) {
var rpcClient = SolanaRpcClient.createClient(
SolanaNetwork.MAIN_NET.getEndpoint(),
httpClient
);
var minRent = NativeProgramClient.getMinimumBalanceForStakeAccount(rpcClient).join();
var seed = ZonedDateTime.now(ZoneOffset.UTC).toString();
var uninitializedStakeAccount = programAccountClient.createOffCurveStakeAccountWithSeed(seed);
var createStakeAccountIx = programAccountClient.createStakeAccountWithSeed(
uninitializedStakeAccount,
minRent
);
var stakeAccountPubKey = uninitializedStakeAccount.publicKey();
var initializeIx = programAccountClient.initializeStakeAccount(stakeAccountPubKey);
var transferIx = programAccountClient.transferSolLamports(stakeAccountPubKey, stakeLamports);
var delegateStakeIx = programAccountClient.delegateStakeAccount(stakeAccountPubKey, validatorVoteAccount);
var instructions = List.of(createStakeAccountIx, initializeIx, transferIx, delegateStakeIx);
}
Create & Extend Lookup Table
var programClient = NativeProgramClient.createClient();
var programAccountClient = programClient.createAccountClient(feePayer);
var newAccounts = List.of(
PublicKey.fromBase58Encoded(""),
PublicKey.fromBase58Encoded(""),
PublicKey.fromBase58Encoded("")
);
long recentSlot = rpcClient.getSlot(FINALIZED).join();
var lookupTablePDA = nativeProgramAccountClient.findLookupTableAddress(recentSlot);
var createLookupTableIx = nativeProgramAccountClient.createLookupTable(lookupTablePDA, recentSlot);
var extendTableIx = nativeProgramAccountClient.extendLookupTable(lookupTablePDA.publicKey(), newAccounts);
var instructions = List.of(createLookupTableIx, extendTableIx);
Durable Nonce Transactions
See the official Solana documentation for context on durable nonce transactions.
Create & Initialize Nonce Account
Signer signer = ...
var rpcEndpoint = SolanaNetwork.MAIN_NET.getEndpoint();
try (var httpClient = HttpClient.newHttpClient()) {
var rpcClient = SolanaRpcClient.createClient(rpcEndpoint, httpClient);
var blockHashFuture = rpcClient.getLatestBlockHash();
var minRentFuture = rpcClient.getMinimumBalanceForRentExemption(NonceAccount.BYTES);
var solanaAccounts = SolanaAccounts.MAIN_NET;
var nonceAccountWithSeed = PublicKey.createOffCurveAccountWithAsciiSeed(
signer.publicKey(),
"nonce",
solanaAccounts.systemProgram()
);
var initializeNonceAccountIx = SystemProgram.initializeNonceAccount(
solanaAccounts,
nonceAccountWithSeed.publicKey(),
signer.publicKey()
);
System.out.format("""
Fetching block hash and minimum rent to create nonce account %s with authority %s.
""",
nonceAccountWithSeed.publicKey(),
signer.publicKey()
);
long minRent = minRentFuture.join();
var createNonceAccountIx = SystemProgram.createAccountWithSeed(
solanaAccounts.invokedSystemProgram(),
signer.publicKey(),
nonceAccountWithSeed,
minRent,
NonceAccount.BYTES,
solanaAccounts.systemProgram()
);
var instructions = List.of(createNonceAccountIx, initializeNonceAccountIx);
var transaction = Transaction.createTx(signer.publicKey(), instructions);
var blockHash = blockHashFuture.join().blockHash();
transaction.setRecentBlockHash(blockHash);
transaction.sign(signer);
var base64Encoded = transaction.base64EncodeToString();
var sendTransactionFuture = rpcClient.sendTransaction(base64Encoded);
System.out.format("""
Creating nonce account %s
https://explorer.solana.com/tx/%s
""",
nonceAccountWithSeed.publicKey(),
transaction.getBase58Id()
);
var sig = sendTransactionFuture.join();
System.out.format("""
Confirmed transaction %s
https://solscan.io/account/%s
""",
sig,
nonceAccountWithSeed.publicKey()
);
var nonceAccountInfo = rpcClient.getAccountInfo(nonceAccountWithSeed.publicKey()).join();
var nonceAccount = NonceAccount.read(nonceAccountInfo);
System.out.println(nonceAccount);
}
Create & Send Durable Nonce Transaction
var signer = ...
var nonceAccountKey = PublicKey.fromBase58Encoded("");
var sendToKey = PublicKey.fromBase58Encoded("");
var transferSOL = new BigDecimal("0.0");
var solanaAccounts = SolanaAccounts.MAIN_NET;
var rpcEndpoint = SolanaNetwork.MAIN_NET.getEndpoint();
try (var httpClient = HttpClient.newHttpClient()) {
var rpcClient = SolanaRpcClient.createClient(rpcEndpoint, httpClient);
var nonceAccountInfo = rpcClient.getAccountInfo(nonceAccountKey).join();
var nonceAccount = NonceAccount.read(nonceAccountInfo);
System.out.println(nonceAccount);
var advanceNonceIx = nonceAccount.advanceNonceAccount(solanaAccounts);
var transferIx = SystemProgram.transfer(
solanaAccounts.invokedSystemProgram(),
signer.publicKey(),
sendToKey,
LamportDecimal.fromBigDecimal(transferSOL).longValue()
);
var instructions = List.of(advanceNonceIx, transferIx);
var transaction = Transaction.createTx(signer.publicKey(), instructions);
transaction.setRecentBlockHash(nonceAccount.nonce());
transaction.sign(signer);
var base64Encoded = transaction.base64EncodeToString();
var sendTransactionFuture = rpcClient.sendTransaction(base64Encoded);
System.out.format("""
Transferring %s SOL from %s to %s.
https://explorer.solana.com/tx/%s
""",
transferSOL.toPlainString(), signer.publicKey(), sendToKey,
transaction.getBase58Id()
);
var sig = sendTransactionFuture.join();
System.out.println("Confirmed transaction " + sig);
}