X: Clean-up and documentation updates
This commit is contained in:
+135
-48
@@ -4,28 +4,39 @@ The Jupiter Perps Price Alarm monitors the Jupiter Perps aggregated oracle accou
|
||||
|
||||
Oracle prices are received through Solana WebSocket `accountSubscribe` using `processed` commitment. The application does not poll prices once per second. It also fetches the current oracle account state whenever a WebSocket connection opens, reconnects automatically, and supports multiple RPC endpoints for redundancy.
|
||||
|
||||
The alarm is currently initialized and started by `NenjimHubImpl`. Its
|
||||
`SolanaWallet` and `JupiterPerpsService` are selected by the Hub and injected
|
||||
before startup. The alarm action configuration files do not select a wallet or
|
||||
signing key.
|
||||
|
||||
> **Important:** This application is not necessarily notification-only. Every active entry in a Jupiter Perps position action file can sign and submit a real transaction. Review both transaction action files before running it.
|
||||
|
||||
## Startup flow
|
||||
|
||||
The application performs the following steps before it starts monitoring prices:
|
||||
The alarm performs the following steps before it starts monitoring prices:
|
||||
|
||||
1. Parse command-line options and the alarm configuration file.
|
||||
2. Fetch the wallet's current open Jupiter Perps positions.
|
||||
3. Populate entry-price and liquidation-price variables.
|
||||
1. Parse the configured alarm path, WebSocket endpoint environment and
|
||||
`alarms.conf`.
|
||||
2. Parse the position-increase and position-decrease action files, including
|
||||
their structure and reserve settings.
|
||||
3. Fetch the injected wallet's current open Jupiter Perps positions and populate
|
||||
entry-price and liquidation-price variables.
|
||||
4. Resolve and validate every alarm condition.
|
||||
5. Start the periodic variable refresher and file-trigger watcher.
|
||||
6. Parse and validate the four action configuration files.
|
||||
6. Parse the console and Pushover action files and construct all alarm actions.
|
||||
7. Open one oracle WebSocket connection per configured asset and RPC endpoint.
|
||||
|
||||
Startup fails before WebSockets are opened if an alarm condition or action configuration contains an unresolved variable or invalid value.
|
||||
Startup fails before WebSockets are opened if an alarm condition or an action
|
||||
value that is resolved during startup contains an unavailable variable or
|
||||
invalid value. Jupiter transaction-row expressions are resolved and validated
|
||||
when their alarm triggers.
|
||||
|
||||
## Requirements and build
|
||||
|
||||
The project uses:
|
||||
|
||||
- JDK 25
|
||||
- Gradle 9.3.1 through the Gradle wrapper
|
||||
- Gradle 9.6.1 through the Gradle wrapper
|
||||
- Java preview features
|
||||
- Detag-generated Java sources from `src/main/tjava`
|
||||
|
||||
@@ -43,35 +54,45 @@ To create the application JAR and collect runtime dependencies in `build/libs`:
|
||||
|
||||
There is currently no alarm-specific automated self-test task.
|
||||
|
||||
## Running the alarm application
|
||||
## Running through Nenjim
|
||||
|
||||
The alarm entry point is:
|
||||
The alarm no longer has a standalone `main` method. `NenjimHubImpl` constructs
|
||||
the wallet, Jupiter service and alarm, then starts the alarm as part of normal
|
||||
Hub startup. Run the configured application with:
|
||||
|
||||
```text
|
||||
com.r35157.jupiterperpsalarm.impl.ref.JupiterPerpsAlarmImpl
|
||||
```bash
|
||||
./gradlew run
|
||||
```
|
||||
|
||||
The Gradle application plugin currently points at the Nenjim Hub main class, so `./gradlew run` does **not** directly start the alarm application. Run `JupiterPerpsAlarmImpl` from the IDE, or run the prepared JAR and dependencies explicitly:
|
||||
After `./gradlew prepareLibs`, it can also be started explicitly with the Nenjim
|
||||
Hub main class:
|
||||
|
||||
```bash
|
||||
java --enable-preview \
|
||||
-cp "build/libs/*" \
|
||||
com.r35157.jupiterperpsalarm.impl.ref.JupiterPerpsAlarmImpl \
|
||||
--config=conf/alarms.conf
|
||||
com.r35157.nenjim.hubd.impl.ref.Main
|
||||
```
|
||||
|
||||
The repository contains example files for the alarm configuration and every action configuration. The real `conf/*.conf` files are ignored by Git; keep credentials and operational wallet details out of version control.
|
||||
The current Hub composition binds the alarm to `conf/alarms.conf` and to the
|
||||
test Jupiter Perps wallet and service. Until Nenjim provides configured
|
||||
injection, a different configuration or wallet must be selected in the Hub's
|
||||
composition code, not in an alarm action file.
|
||||
|
||||
### Command-line options and environment variables
|
||||
The repository contains example files for the alarm configuration and every
|
||||
action configuration. The real `conf/*.conf` files are ignored by Git; keep
|
||||
credentials and operational details out of version control.
|
||||
|
||||
| Purpose | Command-line option | Environment variable | Default |
|
||||
|---|---|---|---|
|
||||
| Alarm configuration | `--config=<path>` | `PRICE_ALARMS_CONFIG` | `price-alarms.conf` |
|
||||
| Solana WebSocket endpoints | `--ws=<url1,url2,...>` | `SOLANA_WS_URLS` | `wss://api.mainnet-beta.solana.com` |
|
||||
### Environment variables
|
||||
|
||||
The command-line option takes precedence over its environment variable.
|
||||
The Hub does not currently forward alarm-specific command-line options. Solana
|
||||
WebSocket endpoints can be overridden with:
|
||||
|
||||
The variable-refresh file watcher uses the configuration file's parent directory. Until that is changed, use a configuration path with an explicit directory component, such as `conf/alarms.conf` or `./price-alarms.conf`, rather than relying on the bare default filename.
|
||||
```bash
|
||||
export SOLANA_WS_URLS='wss://first-provider.example,wss://second-provider.example'
|
||||
```
|
||||
|
||||
If `SOLANA_WS_URLS` is absent, the alarm uses
|
||||
`wss://api.mainnet-beta.solana.com`.
|
||||
|
||||
## Configuration files
|
||||
|
||||
@@ -79,11 +100,11 @@ The application uses five configuration files:
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `alarms.conf` | Variables and price-alarm definitions |
|
||||
| `alarms.conf` | Shared variables and price-alarm definitions |
|
||||
| `alarmaction_Console.conf` | Alarm IDs written to the console |
|
||||
| `alarmaction_Pushover.conf` | Pushover credentials and notifications |
|
||||
| `alarmaction_JupiterPerpsPositionIncreaseAlarmAction.conf` | Jupiter wallet, signer, and position increases |
|
||||
| `alarmaction_JupiterPerpsPositionDecreaseAlarmAction.conf` | Jupiter wallet, signer, and position decreases |
|
||||
| `alarmaction_JupiterPerpsPositionIncreaseAlarmAction.conf` | USDC reserve and position increases |
|
||||
| `alarmaction_JupiterPerpsPositionDecreaseAlarmAction.conf` | Position-size reserve and position decreases |
|
||||
|
||||
The four action files are resolved in the same directory as the file supplied through `--config`. All five files are required at startup, although an action can contain no alarm IDs. Blank lines and lines beginning with `#` are ignored.
|
||||
|
||||
@@ -97,12 +118,16 @@ Example files:
|
||||
|
||||
### Format version
|
||||
|
||||
Every configuration file must declare its format version as its first actual
|
||||
configuration entry:
|
||||
Every configuration file must declare its own format version as its first
|
||||
actual configuration entry:
|
||||
|
||||
```text
|
||||
FORMAT_VERSION=1
|
||||
```
|
||||
| File | Format version |
|
||||
|---|---:|
|
||||
| `alarms.conf` | `2` |
|
||||
| `alarmaction_Console.conf` | `1` |
|
||||
| `alarmaction_Pushover.conf` | `1` |
|
||||
| `alarmaction_JupiterPerpsPositionIncreaseAlarmAction.conf` | `2` |
|
||||
| `alarmaction_JupiterPerpsPositionDecreaseAlarmAction.conf` | `2` |
|
||||
|
||||
Blank lines and full-line comments may appear before it. The application
|
||||
rejects a missing, duplicate, malformed, misplaced, older, or newer version
|
||||
@@ -121,12 +146,15 @@ the project-wide policy.
|
||||
Variable definitions live in `alarms.conf`. A definition consists of a name and a single-token value:
|
||||
|
||||
```text
|
||||
{{JUPITER_PERPS_WALLET}} vj98roDZ7744EBfxyuDFkKpEGCsKQLr7K8UFRumJNHf
|
||||
{{SOL_WARNING_PRICE}} 150.00
|
||||
```
|
||||
|
||||
Variable names must use uppercase letters, digits, and underscores. User-defined variables can be referenced from alarm conditions and action configuration values as `{{NAME}}`.
|
||||
|
||||
`JUPITER_PERPS_WALLET` is required for the initial and periodic Jupiter position fetches. For open SOL, BTC, and ETH positions, the refresher supplies these dynamic variables:
|
||||
The wallet address used for initial and periodic Jupiter position fetches comes
|
||||
from the injected `SolanaWallet`; it is not a shared configuration variable.
|
||||
For open SOL, BTC, and ETH positions belonging to that wallet, the refresher
|
||||
supplies these dynamic variables:
|
||||
|
||||
```text
|
||||
{{SOL_LONG_ENTRY_PRICE}} {{SOL_LONG_LIQ_PRICE}}
|
||||
@@ -137,9 +165,17 @@ Variable names must use uppercase letters, digits, and underscores. User-defined
|
||||
{{ETH_SHORT_ENTRY_PRICE}} {{ETH_SHORT_LIQ_PRICE}}
|
||||
```
|
||||
|
||||
The refresher replaces user-supplied variables with these names when position data is fetched. Only variables for positions returned by Jupiter are populated. Startup validation fails if a condition or action value references a variable that is unavailable after the initial position fetch.
|
||||
The refresher replaces user-supplied variables with these names when position
|
||||
data is fetched. Only variables for positions returned by Jupiter are
|
||||
populated. Startup validation fails if an alarm condition references a variable
|
||||
that is unavailable after the initial position fetch. Transaction-row
|
||||
expressions are resolved later, when their alarm triggers.
|
||||
|
||||
Alarm conditions, Pushover notes, and Jupiter position-increase rows are resolved again when an alarm triggers, so refreshed values take effect without restarting the application. Pushover credentials and severity plus the Jupiter wallet and signer are resolved during startup.
|
||||
Alarm conditions, Pushover notes, and Jupiter position-increase and
|
||||
position-decrease rows are resolved again when an alarm triggers, so refreshed
|
||||
values take effect without restarting the application. Pushover credentials
|
||||
and severity are resolved during startup. The wallet and signer belong to the
|
||||
injected `SolanaWallet` and are not resolved from alarm configuration.
|
||||
|
||||
## Alarm definitions
|
||||
|
||||
@@ -362,13 +398,13 @@ Credentials, severity, and notes may reference shared variables. Credentials and
|
||||
|
||||
### Automatic position increase
|
||||
|
||||
`alarmaction_JupiterPerpsPositionIncreaseAlarmAction.conf` contains the wallet and signer followed by zero or more position increases:
|
||||
`alarmaction_JupiterPerpsPositionIncreaseAlarmAction.conf` contains a minimum
|
||||
USDC reserve followed by zero or more position increases:
|
||||
|
||||
```text
|
||||
FORMAT_VERSION=1
|
||||
FORMAT_VERSION=2
|
||||
|
||||
WALLET_ID {{JUPITER_PERPS_WALLET}}
|
||||
SIGNER_KEY_NAME <jup-key-name>
|
||||
RESERVE_USDC_LIMIT 10
|
||||
|
||||
# ID ASSET DIRECTION COLLATERAL_USDC SIZE_DELTA_USD MAX_SLIPPAGE_BPS
|
||||
4 SOL LONG 0.25 2.50 200
|
||||
@@ -382,11 +418,55 @@ Each active row can submit a real transaction when its alarm triggers. Supported
|
||||
- `SIZE_DELTA_USD`: zero or greater.
|
||||
- `MAX_SLIPPAGE_BPS`: from `0` to `10000`.
|
||||
|
||||
Wallet, signer, asset, direction, amounts, and slippage may reference shared variables. Wallet and signer are resolved during startup. Every transaction row is validated during startup and resolved again at trigger time, allowing refreshed variables to change the transaction parameters without a restart.
|
||||
`RESERVE_USDC_LIMIT` is the amount of USDC that must remain after collateral is
|
||||
deducted. An increase is skipped unless the injected wallet's USDC balance can
|
||||
cover both the requested collateral and this reserve.
|
||||
|
||||
For a configured ID, the action builds a Jupiter position-increase transaction, signs it by running `jup sign -f json --key <SIGNER_KEY_NAME> --tx <serialized-transaction>`, verifies that the returned signer matches `WALLET_ID`, and submits the signed transaction. IDs absent from this file never perform a transaction.
|
||||
Asset, direction, amounts, and slippage may reference shared variables. Every
|
||||
transaction row is structurally parsed during startup, then resolved and
|
||||
validated at trigger time. This allows refreshed variables to change the
|
||||
transaction parameters without a restart.
|
||||
|
||||
The example transaction rows are commented out. Do not activate a row until its alarm condition, wallet, signer, asset, direction, amounts, and slippage have been reviewed.
|
||||
For a configured ID, the injected `JupiterPerpsService` builds the position
|
||||
increase, uses its injected wallet to sign it, submits it and awaits the
|
||||
transaction confirmation. IDs absent from this file never perform a
|
||||
transaction.
|
||||
|
||||
The example transaction rows are commented out. Do not activate a row until
|
||||
its alarm condition, injected wallet binding, asset, direction, amounts,
|
||||
reserve, and slippage have been reviewed.
|
||||
|
||||
### Automatic position decrease
|
||||
|
||||
`alarmaction_JupiterPerpsPositionDecreaseAlarmAction.conf` contains a minimum
|
||||
remaining position-size reserve followed by zero or more position decreases:
|
||||
|
||||
```text
|
||||
FORMAT_VERSION=2
|
||||
|
||||
RESERVE_POSITION_SIZE_USD_LIMIT 10
|
||||
|
||||
# ID ASSET DIRECTION RECEIVE_TOKEN SIZE_DELTA_USD MAX_SLIPPAGE_BPS
|
||||
3 SOL SHORT USDC 5.00 200
|
||||
```
|
||||
|
||||
Supported values are:
|
||||
|
||||
- `ASSET`: `SOL`, `ETH`, or `BTC`.
|
||||
- `DIRECTION`: `LONG` or `SHORT`.
|
||||
- `RECEIVE_TOKEN`: `USDC` or the token matching `ASSET`.
|
||||
- `SIZE_DELTA_USD`: greater than zero.
|
||||
- `MAX_SLIPPAGE_BPS`: from `0` to `10000`.
|
||||
|
||||
The action finds the injected wallet's single matching open position. It skips
|
||||
the decrease if the resulting position size would be below
|
||||
`RESERVE_POSITION_SIZE_USD_LIMIT`. Asset, direction, receive token, amount and
|
||||
slippage may reference shared variables and are resolved again at trigger time.
|
||||
|
||||
For a configured ID, the injected `JupiterPerpsService` builds the position
|
||||
decrease, uses its injected wallet to sign it, submits it and awaits the
|
||||
transaction confirmation. IDs absent from this file never perform a
|
||||
transaction.
|
||||
|
||||
## RPC redundancy and reconnect behavior
|
||||
|
||||
@@ -407,7 +487,11 @@ Each connection:
|
||||
|
||||
## Validation and errors
|
||||
|
||||
Structural configuration errors include the file path and line number. After the initial Jupiter position fetch, every condition is resolved and parsed. The action files are then parsed and validated before WebSockets are opened.
|
||||
Structural configuration errors include the file path and line number. The two
|
||||
Jupiter action files are parsed before the initial position fetch. After that
|
||||
fetch, every alarm condition is resolved and parsed, and the console and
|
||||
Pushover files are loaded before WebSockets are opened. Jupiter transaction-row
|
||||
expressions are resolved and validated only when their alarm triggers.
|
||||
|
||||
Startup validation rejects, among other things:
|
||||
|
||||
@@ -418,12 +502,14 @@ Startup validation rejects, among other things:
|
||||
- missing range targets;
|
||||
- negative target values or percentages;
|
||||
- ranges whose lower target exceeds the upper target;
|
||||
- missing action credentials or wallet settings;
|
||||
- missing action credentials or reserve settings;
|
||||
- duplicate action IDs;
|
||||
- invalid Pushover severities;
|
||||
- invalid Jupiter assets, directions, amounts, or slippage.
|
||||
- invalid Pushover severities.
|
||||
|
||||
At runtime, a later condition resolution/parsing failure skips that price event for the affected alarm. A later action-variable failure is logged by the action dispatcher, and the remaining actions are still attempted.
|
||||
At runtime, a later condition resolution/parsing failure skips that price event
|
||||
for the affected alarm. Invalid Jupiter assets, directions, receive tokens,
|
||||
amounts, slippage, or unavailable action variables are logged by the action
|
||||
dispatcher, and the remaining actions are still attempted.
|
||||
|
||||
## Current limitations
|
||||
|
||||
@@ -434,6 +520,7 @@ At runtime, a later condition resolution/parsing failure skips that price event
|
||||
- Target expressions support only a decimal value with an optional single percentage adjustment; they are not a general expression language.
|
||||
- Configuration files are read only during startup; editing an action file requires a restart.
|
||||
- Action IDs are not cross-validated against `alarms.conf`; an unknown ID is accepted but never triggered.
|
||||
- Pushover credentials and severity plus the Jupiter wallet and signer are resolved only during startup. Dynamic re-resolution applies to conditions, Pushover notes, and Jupiter transaction rows.
|
||||
- A bare default configuration path has no parent directory for the refresh watcher; use an explicit path such as `./price-alarms.conf` or `conf/alarms.conf`.
|
||||
- Pushover credentials and severity are resolved only during startup. Dynamic
|
||||
re-resolution applies to conditions, Pushover notes, and Jupiter transaction
|
||||
rows. Wallet and signer selection requires changing the Hub composition.
|
||||
- This application is a monitoring and automation aid, not a substitute for independent risk controls.
|
||||
|
||||
Reference in New Issue
Block a user