Skip to content

Commit

Permalink
Fixed merged conflict and changed naming for legacy transaction and l…
Browse files Browse the repository at this point in the history
…egacy message
  • Loading branch information
Chintan Patel authored and Chintan Patel committed Nov 12, 2024
2 parents 46359ce + 43deb51 commit 2330b29
Show file tree
Hide file tree
Showing 52 changed files with 4,258 additions and 746 deletions.
112 changes: 87 additions & 25 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,93 @@
# SolanaJ

Solana blockchain client, written in pure Java.
Solanaj is an API for integrating with Solana blockchain using the [Solana RPC API](https://docs.solana.com/apps/jsonrpc-api)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Java Version](https://img.shields.io/badge/Java-17%2B-blue)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
[![Maven Central](https://img.shields.io/maven-central/v/com.mmorrell/solanaj.svg)](https://search.maven.org/artifact/com.mmorrell/solanaj)
[![Solana](https://img.shields.io/badge/Solana-Compatible-blueviolet)](https://solana.com/)
[![Java](https://img.shields.io/badge/Pure-Java-orange)](https://www.java.com/)
[![Documentation](https://img.shields.io/badge/API-Documentation-lightgrey)](https://docs.solana.com/apps/jsonrpc-api)
[![Discord](https://img.shields.io/discord/889577356681945098?color=blueviolet)](https://discord.gg/solana)
[![GitHub Stars](https://img.shields.io/github/stars/skynetcap/solanaj?style=social)](https://github.com/skynetcap/solanaj)

Solana blockchain client, written in pure Java. SolanaJ is an API for integrating with Solana blockchain using the [Solana RPC API](https://docs.solana.com/apps/jsonrpc-api).

This fork includes functionality for multiple Solana programs, including the Serum DEX.

# SolanaJ-Programs
For SolanaJ implementations of popular Solana programs such as Serum, please visit: https://github.com/skynetcap/solanaj-programs
## Table of Contents

- [SolanaJ-Programs](#solanaj-programs)
- [Requirements](#%EF%B8%8F-requirements)
- [Dependencies](#-dependencies)
- [Installation](#-installation)
- [Build](#%EF%B8%8F-build)
- [Examples](#-examples)
- [Transfer Lamports](#transfer-lamports)
- [Get Balance](#get-balance)
- [Get Serum Market + Orderbooks](#get-serum-market--orderbooks)
- [Send a Transaction with Memo Program](#send-a-transaction-with-memo-program)
- [Contributing](#-contributing)
- [License](#-license)

## SolanaJ-Programs

For SolanaJ implementations of popular Solana programs such as Serum, please visit: [https://github.com/skynetcap/solanaj-programs](https://github.com/skynetcap/solanaj-programs)

## 🛠️ Requirements

## Requirements
- Java 17+

## Dependencies
## 📚 Dependencies

- bitcoinj
- OkHttp
- Moshi

## Installation
1. Add Maven dependency:
## 📦 Installation

Add the following Maven dependency to your project's `pom.xml`:

```xml
<dependency>
<groupId>com.mmorrell</groupId>
<artifactId>solanaj</artifactId>
<version>1.17.6</version>
<groupId>com.mmorrell</groupId>
<artifactId>solanaj</artifactId>
<version>1.19.2</version>
</dependency>
```

## Build
In pom.xml update the plugin maven-gpg-plugin configuration with your homedir and keyname.
To see if you have a gpg key run `gpg --list-secret-keys`
If nothing is returned create one with `gpg --full-generate-key`
Then run `mvn install` and the build should complete successfully.
## 🏗️ Build

1. In `pom.xml`, update the `maven-gpg-plugin` configuration with your homedir and keyname:

```xml
<configuration>
<homedir>/home/phil/.gnupg/</homedir>
<keyname>AE2D00367F40E980F7C62FF792C4533F3EE03477</keyname>
<homedir>/home/your_username/.gnupg/</homedir>
<keyname>YOUR_GPG_KEY_ID</keyname>
</configuration>
```

## Example
##### Transfer lamports
2. Check if you have a GPG key:

```sh
gpg --list-secret-keys
```

3. If no key is returned, create one:

```sh
gpg --full-generate-key
```

4. Run the Maven install command:

```sh
mvn install
```

The build should complete successfully.

## 🚀 Examples

### Transfer Lamports

```java
RpcClient client = new RpcClient(Cluster.TESTNET);
Expand All @@ -57,15 +104,16 @@ legacyTransaction.addInstruction(SystemProgram.transfer(fromPublicKey, toPublick
String signature = client.getApi().sendTransaction(legacyTransaction, signer);
```

##### Get balance
### Get Balance

```java
RpcClient client = new RpcClient(Cluster.TESTNET);

long balance = client.getApi().getBalance(new PublicKey("QqCCvshxtqMAL2CVALqiJB7uEeE5mjSPsseQdDzsRUo"));
```

##### Get Serum market + orderbooks
### Get Serum Market + Orderbooks

```java
final PublicKey solUsdcPublicKey = new PublicKey("7xMDbYTCqQEcK2aM9LbetGtNFJpzKdfXzLL5juaLh4GJ");
final Market solUsdcMarket = new MarketBuilder()
Expand All @@ -78,6 +126,7 @@ final OrderBook bids = solUsdcMarket.getBidOrderBook();
```

##### Send a legacyTransaction with call to the "Memo" program

```java
// Create account from private key
final Account feePayer = new Account(Base58.decode(new String(data)));
Expand All @@ -88,9 +137,22 @@ legacyTransaction.addInstruction(
MemoProgram.writeUtf8(feePayer.getPublicKey(),"Hello from SolanaJ :)")
);

String response = result = client.getApi().sendTransaction(legacyTransaction, feePayer);
String response = client.getApi().sendTransaction(legacyTransaction, feePayer);
```

## License
## 🤝 Contributing

We welcome contributions to SolanaJ! Here's how you can help:

1. Fork the repository
2. Create a new branch (`git checkout -b feature/your-feature-name`)
3. Make your changes
4. Commit your changes (`git commit -am 'Add some feature'`)
5. Push to the branch (`git push origin feature/your-feature-name`)
6. Create a new Pull Request

Please make sure to update tests as appropriate and adhere to the existing coding style.

## 📄 License

MIT License
SolanaJ is open-source software licensed under the [MIT License](LICENSE). See the LICENSE file for more details.
63 changes: 42 additions & 21 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -120,6 +120,13 @@
<version>2.17.2</version>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.12.4</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
Expand Down Expand Up @@ -184,31 +191,45 @@
</executions>
<configuration>
<source>17</source>
<doclint>none</doclint>
<failOnError>false</failOnError>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<homedir>c:/Users/Michael/.gnupg/</homedir>
<keyname>0x27FAE7D2</keyname>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>deploy</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<homedir>/Users/chintan_mbp/.gnupg/</homedir>
<keyname>4B9021119F83557FF09AEBAAA4751749EC8210A3</keyname>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
27 changes: 27 additions & 0 deletions src/main/java/org/p2p/solanaj/core/Account.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.List;

import org.bitcoinj.crypto.*;
import org.bitcoinj.core.Base58;
import org.p2p.solanaj.utils.TweetNaclFast;
import org.p2p.solanaj.utils.bip32.wallet.SolanaBip44;
import org.p2p.solanaj.utils.bip32.wallet.DerivableType;
Expand Down Expand Up @@ -116,4 +117,30 @@ private static byte[] convertJsonStringToByteArray(String characters) {

return buffer.array();
}

/**
* Creates an Account from a base58-encoded private key string.
* @param base58PrivateKey The base58-encoded private key
* @return A new Account instance
*/
public static Account fromBase58PrivateKey(String base58PrivateKey) {
byte[] privateKey = Base58.decode(base58PrivateKey);
return new Account(privateKey);
}

/**
* Returns the account's public key as a base58-encoded string.
* @return The base58-encoded public key
*/
public String getPublicKeyBase58() {
return this.getPublicKey().toBase58();
}

/**
* Returns the account's private key as a base58-encoded string.
* @return The base58-encoded private key
*/
public String getPrivateKeyBase58() {
return Base58.encode(this.getSecretKey());
}
}
41 changes: 9 additions & 32 deletions src/main/java/org/p2p/solanaj/core/AccountKeysList.java
Original file line number Diff line number Diff line change
@@ -1,61 +1,38 @@
package org.p2p.solanaj.core;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.*;

public class AccountKeysList {
private final HashMap<String, AccountMeta> accounts;
private final Map<String, AccountMeta> accounts;

public AccountKeysList() {
accounts = new HashMap<>();
}

public void add(AccountMeta accountMeta) {
String key = accountMeta.getPublicKey().toString();

if (accounts.containsKey(key)) {
if (!accounts.get(key).isWritable() && accountMeta.isWritable()) {
accounts.put(key, accountMeta);
}
} else {
accounts.put(key, accountMeta);
}
accounts.merge(key, accountMeta, (existing, newMeta) ->
!existing.isWritable() && newMeta.isWritable() ? newMeta : existing);
}

public void addAll(Collection<AccountMeta> metas) {
for (AccountMeta meta : metas) {
add(meta);
}
metas.forEach(this::add);
}

public ArrayList<AccountMeta> getList() {
ArrayList<AccountMeta> accountKeysList = new ArrayList<>(accounts.values());
accountKeysList.sort(metaComparator);

return accountKeysList;
}

private static final Comparator<AccountMeta> metaComparator = (am1, am2) -> {

int cmpSigner = am1.isSigner() == am2.isSigner() ? 0 : am1.isSigner() ? -1 : 1;
if (cmpSigner != 0) {
return cmpSigner;
}

int cmpkWritable = am1.isWritable() == am2.isWritable() ? 0 : am1.isWritable() ? -1 : 1;
if (cmpkWritable != 0) {
return cmpkWritable;
}

return Integer.compare(cmpSigner, cmpkWritable);
};

@Override
public String toString() {
return "AccountKeysList{" +
"accounts=" + accounts +
'}';
}

private static final Comparator<AccountMeta> metaComparator = Comparator
.comparing(AccountMeta::isSigner).reversed()
.thenComparing(AccountMeta::isWritable).reversed();
}
13 changes: 12 additions & 1 deletion src/main/java/org/p2p/solanaj/core/AccountMeta.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ public class AccountMeta {

private boolean isWritable;

/**
* Sorting based on isSigner and isWritable cannot fully meet the requirements. This value can be used for custom sorting, because if the order is incorrect during serialization, it may lead to failed method calls.
*/
private int sort = Integer.MAX_VALUE;

public AccountMeta(PublicKey publicKey, boolean isSigner, boolean isWritable) {
this.publicKey = publicKey;
this.isSigner = isSigner;
this.isWritable = isWritable;
}

@Override
public String toString() {
return "AccountMeta{" +
Expand All @@ -21,4 +32,4 @@ public String toString() {
", isWritable=" + isWritable +
'}';
}
}
}
Loading

0 comments on commit 2330b29

Please sign in to comment.