Skip to content

Commit

Permalink
Add discriminator-based filtering and position retrieval to tests
Browse files Browse the repository at this point in the history
Implemented a method to retrieve all Jupiter perpetual positions using discriminator-based filtering. Enhanced the existing test cases for deserialization and added new tests to validate the retrieval of positions from the program account.
  • Loading branch information
skynetcap committed Sep 22, 2024
1 parent 3488152 commit 574cd78
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@
import lombok.Data;
import org.p2p.solanaj.core.PublicKey;

/**
* 8 (padding) +
* 32 (owner) +
* 32 (pool) +
* 32 (custody) +
* 32 (collateralCustody) +
* 8 (openTime) +
* 8 (updateTime) +
* 4 (side) +
* 8 (price) +
* 8 (sizeUsd) +
* 8 (collateralUsd) +
* 8 (realisedPnlUsd) +
* 8 (cumulativeInterestSnapshot) +
* 8 (lockedAmount) +
* 4 (bump) = 8 + 128 + 64 + 4 + 4 = 216 bytes
*/
@Data
@Builder
public class JupiterPerpPosition {
Expand Down
87 changes: 74 additions & 13 deletions jupiter/src/test/java/JupiterTest.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
import com.mmorrell.jupiter.model.JupiterPerpPosition;
import lombok.extern.slf4j.Slf4j;
import org.bitcoinj.core.Base58;
import org.junit.jupiter.api.Test;
import org.p2p.solanaj.core.PublicKey;
import org.p2p.solanaj.rpc.Cluster;
import org.p2p.solanaj.rpc.RpcClient;
import org.p2p.solanaj.rpc.RpcException;
import org.p2p.solanaj.rpc.types.AccountInfo;
import org.p2p.solanaj.rpc.types.Memcmp;
import org.p2p.solanaj.rpc.types.ProgramAccount;

import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

import static org.junit.jupiter.api.Assertions.*;

/**
* Test class for Jupiter Perpetuals positions.
*/
@Slf4j
public class JupiterTest {

private final RpcClient client = new RpcClient(Cluster.MAINNET);

@Test
public void testProofOfConcept() {
log.info("Testing proof of concept");
}
private final RpcClient client = new RpcClient("https://mainnet.helius-rpc.com/?api-key=a778b653-bdd6-41bc-8cda-0c7377faf1dd");

@Test
public void testJupiterPerpPositionDeserialization() throws RpcException {
Expand All @@ -28,21 +32,21 @@ public void testJupiterPerpPositionDeserialization() throws RpcException {

// Fetch the account data
AccountInfo accountInfo = client.getApi().getAccountInfo(positionPublicKey);

assertNotNull(accountInfo, "Account info should not be null");

byte[] data = Base64.getDecoder().decode(accountInfo.getValue().getData().get(0));

// Deserialize the data into JupiterPerpPosition
JupiterPerpPosition position = JupiterPerpPosition.fromByteArray(data);

// Log the deserialized position
log.info("Deserialized JupiterPerpPosition: {}", position);

// Assertions
assertNotNull(position);
assertEquals(positionPublicKeyOwner, position.getOwner());

// Add more specific assertions based on expected values
assertNotNull(position.getPool());
assertNotNull(position.getCustody());
Expand All @@ -55,4 +59,61 @@ public void testJupiterPerpPositionDeserialization() throws RpcException {
assertTrue(position.getCollateralUsd() > 0);
// Add more assertions as needed
}

@Test
public void testGetAllJupiterPerpPositions() throws RpcException {
PublicKey programId = new PublicKey("PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu");

// Get the discriminator for the Position account
byte[] positionDiscriminator = getAccountDiscriminator("Position");

// Create a memcmp filter for the discriminator at offset 0
Memcmp memcmpFilter = new Memcmp(0, Base58.encode(positionDiscriminator));

// Get all program accounts matching the filters
List<ProgramAccount> positionAccounts = client.getApi().getProgramAccounts(
programId,
Collections.singletonList(memcmpFilter),
216
);

List<JupiterPerpPosition> positions = new ArrayList<>();
for (ProgramAccount account : positionAccounts) {
// Decode the account data
byte[] data = account.getAccount().getDecodedData();

// Deserialize the data into JupiterPerpPosition
JupiterPerpPosition position = JupiterPerpPosition.fromByteArray(data);

if (position.getSizeUsd() > 0) {
// Add to the list
positions.add(position);
}
}

positions.sort(Comparator.comparingLong(JupiterPerpPosition::getSizeUsd));

// Log the positions
for (JupiterPerpPosition position : positions) {
double leverage = (double) position.getSizeUsd() / position.getCollateralUsd();
log.info("Owner: {}, Size USD: {}, Leverage: {}", position.getOwner().toBase58(), position.getSizeUsd(), leverage);
}
}

/**
* Calculates the account discriminator for a given account name.
*
* @param accountName the name of the account.
* @return the first 8 bytes of the SHA-256 hash of "account:<accountName>".
*/
private byte[] getAccountDiscriminator(String accountName) {
String preimage = "account:" + accountName;
try {
MessageDigest hasher = MessageDigest.getInstance("SHA-256");
hasher.update(preimage.getBytes(StandardCharsets.UTF_8));
return Arrays.copyOfRange(hasher.digest(), 0, 8);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-256 algorithm not found for discriminator calculation.");
}
}
}

0 comments on commit 574cd78

Please sign in to comment.