GitHub Repository

Dependencies

Usage Examples

Retrieve and Parse Drift placeOrders Transaction

Prints the following at the end:

Limit Long 0.1 @ 111 on SOL-PERP [reduceOnly=false] [postOnly=MustPostOnly]

try (var httpClient = HttpClient.newHttpClient()) {
  var rpcClient = SolanaRpcClient.createClient(SolanaNetwork.MAIN_NET.getEndpoint(), httpClient);

  // Fetch a Drift placeOrders Transaction
  var txFuture = rpcClient.getTransaction(
      "36Wnn99Y49mJ5GKiNiT3ja2q8gzSvMNrN5A3Bcn2YfCyrwY7kgQGVAu9VNzXqmWSbgzX76oUGxYNuPGM7tpPoJJS"
  );
  var tx = txFuture.join();
  byte[] txData = tx.data();

  var skeleton = TransactionSkeleton.deserializeSkeleton(txData);

  Instruction[] instructions;
  if (skeleton.isLegacy()) {
    instructions = skeleton.parseLegacyInstructions();
  } else {
    // Fetch Lookup tables to allow parsing of versioned transactions.
    int txVersion = skeleton.version();
    if (txVersion == 0) {
      var tableAccountInfos = rpcClient.getMultipleAccounts(
          Arrays.asList(skeleton.lookupTableAccounts()),
          AddressLookupTable.FACTORY
      ).join();

      var lookupTables = tableAccountInfos.stream()
          .map(AccountInfo::data)
          .collect(Collectors.toUnmodifiableMap(AddressLookupTable::address, Function.identity()));
      var accounts = skeleton.parseAccounts(lookupTables);

      instructions = skeleton.parseInstructions(accounts);
    } else {
      throw new IllegalStateException("Unhandled tx version " + txVersion);
    }
  }

  // instructions[0]; // Compute Budget Limit
  // instructions[1]; // Compute Unit Price
  // instructions[2]; // Drift Place Orders
  var placeOrdersIxData = Arrays.stream(instructions)
      .filter(DriftProgram.PLACE_ORDERS_DISCRIMINATOR)
      .map(DriftProgram.PlaceOrdersIxData::read)
      .findFirst()
      .orElseThrow();

  OrderParams[] orderParams = placeOrdersIxData.params();
  OrderParams order = orderParams[0];

  // Fetch token contexts to make use of convenient scaled value conversions.
  var jupiterClient = JupiterClient.createClient(httpClient);
  var verifiedTokens = jupiterClient.verifiedTokenMap().join();

  // Create Drift Client to map market indexes from the order to its configuration.
  var nativeProgramClient = NativeProgramClient.createClient();
  var nativeProgramAccountClient = nativeProgramClient
      .createAccountClient(AccountMeta.createFeePayer(PublicKey.NONE));
  var driftClient = DriftProgramClient.createClient(nativeProgramAccountClient);

  var driftAccounts = driftClient.accounts();
  MarketConfig marketConfig;
  TokenContext baseTokenContext;
  if (order.marketType() == MarketType.Perp) {
    var perpMarketConfig = driftAccounts.perpMarketConfig(order.marketIndex());
    var spotConfig = driftClient.spotMarket(perpMarketConfig.baseAssetSymbol());
    baseTokenContext = verifiedTokens.get(spotConfig.mint());
    marketConfig = perpMarketConfig;
  } else {
    var spotConfig = driftAccounts.spotMarketConfig(order.marketIndex());
    baseTokenContext = verifiedTokens.get(spotConfig.mint());
    marketConfig = spotConfig;
  }

  // Assume all Drift markets are priced in USDC
  var usdcTokenMint = driftClient.spotMarket(DriftAsset.USDC).mint();
  var usdcTokenContext = verifiedTokens.get(usdcTokenMint);

  // Limit Long 0.1 @ 111 on SOL-PERP [reduceOnly=false] [postOnly=MustPostOnly]
  System.out.format("""
          %s %s %s @ %s on %s [reduceOnly=%b] [postOnly=%s]
          """,
      order.orderType(),
      order.direction(),
      baseTokenContext.toDecimal(order.baseAssetAmount()).toPlainString(),
      usdcTokenContext.toDecimal(order.price()).toPlainString(),
      marketConfig.symbol(),
      order.reduceOnly(),
      order.postOnly()
  );
}