49: Bind Jupiter position services to wallets
This commit is contained in:
@@ -9,11 +9,11 @@ import java.math.BigDecimal;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for reading Jupiter Perps data and constructing and executing
|
* Service for reading Jupiter Perps data and executing complete position
|
||||||
* Jupiter Perps transactions.
|
* operations.
|
||||||
*
|
*
|
||||||
* <p>This service does not sign transactions. A compatible wallet is
|
* <p>For position mutations, the service constructs the required transaction
|
||||||
* required to sign a constructed transaction before it can be executed.</p>
|
* and delegates signing and submission to the supplied wallet.</p>
|
||||||
*/
|
*/
|
||||||
public interface JupiterPerpsService {
|
public interface JupiterPerpsService {
|
||||||
/**
|
/**
|
||||||
@@ -49,8 +49,8 @@ public interface JupiterPerpsService {
|
|||||||
/**
|
/**
|
||||||
* Opens or increases a Jupiter Perps position.
|
* Opens or increases a Jupiter Perps position.
|
||||||
*
|
*
|
||||||
* <p>The service constructs the transaction, asks the supplied wallet to
|
* <p>The service constructs the transaction and asks the supplied wallet
|
||||||
* sign it, and submits it to Jupiter.</p>
|
* to sign and submit it.</p>
|
||||||
*
|
*
|
||||||
* @param wallet the wallet that owns or will own the position
|
* @param wallet the wallet that owns or will own the position
|
||||||
* @param tradedTokenMint the mint address of the asset being traded
|
* @param tradedTokenMint the mint address of the asset being traded
|
||||||
@@ -76,8 +76,8 @@ public interface JupiterPerpsService {
|
|||||||
/**
|
/**
|
||||||
* Decreases an existing Jupiter Perps position.
|
* Decreases an existing Jupiter Perps position.
|
||||||
*
|
*
|
||||||
* <p>The service constructs the transaction, asks the supplied wallet to
|
* <p>The service constructs the transaction and asks the supplied wallet
|
||||||
* sign it, and submits it to Jupiter.</p>
|
* to sign and submit it.</p>
|
||||||
*
|
*
|
||||||
* @param wallet the wallet that owns the position
|
* @param wallet the wallet that owns the position
|
||||||
* @param positionAccount the Jupiter Perps position to decrease
|
* @param positionAccount the Jupiter Perps position to decrease
|
||||||
|
|||||||
+2
-111
@@ -7,15 +7,12 @@ import com.r35157.libs.jupiter.perps.JupiterPerpsPositionDirection;
|
|||||||
import com.r35157.libs.jupiter.perps.JupiterPerpsService;
|
import com.r35157.libs.jupiter.perps.JupiterPerpsService;
|
||||||
import com.r35157.libs.jupiter.perps.protocol.DecreasePositionRequest;
|
import com.r35157.libs.jupiter.perps.protocol.DecreasePositionRequest;
|
||||||
import com.r35157.libs.jupiter.perps.protocol.DecreasePositionResponse;
|
import com.r35157.libs.jupiter.perps.protocol.DecreasePositionResponse;
|
||||||
import com.r35157.libs.jupiter.perps.protocol.ExecuteTransactionRequest;
|
|
||||||
import com.r35157.libs.jupiter.perps.protocol.ExecuteTransactionResponse;
|
|
||||||
import com.r35157.libs.jupiter.perps.protocol.IncreasePositionRequest;
|
import com.r35157.libs.jupiter.perps.protocol.IncreasePositionRequest;
|
||||||
import com.r35157.libs.jupiter.perps.protocol.IncreasePositionResponse;
|
import com.r35157.libs.jupiter.perps.protocol.IncreasePositionResponse;
|
||||||
import com.r35157.libs.jupiter.perps.protocol.TransactionMetadata;
|
import com.r35157.libs.jupiter.perps.protocol.TransactionMetadata;
|
||||||
import com.r35157.libs.solana.SolanaAccountInfo;
|
import com.r35157.libs.solana.SolanaAccountInfo;
|
||||||
import com.r35157.libs.solana.SolanaBlockChain;
|
import com.r35157.libs.solana.SolanaBlockChain;
|
||||||
import com.r35157.libs.solana.SolanaProgramAccountMemcmpFilter;
|
import com.r35157.libs.solana.SolanaProgramAccountMemcmpFilter;
|
||||||
import com.r35157.libs.solana.SolanaSignedTransaction;
|
|
||||||
import com.r35157.libs.solana.SolanaUnsignedTransaction;
|
import com.r35157.libs.solana.SolanaUnsignedTransaction;
|
||||||
import com.r35157.libs.valuetypes.basic.MoneyAmount;
|
import com.r35157.libs.valuetypes.basic.MoneyAmount;
|
||||||
import com.r35157.libs.valuetypes.basic.WellKnownCurrencyTypes;
|
import com.r35157.libs.valuetypes.basic.WellKnownCurrencyTypes;
|
||||||
@@ -133,10 +130,7 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService {
|
|||||||
maxSlippageBps
|
maxSlippageBps
|
||||||
);
|
);
|
||||||
|
|
||||||
SolanaSignedTransaction signedTransaction =
|
return wallet.signAndSendTransaction(unsignedTransaction);
|
||||||
wallet.signTransaction(unsignedTransaction);
|
|
||||||
|
|
||||||
return executePositionIncreaseTransaction(signedTransaction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NotNull SolanaUnsignedTransaction buildPositionIncreaseTransaction(
|
private @NotNull SolanaUnsignedTransaction buildPositionIncreaseTransaction(
|
||||||
@@ -189,36 +183,6 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NotNull ΩSolanaTransactionSignatureΩ
|
|
||||||
executePositionIncreaseTransaction(
|
|
||||||
@NotNull SolanaSignedTransaction transaction
|
|
||||||
) throws IOException, InterruptedException {
|
|
||||||
if (transaction.serializedTransaction() == null
|
|
||||||
|| transaction.serializedTransaction().isBlank()) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Signed transaction must not be blank"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecuteTransactionRequest request =
|
|
||||||
new ExecuteTransactionRequest(
|
|
||||||
"increase-position",
|
|
||||||
transaction.serializedTransaction()
|
|
||||||
);
|
|
||||||
|
|
||||||
ExecuteTransactionResponse response =
|
|
||||||
requestTransactionExecution(request);
|
|
||||||
|
|
||||||
if (response.txid() == null || response.txid().isBlank()) {
|
|
||||||
throw new IOException(
|
|
||||||
"Jupiter transaction execution response did not "
|
|
||||||
+ "contain a transaction signature"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.txid();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ΩSolanaTransactionSignatureΩ executePositionDecrease(
|
public @NotNull ΩSolanaTransactionSignatureΩ executePositionDecrease(
|
||||||
@NotNull SolanaWallet wallet,
|
@NotNull SolanaWallet wallet,
|
||||||
@@ -235,10 +199,7 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService {
|
|||||||
maxSlippageBps
|
maxSlippageBps
|
||||||
);
|
);
|
||||||
|
|
||||||
SolanaSignedTransaction signedTransaction =
|
return wallet.signAndSendTransaction(unsignedTransaction);
|
||||||
wallet.signTransaction(unsignedTransaction);
|
|
||||||
|
|
||||||
return executePositionDecreaseTransaction(signedTransaction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NotNull SolanaUnsignedTransaction buildPositionDecreaseTransaction(
|
private @NotNull SolanaUnsignedTransaction buildPositionDecreaseTransaction(
|
||||||
@@ -287,36 +248,6 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NotNull ΩSolanaTransactionSignatureΩ
|
|
||||||
executePositionDecreaseTransaction(
|
|
||||||
@NotNull SolanaSignedTransaction transaction
|
|
||||||
) throws IOException, InterruptedException {
|
|
||||||
if (transaction.serializedTransaction() == null
|
|
||||||
|| transaction.serializedTransaction().isBlank()) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Signed transaction must not be blank"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecuteTransactionRequest request =
|
|
||||||
new ExecuteTransactionRequest(
|
|
||||||
"decrease-position",
|
|
||||||
transaction.serializedTransaction()
|
|
||||||
);
|
|
||||||
|
|
||||||
ExecuteTransactionResponse response =
|
|
||||||
requestTransactionExecution(request);
|
|
||||||
|
|
||||||
if (response.txid() == null || response.txid().isBlank()) {
|
|
||||||
throw new IOException(
|
|
||||||
"Jupiter transaction execution response did not "
|
|
||||||
+ "contain a transaction signature"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.txid();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DecreasePositionRequest buildDecreasePositionRequest(
|
private static DecreasePositionRequest buildDecreasePositionRequest(
|
||||||
ΩJupiterPerpsPositionAccountΩ positionAccount,
|
ΩJupiterPerpsPositionAccountΩ positionAccount,
|
||||||
ΩSPLMintAddressΩ receiveTokenMint,
|
ΩSPLMintAddressΩ receiveTokenMint,
|
||||||
@@ -743,51 +674,11 @@ public class AnchorIdlJupiterPerpsServiceImpl implements JupiterPerpsService {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ExecuteTransactionResponse requestTransactionExecution(
|
|
||||||
ExecuteTransactionRequest request
|
|
||||||
) throws IOException, InterruptedException {
|
|
||||||
String requestJson =
|
|
||||||
OBJECT_MAPPER.writeValueAsString(request);
|
|
||||||
|
|
||||||
HttpRequest httpRequest = HttpRequest.newBuilder()
|
|
||||||
.uri(EXECUTE_TRANSACTION_ENDPOINT)
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.header("Accept", "application/json")
|
|
||||||
.header("x-client-platform", "nenjim-hub")
|
|
||||||
.POST(HttpRequest.BodyPublishers.ofString(requestJson))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
HttpResponse<String> httpResponse = HTTP_CLIENT.send(
|
|
||||||
httpRequest,
|
|
||||||
HttpResponse.BodyHandlers.ofString()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (httpResponse.statusCode() < 200
|
|
||||||
|| httpResponse.statusCode() >= 300) {
|
|
||||||
throw new IOException(
|
|
||||||
"Jupiter transaction execution failed with HTTP "
|
|
||||||
+ httpResponse.statusCode()
|
|
||||||
+ ": "
|
|
||||||
+ httpResponse.body()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return OBJECT_MAPPER.readValue(
|
|
||||||
httpResponse.body(),
|
|
||||||
ExecuteTransactionResponse.class
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final ΩSPLMintAddressΩ BTC_MINT = "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh";
|
private static final ΩSPLMintAddressΩ BTC_MINT = "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh";
|
||||||
private static final ΩSPLMintAddressΩ ETH_MINT = "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs";
|
private static final ΩSPLMintAddressΩ ETH_MINT = "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs";
|
||||||
private static final ΩSPLMintAddressΩ SOL_MINT = "So11111111111111111111111111111111111111112";
|
private static final ΩSPLMintAddressΩ SOL_MINT = "So11111111111111111111111111111111111111112";
|
||||||
private static final ΩSPLMintAddressΩ USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
private static final ΩSPLMintAddressΩ USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
||||||
|
|
||||||
private static final URI EXECUTE_TRANSACTION_ENDPOINT =
|
|
||||||
URI.create(
|
|
||||||
"https://perps-api.jup.ag/v2/transaction/execute"
|
|
||||||
);
|
|
||||||
|
|
||||||
private static final URI DECREASE_POSITION_ENDPOINT =
|
private static final URI DECREASE_POSITION_ENDPOINT =
|
||||||
URI.create(
|
URI.create(
|
||||||
"https://perps-api.jup.ag/v2/positions/decrease"
|
"https://perps-api.jup.ag/v2/positions/decrease"
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
package com.r35157.libs.jupiter.perps.protocol;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Jupiter Perps protocol request for executing a signed transaction.
|
|
||||||
*
|
|
||||||
* @param action the Jupiter transaction action
|
|
||||||
* @param serializedTxBase64 the complete signed Solana transaction,
|
|
||||||
* encoded as Base64
|
|
||||||
*/
|
|
||||||
public record ExecuteTransactionRequest(
|
|
||||||
String action,
|
|
||||||
String serializedTxBase64
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
package com.r35157.libs.jupiter.perps.protocol;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Relevant fields returned by Jupiter after executing a transaction.
|
|
||||||
*
|
|
||||||
* @param txid the Solana transaction signature
|
|
||||||
*/
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
|
||||||
public record ExecuteTransactionResponse(
|
|
||||||
String txid
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user