43: Prevent Position Decrease from reducing a position below a configured size reserve
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
# Wallet and signer used for position-decrease transactions
|
||||
################################################################
|
||||
WALLET_ID {{JUPITER_PERPS_WALLET}}
|
||||
SIGNER_KEY_NAME <SIGNER>
|
||||
|
||||
WALLET_ID {{JUPITER_PERPS_WALLET}}
|
||||
SIGNER_KEY_NAME <SIGNER>
|
||||
RESERVE_POSITION_SIZE_USD_LIMIT 10
|
||||
|
||||
# Id Asset Direction ReceiveToken SizeDeltaUSD MaxSlippageBPS
|
||||
########################################################################
|
||||
|
||||
+40
@@ -9,6 +9,7 @@ import com.r35157.libs.solana.SolanaSignedTransaction;
|
||||
import com.r35157.libs.solana.SolanaUnsignedTransaction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -68,6 +69,10 @@ public final class JupiterPerpsPositionDecreaseAlarmAction
|
||||
JupiterPerpsPosition position =
|
||||
findOpenPosition(positionDecrease);
|
||||
|
||||
if (!isPositionSizeOk(position, positionDecrease)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SolanaUnsignedTransaction utrans =
|
||||
jupiter.buildPositionDecreaseTransaction(
|
||||
position.positionAccount(),
|
||||
@@ -76,8 +81,10 @@ public final class JupiterPerpsPositionDecreaseAlarmAction
|
||||
positionDecrease.sizeUsdDelta(),
|
||||
positionDecrease.maxSlippageBps()
|
||||
);
|
||||
|
||||
SolanaSignedTransaction strans =
|
||||
wallet.signTransaction(utrans);
|
||||
|
||||
ΩSolanaTransactionSignatureΩ signature =
|
||||
jupiter.executePositionDecreaseTransaction(strans);
|
||||
|
||||
@@ -135,6 +142,39 @@ public final class JupiterPerpsPositionDecreaseAlarmAction
|
||||
return matchingPosition;
|
||||
}
|
||||
|
||||
private boolean isPositionSizeOk(
|
||||
JupiterPerpsPosition position,
|
||||
JupiterPerpsPositionDecreaseAlarmActionConfiguration
|
||||
.ResolvedPositionDecrease positionDecrease
|
||||
) {
|
||||
ΩUSDCAmountΩ currentPositionSize = position.positionSize();
|
||||
ΩUSDCAmountΩ decreaseSizeUsd = positionDecrease.sizeUsdDelta();
|
||||
ΩUSDCAmountΩ reservePositionSizeUsdLimit =
|
||||
configuration.reservePositionSizeUsdLimit();
|
||||
|
||||
ΩUSDCAmountΩ remainingPositionSize =
|
||||
currentPositionSize.subtract(decreaseSizeUsd);
|
||||
|
||||
if (remainingPositionSize.compareTo(
|
||||
reservePositionSizeUsdLimit
|
||||
) < 0) {
|
||||
System.err.println(
|
||||
"Position Decrease of "
|
||||
+ decreaseSizeUsd
|
||||
+ " USD skipped: Position size is "
|
||||
+ currentPositionSize
|
||||
+ " USD and would become "
|
||||
+ remainingPositionSize
|
||||
+ " USD, which is below the "
|
||||
+ reservePositionSizeUsdLimit
|
||||
+ " USD reserve."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private final JupiterPerpsPositionDecreaseAlarmActionConfiguration
|
||||
configuration;
|
||||
private final SolanaWallet wallet;
|
||||
|
||||
+10
@@ -10,11 +10,21 @@ import java.util.Objects;
|
||||
public record JupiterPerpsPositionDecreaseAlarmActionConfiguration(
|
||||
ΩSolanaWalletIdΩ walletId,
|
||||
String signerKeyName,
|
||||
ΩUSDCAmountΩ reservePositionSizeUsdLimit,
|
||||
Map<Integer, PositionDecrease> positionDecreases
|
||||
) {
|
||||
public JupiterPerpsPositionDecreaseAlarmActionConfiguration {
|
||||
Objects.requireNonNull(walletId, "walletId");
|
||||
Objects.requireNonNull(signerKeyName, "signerKeyName");
|
||||
Objects.requireNonNull(reservePositionSizeUsdLimit, "reservePositionSizeUsdLimit");
|
||||
|
||||
if (reservePositionSizeUsdLimit.signum() < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Position size USD reserve limit cannot be negative: "
|
||||
+ reservePositionSizeUsdLimit
|
||||
);
|
||||
}
|
||||
|
||||
positionDecreases = Map.copyOf(positionDecreases);
|
||||
|
||||
if (walletId.isBlank()) {
|
||||
|
||||
+23
@@ -1,6 +1,7 @@
|
||||
package com.r35157.jupiterperpsalarm.impl.ref;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -20,6 +21,7 @@ public final class JupiterPerpsPositionDecreaseAlarmActionConfigurationParser {
|
||||
positionDecreases = new LinkedHashMap<>();
|
||||
ΩSolanaWalletIdΩ walletId = null;
|
||||
String signerKeyName = null;
|
||||
ΩUSDCAmountΩ reservePositionSizeUsdLimit = null;
|
||||
|
||||
for (int lineNumber = 1; lineNumber <= lines.size(); lineNumber++) {
|
||||
String line = removeComment(lines.get(lineNumber - 1)).trim();
|
||||
@@ -51,6 +53,20 @@ public final class JupiterPerpsPositionDecreaseAlarmActionConfigurationParser {
|
||||
);
|
||||
}
|
||||
signerKeyName = variableResolver.resolve(columns[1]);
|
||||
} else if (firstColumn.equals("RESERVE_POSITION_SIZE_USD_LIMIT")) {
|
||||
requireColumnCount(
|
||||
columns,
|
||||
2,
|
||||
"RESERVE_POSITION_SIZE_USD_LIMIT value"
|
||||
);
|
||||
if (reservePositionSizeUsdLimit != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Duplicate RESERVE_POSITION_SIZE_USD_LIMIT"
|
||||
);
|
||||
}
|
||||
reservePositionSizeUsdLimit = new ΩUSDCAmountΩ(
|
||||
variableResolver.resolve(columns[1])
|
||||
);
|
||||
} else {
|
||||
parsePositionDecrease(
|
||||
columns,
|
||||
@@ -78,9 +94,16 @@ public final class JupiterPerpsPositionDecreaseAlarmActionConfigurationParser {
|
||||
);
|
||||
}
|
||||
|
||||
if (reservePositionSizeUsdLimit == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Missing RESERVE_POSITION_SIZE_USD_LIMIT in " + path
|
||||
);
|
||||
}
|
||||
|
||||
return new JupiterPerpsPositionDecreaseAlarmActionConfiguration(
|
||||
walletId,
|
||||
signerKeyName,
|
||||
reservePositionSizeUsdLimit,
|
||||
positionDecreases
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user