> ## Documentation Index
> Fetch the complete documentation index at: https://sava.software/llms.txt
> Use this file to discover all available pages before exploring further.

# Anchor Programs

> Convenient program clients and generated source based on Anchor IDLs.

<Card title="GitHub Repository" icon="github" horizontal={true} href="https://github.com/sava-software/anchor-programs" />

## [Dependencies](https://github.com/sava-software/anchor-programs/blob/main/anchor-programs/src/main/java/module-info.java)

* java.net.http
* [org.bouncycastle.provider](https://www.bouncycastle.org/download/bouncy-castle-java/#latest)
* software.sava.json.iterator
* software.sava.core
* software.sava.rpc
* software.sava.solana\_programs
* software.sava.anchor\_src\_gen

## Usage Examples

### [Retrieve and Parse Drift placeOrders Transaction](https://github.com/sava-software/anchor-programs/blob/main/examples/src/main/java/software/sava/anchor/program/examples/ParseDriftPlaceOrdersTransaction.java)

Prints the following at the end:

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

```java theme={null}
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()
  );
}
```
