Add configurable Jupiter Perps position decrease alarm action #39

Closed
opened 2026-07-24 16:04:53 +02:00 by minimons · 0 comments
Owner

Background

Issue #38 added and verified end-to-end support for decreasing an existing Jupiter Perps position through:

  • JupiterPerpsService.buildPositionDecreaseTransaction(...)
  • JupiterPerpsService.executePositionDecreaseTransaction(...)

The alarm application already supports automatic position increases through:

  • JupiterPerpsPositionIncreaseAlarmAction
  • JupiterPerpsPositionIncreaseAlarmActionConfiguration
  • JupiterPerpsPositionIncreaseAlarmActionConfigurationParser
  • alarmaction_JupiterPerpsPositionIncreaseAlarmAction.conf

We need an equivalent configurable alarm action for decreasing existing positions.

The new implementation should follow the existing position-increase action architecture and behavior as closely as possible.

Configuration

Add a new configuration file:

alarmaction_JupiterPerpsPositionDecreaseAlarmAction.conf

and an example file:

conf/alarmaction_JupiterPerpsPositionDecreaseAlarmAction.conf.example

Suggested format:

# Wallet and signer used for position-decrease transactions
################################################################
WALLET_ID        {{JUPITER_PERPS_WALLET}}
SIGNER_KEY_NAME  <SIGNER>


# ID  ASSET  DIRECTION  RECEIVE_TOKEN  SIZE_DELTA_USD  MAX_SLIPPAGE_BPS
############################################################################
# Values may reference {{VARIABLES}} defined in alarms.conf.
#3   SOL    SHORT      USDC           5.00            200
#6   SOL    LONG       USDC           5.00            200

Supported values:

  • ID: the alarm ID from alarms.conf.
  • ASSET: SOL, ETH, or BTC.
  • DIRECTION: LONG or SHORT.
  • RECEIVE_TOKEN: USDC or the same token as ASSET.
  • SIZE_DELTA_USD: the amount by which the position should be reduced; must be greater than zero.
  • MAX_SLIPPAGE_BPS: an integer from 0 to 10000.

The wallet and signer should be resolved during startup.

All transaction-row values should be validated during startup and resolved again whenever the alarm triggers, matching the behavior of the existing position-increase action.

Duplicate alarm IDs must be rejected.

An alarm ID absent from this configuration must not perform a decrease transaction.

Configuration model and parser

Add:

  • JupiterPerpsPositionDecreaseAlarmActionConfiguration
  • JupiterPerpsPositionDecreaseAlarmActionConfigurationParser

The configuration model should mirror the existing increase configuration and contain:

  • walletId
  • signerKeyName
  • Map<Integer, PositionDecrease> positionDecreases

A PositionDecrease should retain the unresolved expressions:

  • assetExpression
  • directionExpression
  • receiveTokenExpression
  • sizeUsdDeltaExpression
  • maxSlippageBpsExpression

Resolving it should produce a typed ResolvedPositionDecrease.

A receive-token representation may be added to map SOL, BTC, ETH, and USDC to their corresponding SPL mint addresses.

Startup validation should reject:

  • Missing or blank wallet IDs
  • Missing or blank signer-key names
  • Duplicate alarm IDs
  • Unknown assets
  • Unknown directions
  • Unknown receive tokens
  • A receive token other than USDC or the position's traded asset
  • A size delta that is zero or negative
  • Slippage outside 0..10000
  • Invalid or unresolved variables
  • Incorrect column counts

Parser errors should include the configuration path and line number, matching the existing increase parser.

Alarm action

Add:

JupiterPerpsPositionDecreaseAlarmAction

It should implement ConfiguredAlarmAction and use the same constructor dependencies as JupiterPerpsPositionIncreaseAlarmAction:

  • Configuration directory
  • SolanaBlockChain
  • JupiterPerpsService
  • AlarmVariableResolver

getConfigurationFileName() should return:

alarmaction_JupiterPerpsPositionDecreaseAlarmAction.conf

When an alarm triggers, the action should:

  1. Look up the configured PositionDecrease by alarm ID.
  2. Return without doing anything if the alarm ID is not configured.
  3. Resolve the definition using the current AlarmVariableResolver.
  4. Fetch the wallet's current open positions through JupiterPerpsService.getOpenPositions(...).
  5. Find the position matching the configured asset and direction.
  6. Require exactly one matching open position.
  7. Use its positionAccount when calling buildPositionDecreaseTransaction(...).
  8. Sign the unsigned transaction using the configured SolanaWallet.
  9. Submit it through executePositionDecreaseTransaction(...).
  10. Log the returned Solana transaction signature.

The position account should be resolved dynamically instead of stored in the configuration. This allows the action to continue working when a position is closed and later reopened.

If no matching position exists, or more than one position matches the configured asset and direction, the action must fail safely without signing or submitting a transaction.

The transaction flow should be:

SolanaUnsignedTransaction unsignedTransaction =
        jupiter.buildPositionDecreaseTransaction(
                position.positionAccount(),
                resolvedDecrease.receiveTokenMint(),
                resolvedDecrease.sizeUsdDelta(),
                resolvedDecrease.maxSlippageBps()
        );

SolanaSignedTransaction signedTransaction =
        wallet.signTransaction(unsignedTransaction);

ΩSolanaTransactionSignatureΩ signature =
        jupiter.executePositionDecreaseTransaction(signedTransaction);

Runtime failures should be logged and isolated so the remaining configured alarm actions can still run.

Application integration

Register JupiterPerpsPositionDecreaseAlarmAction in the CompositeAlarmAction list created by JupiterPerpsAlarmImpl.

It should reuse the existing:

  • Configuration directory
  • Cached SolanaBlockChain
  • JupiterPerpsService
  • AlarmVariableResolver

As with the other configured actions, its configuration should be parsed and validated before WebSocket monitoring begins.

Documentation

Update README_alarm.md to document:

  • The new action configuration file
  • Its configuration columns and supported values
  • Dynamic resolution of the position account
  • Startup and trigger-time variable resolution
  • The fact that active rows sign and submit real Jupiter Perps transactions
  • The requirement that RECEIVE_TOKEN is USDC or the position's traded asset
  • Safe failure when no unique matching position can be found
  • The new example configuration file

Update references to the number of required configuration and action files.

Out of scope

This issue does not include:

  • Closing an entire position
  • Closing all positions
  • Changes to alarm-condition or trigger behavior
  • Retry or transaction-idempotency mechanisms
  • Changes to the Jupiter Perps decrease API added in issue #38
  • Changes to wallet signing

Acceptance criteria

  • The project compiles successfully.
  • The new decrease configuration and parser follow the existing increase-action structure.
  • Configuration values may reference shared alarm variables.
  • Invalid configuration fails during startup before WebSockets are opened.
  • An unconfigured alarm ID performs no decrease.
  • A configured alarm dynamically finds the matching open position by asset and direction.
  • Missing or ambiguous matching positions fail without signing or submitting.
  • A configured alarm can build, sign, and execute a partial position decrease.
  • The resulting Solana transaction signature is logged.
  • Existing console, Pushover, and position-increase actions continue to work.
  • Example configuration and alarm documentation are updated.
## Background Issue #38 added and verified end-to-end support for decreasing an existing Jupiter Perps position through: * `JupiterPerpsService.buildPositionDecreaseTransaction(...)` * `JupiterPerpsService.executePositionDecreaseTransaction(...)` The alarm application already supports automatic position increases through: * `JupiterPerpsPositionIncreaseAlarmAction` * `JupiterPerpsPositionIncreaseAlarmActionConfiguration` * `JupiterPerpsPositionIncreaseAlarmActionConfigurationParser` * `alarmaction_JupiterPerpsPositionIncreaseAlarmAction.conf` We need an equivalent configurable alarm action for decreasing existing positions. The new implementation should follow the existing position-increase action architecture and behavior as closely as possible. ## Configuration Add a new configuration file: ```text alarmaction_JupiterPerpsPositionDecreaseAlarmAction.conf ``` and an example file: ```text conf/alarmaction_JupiterPerpsPositionDecreaseAlarmAction.conf.example ``` Suggested format: ```text # Wallet and signer used for position-decrease transactions ################################################################ WALLET_ID {{JUPITER_PERPS_WALLET}} SIGNER_KEY_NAME <SIGNER> # ID ASSET DIRECTION RECEIVE_TOKEN SIZE_DELTA_USD MAX_SLIPPAGE_BPS ############################################################################ # Values may reference {{VARIABLES}} defined in alarms.conf. #3 SOL SHORT USDC 5.00 200 #6 SOL LONG USDC 5.00 200 ``` Supported values: * `ID`: the alarm ID from `alarms.conf`. * `ASSET`: `SOL`, `ETH`, or `BTC`. * `DIRECTION`: `LONG` or `SHORT`. * `RECEIVE_TOKEN`: `USDC` or the same token as `ASSET`. * `SIZE_DELTA_USD`: the amount by which the position should be reduced; must be greater than zero. * `MAX_SLIPPAGE_BPS`: an integer from `0` to `10000`. The wallet and signer should be resolved during startup. All transaction-row values should be validated during startup and resolved again whenever the alarm triggers, matching the behavior of the existing position-increase action. Duplicate alarm IDs must be rejected. An alarm ID absent from this configuration must not perform a decrease transaction. ## Configuration model and parser Add: * `JupiterPerpsPositionDecreaseAlarmActionConfiguration` * `JupiterPerpsPositionDecreaseAlarmActionConfigurationParser` The configuration model should mirror the existing increase configuration and contain: * `walletId` * `signerKeyName` * `Map<Integer, PositionDecrease> positionDecreases` A `PositionDecrease` should retain the unresolved expressions: * `assetExpression` * `directionExpression` * `receiveTokenExpression` * `sizeUsdDeltaExpression` * `maxSlippageBpsExpression` Resolving it should produce a typed `ResolvedPositionDecrease`. A receive-token representation may be added to map `SOL`, `BTC`, `ETH`, and `USDC` to their corresponding SPL mint addresses. Startup validation should reject: * Missing or blank wallet IDs * Missing or blank signer-key names * Duplicate alarm IDs * Unknown assets * Unknown directions * Unknown receive tokens * A receive token other than USDC or the position's traded asset * A size delta that is zero or negative * Slippage outside `0..10000` * Invalid or unresolved variables * Incorrect column counts Parser errors should include the configuration path and line number, matching the existing increase parser. ## Alarm action Add: ```text JupiterPerpsPositionDecreaseAlarmAction ``` It should implement `ConfiguredAlarmAction` and use the same constructor dependencies as `JupiterPerpsPositionIncreaseAlarmAction`: * Configuration directory * `SolanaBlockChain` * `JupiterPerpsService` * `AlarmVariableResolver` `getConfigurationFileName()` should return: ```text alarmaction_JupiterPerpsPositionDecreaseAlarmAction.conf ``` When an alarm triggers, the action should: 1. Look up the configured `PositionDecrease` by alarm ID. 2. Return without doing anything if the alarm ID is not configured. 3. Resolve the definition using the current `AlarmVariableResolver`. 4. Fetch the wallet's current open positions through `JupiterPerpsService.getOpenPositions(...)`. 5. Find the position matching the configured asset and direction. 6. Require exactly one matching open position. 7. Use its `positionAccount` when calling `buildPositionDecreaseTransaction(...)`. 8. Sign the unsigned transaction using the configured `SolanaWallet`. 9. Submit it through `executePositionDecreaseTransaction(...)`. 10. Log the returned Solana transaction signature. The position account should be resolved dynamically instead of stored in the configuration. This allows the action to continue working when a position is closed and later reopened. If no matching position exists, or more than one position matches the configured asset and direction, the action must fail safely without signing or submitting a transaction. The transaction flow should be: ```java SolanaUnsignedTransaction unsignedTransaction = jupiter.buildPositionDecreaseTransaction( position.positionAccount(), resolvedDecrease.receiveTokenMint(), resolvedDecrease.sizeUsdDelta(), resolvedDecrease.maxSlippageBps() ); SolanaSignedTransaction signedTransaction = wallet.signTransaction(unsignedTransaction); ΩSolanaTransactionSignatureΩ signature = jupiter.executePositionDecreaseTransaction(signedTransaction); ``` Runtime failures should be logged and isolated so the remaining configured alarm actions can still run. ## Application integration Register `JupiterPerpsPositionDecreaseAlarmAction` in the `CompositeAlarmAction` list created by `JupiterPerpsAlarmImpl`. It should reuse the existing: * Configuration directory * Cached `SolanaBlockChain` * `JupiterPerpsService` * `AlarmVariableResolver` As with the other configured actions, its configuration should be parsed and validated before WebSocket monitoring begins. ## Documentation Update `README_alarm.md` to document: * The new action configuration file * Its configuration columns and supported values * Dynamic resolution of the position account * Startup and trigger-time variable resolution * The fact that active rows sign and submit real Jupiter Perps transactions * The requirement that `RECEIVE_TOKEN` is USDC or the position's traded asset * Safe failure when no unique matching position can be found * The new example configuration file Update references to the number of required configuration and action files. ## Out of scope This issue does not include: * Closing an entire position * Closing all positions * Changes to alarm-condition or trigger behavior * Retry or transaction-idempotency mechanisms * Changes to the Jupiter Perps decrease API added in issue #38 * Changes to wallet signing ## Acceptance criteria * The project compiles successfully. * The new decrease configuration and parser follow the existing increase-action structure. * Configuration values may reference shared alarm variables. * Invalid configuration fails during startup before WebSockets are opened. * An unconfigured alarm ID performs no decrease. * A configured alarm dynamically finds the matching open position by asset and direction. * Missing or ambiguous matching positions fail without signing or submitting. * A configured alarm can build, sign, and execute a partial position decrease. * The resulting Solana transaction signature is logged. * Existing console, Pushover, and position-increase actions continue to work. * Example configuration and alarm documentation are updated.
minimons added the enhancement label 2026-07-25 11:08:26 +02:00
minimons added this to the Evelyn project 2026-07-25 11:08:32 +02:00
minimons self-assigned this 2026-07-25 11:08:37 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: r35157/com_r35157_nenjim-hubd-impl_ref#39