Skip to content

Commit

Permalink
Add reading of decimals from Token Mint account data, and implement i…
Browse files Browse the repository at this point in the history
…t in MarketBuilder
  • Loading branch information
skynetcapital committed May 6, 2021
1 parent e1dc137 commit 32f4fe3
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 15 deletions.
24 changes: 24 additions & 0 deletions src/main/java/org/p2p/solanaj/serum/Market.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@ public class Market {
private OrderBook bidOrderBook;
private OrderBook askOrderBook;

// Data from token mints
private byte baseDecimals;
private byte quoteDecimals;

public byte getBaseDecimals() {
return baseDecimals;
}

public void setBaseDecimals(byte baseDecimals) {
this.baseDecimals = baseDecimals;
}

public byte getQuoteDecimals() {
return quoteDecimals;
}

public void setQuoteDecimals(byte quoteDecimals) {
this.quoteDecimals = quoteDecimals;
}

public OrderBook getBidOrderBook() {
return bidOrderBook;
}
Expand Down Expand Up @@ -299,6 +319,10 @@ public String toString() {
", quoteLotSize=" + quoteLotSize +
", feeRateBps=" + feeRateBps +
", referrerRebatesAccrued=" + referrerRebatesAccrued +
", bidOrderBook=" + bidOrderBook +
", askOrderBook=" + askOrderBook +
", baseDecimals=" + baseDecimals +
", quoteDecimals=" + quoteDecimals +
'}';
}
}
52 changes: 40 additions & 12 deletions src/main/java/org/p2p/solanaj/serum/MarketBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.util.Base64;
import java.util.List;
import java.util.logging.Logger;

/**
* Builds a {@link Market} object, which can have polled data including bid/ask {@link OrderBook}s
Expand All @@ -17,6 +18,10 @@ public class MarketBuilder {
private final RpcClient client = new RpcClient(Cluster.MAINNET);
private PublicKey publicKey;
private boolean retrieveOrderbooks = false;
private static final Logger LOGGER = Logger.getLogger(MarketBuilder.class.getName());

// TODO move all publickey consts to it's own static class
private static final PublicKey WRAPPED_SOL_MINT = new PublicKey("So11111111111111111111111111111111111111112");

public MarketBuilder setRetrieveOrderBooks(boolean retrieveOrderbooks) {
this.retrieveOrderbooks = retrieveOrderbooks;
Expand All @@ -31,7 +36,7 @@ public Market build() {
Market market = new Market();

// Get account Info
byte[] base64AccountInfo = getAccountData();
byte[] base64AccountInfo = retrieveAccountData();

// Read market
if (base64AccountInfo == null) {
Expand All @@ -42,33 +47,56 @@ public Market build() {

// Get Order books
if (retrieveOrderbooks) {
byte[] base64BidOrderbook = getOrderbookData(market.getBids());
byte[] base64AskOrderbook = getOrderbookData(market.getAsks());
// TODO - multi-thread these
// Data from the order books
byte[] base64BidOrderbook = retrieveAccountData(market.getBids());
byte[] base64AskOrderbook = retrieveAccountData(market.getAsks());

OrderBook bidOrderBook = OrderBook.readOrderBook(base64BidOrderbook);
OrderBook askOrderBook = OrderBook.readOrderBook(base64AskOrderbook);

market.setBidOrderBook(bidOrderBook);
market.setAskOrderBook(askOrderBook);

// Data from the token mints
// TODO - multi-thread these
byte baseDecimals = getMintDecimals(market.getBaseMint());
byte quoteDecimals = getMintDecimals(market.getQuoteMint());

LOGGER.info(String.format("Base decimals = %d", baseDecimals));
LOGGER.info(String.format("Quote decimals = %d", quoteDecimals));

market.setBaseDecimals(baseDecimals);
market.setQuoteDecimals(quoteDecimals);
}

return market;
}

private byte[] getAccountData() {
AccountInfo accountInfo = null;
try {
accountInfo = client.getApi().getAccountInfo(publicKey);
} catch (RpcException e) {
e.printStackTrace();
/**
* Retrieves decimals for a given Token Mint's {@link PublicKey} from Solana account data.
* @param tokenMint
* @return
*/
private byte getMintDecimals(PublicKey tokenMint) {
if (tokenMint.equals(WRAPPED_SOL_MINT)) {
return 9;
}

final List<String> accountData = accountInfo.getValue().getData();
// RPC call to get mint's account data into decoded bytes (already base64 decoded)
byte[] accountData = retrieveAccountData(tokenMint);

return Base64.getDecoder().decode(accountData.get(0));
// Deserialize accountData into the MINT_LAYOUT enum
byte decimals = SerumUtils.readDecimalsFromTokenMintData(accountData);

return decimals;
}

private byte[] retrieveAccountData() {
return retrieveAccountData(publicKey);
}

private byte[] getOrderbookData(PublicKey publicKey) {
private byte[] retrieveAccountData(PublicKey publicKey) {
AccountInfo orderBook = null;

try {
Expand Down
28 changes: 26 additions & 2 deletions src/main/java/org/p2p/solanaj/serum/SerumUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.p2p.solanaj.core.PublicKey;

import java.nio.ByteBuffer;
import java.util.logging.Logger;

/**
* version 2 market offsets.
Expand Down Expand Up @@ -41,6 +42,9 @@
*/
public class SerumUtils {

private static final Logger LOGGER = Logger.getLogger(SerumUtils.class.getName());

// Market
public static final int OWN_ADDRESS_OFFSET = 13;
private static final int VAULT_SIGNER_NONCE_OFFSET = 28;
private static final int BASE_MINT_OFFSET = 53;
Expand All @@ -61,8 +65,8 @@ public class SerumUtils {
private static final int FEE_RATE_BPS_OFFSET = 365;
private static final int REFERRER_REBATES_ACCRUED_OFFSET = 373;



// Token mint
private static final int TOKEN_MINT_DECIMALS_OFFSET = 44;

public static PublicKey readOwnAddressPubkey(byte[] bytes) {
return PublicKey.readPubkey(bytes, OWN_ADDRESS_OFFSET);
Expand Down Expand Up @@ -183,4 +187,24 @@ public static void writeClientId(ByteBuffer result, long clientId) {
public static void writeLimit(ByteBuffer result) {
result.putShort(49, (short) 65535);
}

/**
* Reads the decimals value from decoded account data of a given token mint
*
* Note: MINT_LAYOUT = struct([blob(44), u8('decimals'), blob(37)]);
*
* 0-43 = other data
* index 44 = the single byte of decimals we want
* 45-... = other data
*
* @param accountData decoded account data from the token mint
* @return int containing the number of decimals in the token mint
*/
public static byte readDecimalsFromTokenMintData(byte[] accountData) {
// Read a SINGLE byte at offset 44
byte result = accountData[TOKEN_MINT_DECIMALS_OFFSET];
LOGGER.info(String.format("Market decimals byte = %d", result));

return result;
}
}
2 changes: 1 addition & 1 deletion src/test/java/org/p2p/solanaj/core/MainnetTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public void testPriceDeserialization() {
*/
@Test
public void marketBuilderSolUsdcTest() {
final PublicKey solUsdcPublicKey = new PublicKey("7xMDbYTCqQEcK2aM9LbetGtNFJpzKdfXzLL5juaLh4GJ");;
final PublicKey solUsdcPublicKey = new PublicKey("9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT");;

final Market solUsdcMarket = new MarketBuilder()
.setPublicKey(solUsdcPublicKey)
Expand Down

0 comments on commit 32f4fe3

Please sign in to comment.