- HTTP and WebSocket JSON RPC Clients.
- Transaction (de)serialization.
- Legacy
- V0
- Crypto utilities for elliptic curve Ed25519 and Solana accounts.
- Borsh (de)serialization.
- The latest generally available JDK. This project will continue to move to the latest and will not maintain versions released against previous JDK's.
-
- java.base
- Bouncy Castle
-
- software.sava.core
- java.net.http
- JSON Iterator
Create a GitHub user access token with read access to GitHub Packages.
Then add the following to your Gradle build script.
repositories {
maven {
url = "https://maven.pkg.github.com/sava-software/sava"
credentials {
username = GITHUB_USERNAME
password = GITHUB_PERSONAL_ACCESS_TOKEN
}
}
}
dependencies {
implementation "software.sava:sava-core:$VERSION"
implementation "software.sava:sava-rpc:$VERSION"
}
Unit tests are needed and welcomed. Otherwise, please open a discussion, issue, or send an email before working on a pull request.
In addition to the MIT License, this project is under active development and breaking changes are to be expected.
More parses are available for programs which have Anchor IDL's in the sava anchor-programs project.
try (final var httpClient = HttpClient.newHttpClient()) {
final var rpcClient = SolanaRpcClient.createClient(SolanaNetwork.MAIN_NET.getEndpoint(), httpClient);
final var accountInfoFuture = rpcClient.getAccountInfo(
PublicKey.fromBase58Encoded("7Y9fsUT7EcnkH3jhN2GM4TBSBe1BeCyTCUwA2bxi29pr"),
AddressLookupTable.FACTORY
);
final var accountInfo = accountInfoFuture.join();
final AddressLookupTable table = accountInfo.data();
System.out.println(table);
}
Retrieve all lookup tables which are active and frozen.
Note: You will need access to an RPC node which has getProgramAccounts enabled, such as Helius.
try (final var httpClient = HttpClient.newHttpClient()) {
final var rpcClient = SolanaRpcClient.createClient(
URI.create("https://mainnet.helius-rpc.com/?api-key="),
httpClient
);
final byte[] stillActive = new byte[Long.BYTES];
ByteUtil.putInt64LE(stillActive, 0, Clock.MAX_SLOT);
final var activeFilter = Filter.createMemCompFilter(DEACTIVATION_SLOT_OFFSET, stillActive);
final var noAuthorityFilter = Filter.createMemCompFilter(AUTHORITY_OPTION_OFFSET, new byte[]{0});
final var accountInfoFuture = rpcClient.getProgramAccounts(
SolanaAccounts.MAIN_NET.addressLookupTableProgram(),
List.of(
// Filter all active frozen tables.
activeFilter,
noAuthorityFilter
),
AddressLookupTable.FACTORY
);
final var accountInfoList = accountInfoFuture.join();
accountInfoList.stream()
.map(AccountInfo::data)
.forEach(System.out::println);
System.out.format("Retrieved %d tables which are active and frozen.%n", accountInfoList.size());
}
Subscribe to the Address Lookup Table Program.
try (final var httpClient = HttpClient.newHttpClient()) {
final var webSocket = SolanaRpcWebsocket.build()
.uri(SolanaNetwork.MAIN_NET.getWebSocketEndpoint())
.webSocketBuilder(httpClient)
.commitment(Commitment.CONFIRMED)
.onClose((_, statusCode, reason) -> System.out.format("%d: %s%n", statusCode, reason))
.onError((_, throwable) -> throwable.printStackTrace())
.create();
webSocket.programSubscribe(SolanaAccounts.MAIN_NET.addressLookupTableProgram(), accountInfo -> {
final var table = AddressLookupTable.read(accountInfo.pubKey(), accountInfo.data());
// {
// "address": "Fuy3RVz8u2pNaeGLHG7wp8eBg7JA3vzBcDB82PXTGAHz",
// "deactivationSlot": 18446744073709551615,
// "lastExtendedSlot": 283587161,
// "lastExtendedSlotStartIndex": 0,
// "authority": "C5vPh26poBM8mYbdEnDMWGMhcrQrb84eULChZKkExDG1",
// "accounts": "[675MHPyK53QJUNWyjYb3gyse5podtFRdsj61ssRcPEUr, C5vPh26poBM8mYbdEnDMWGMhcrQrb84eULChZKkExDG1, 5hvPX4JoMwKCoYQomQRF4jutJ3JDraj2rGoWsvUZGtyN, 2TzAT9jnyAxna1N2hASrPXftHyVU9mByCHMNKTLtRX82]"
// }
System.out.println(table);
});
webSocket.connect();
Thread.sleep(Integer.MAX_VALUE);
}