72: Add the Evelyn IOU buyback-and-burn service

This commit is contained in:
2026-08-13 16:47:01 +02:00
parent 961f8c69cb
commit 3d5de0e09b
11 changed files with 1790 additions and 8 deletions
@@ -0,0 +1,90 @@
package com.fanitas.evelyn.service.burner;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import java.util.List;
/**
* Continuously buys back and burns Evelyn IOU from a dedicated wallet.
*
* <p>Accepted buyback inputs and their reserves are configured as an ordered
* {@link List} of {@link MoneyAmount} values. Each
* {@link MoneyAmount#currencyType() currency type}'s stable AssetAZ UUID is
* the authoritative identity, and each {@link MoneyAmount#amount() amount} is
* the minimum balance that must remain. List order is currency priority.
* Solana mint addresses and token programs are integration details resolved
* internally through the Currency Identity Service and Solana and are not
* part of Evelyn's input configuration.</p>
*
* <p>Every non-overlapping iteration has this order:</p>
* <ol>
* <li>If a prior burn has a pending signature, await only that exact
* signature at Solana {@code FINALIZED}. An unknown result ends the
* iteration; definitive failure is logged without notification; success
* receives the burn's single notification attempt. No new swap or burn is
* submitted in an iteration that begins with a pending burn.</li>
* <li>Unless swaps are suspended, inspect accepted currencies in priority
* order. Canonicalize each AssetAZ UUID, resolve its native-SOL or SPL
* representation internally, apply its own minimum reserve, and require a
* fresh input/USDC price. Missing or unusable candidate data does not
* prevent later currencies from being considered.</li>
* <li>Select at most the configured USDC-equivalent maximum, rounded down
* to the input currency's supported precision. Native SOL uses its native
* balance and nine-decimal precision; no future transaction fee is
* estimated when applying its reserve.</li>
* <li>Attempt no more than one exact-input Jupiter swap. Normal return is
* already {@code CONFIRMED}; it is not awaited a second time. A definitive
* failure permits a later iteration to try again, while a timeout or other
* potentially unknown post-submission result suspends swaps for this
* lifecycle.</li>
* <li>Reload the complete visible Evelyn IOU balance, including tokens
* deposited or acquired before this iteration. Absence or failure of a
* swap does not suppress this step, and the USDC buyback limit never caps
* the amount eligible for burning.</li>
* <li>Require a positive, sufficiently fresh canonical EVE/USDT price and
* calculate the complete balance's dollar value before submitting a burn.
* Missing, invalid, or stale price data postpones the burn.</li>
* <li>Submit the complete EVE balance once and retain its signature,
* amount, and notification value as pending before waiting. The service
* never automatically retries, rebuilds, re-signs, or resubmits a swap or
* burn because timeout, interruption, or communication failure can leave
* the original transaction's outcome unknown.</li>
* <li>Await the burn at {@code FINALIZED}. Timeout or I/O retains the
* signature for a later await; definitive on-chain failure clears it
* without notification; successful finalization permits notification.</li>
* <li>Attempt the fixed proof notification exactly once for a successfully
* finalized burn. Notification failure neither retries delivery nor
* repeats the completed burn.</li>
* </ol>
*
* <p>One dedicated worker begins immediately on {@link #start()}, uses fixed
* delay measured after each completed iteration, and never overlaps
* iterations. {@link #stop()} prevents new iterations and stops that worker.
* Pending signatures and swap/burn suspension flags are process-local only
* and are deliberately reset by a completed explicit stop/start cycle or a
* process restart. Such a reset forgets unknown transaction state and can
* weaken duplicate prevention; operators should reconcile uncertain on-chain
* activity before deliberately restarting a suspended or pending service.</p>
*/
public interface EvelynIOUBurnerService {
/**
* Starts the dedicated worker and begins the first iteration immediately.
*
* @throws IllegalStateException if this instance is already running or a
* prior worker has not terminated cleanly
*/
void start();
/**
* Prevents new iterations, interrupts current processing, and stops the
* dedicated worker cleanly.
*
* <p>A completed stop clears process-local pending and suspension state.
* If the calling thread is interrupted while waiting for termination, its
* interrupt status is preserved.</p>
*
* @throws IllegalStateException if clean worker termination cannot be
* established
*/
void stop();
}
@@ -8,16 +8,31 @@ import java.io.IOException;
import java.math.BigDecimal;
/**
* Exchanges an exact human-readable SPL-token amount through Jupiter.
* Exchanges an exact human-readable token amount through Jupiter.
*
* <p>The service resolves token precision from Solana, obtains and validates a
* <p>An input can be a supported SPL token or native SOL represented by
* Jupiter's canonical SOL/WSOL mint
* {@code So11111111111111111111111111111111111111112}. The canonical address
* remains the {@code inputTokenMint} passed to the unchanged swap operation;
* callers that select native SOL remain responsible for reading the native
* wallet balance and applying their own reserve policy. Output remains a
* supported SPL-token mint.</p>
*
* <p>The service resolves mint precision from Solana, obtains and validates a
* Jupiter Swap V2 order, asks its configured wallet to sign the transaction,
* submits the signed transaction through Jupiter's managed execution
* endpoint, and independently awaits Solana confirmation.</p>
* endpoint, and independently awaits Solana confirmation. Legacy SPL-token
* and Token-2022 behavior is unchanged.</p>
*/
public interface JupiterSwapService {
/**
* Swaps an exact amount of one SPL token for another SPL token.
* Swaps an exact amount of a supported token or native SOL into an SPL
* token.
*
* <p>Native SOL input is expressed with the canonical SOL/WSOL mint
* {@code So11111111111111111111111111111111111111112}; the service passes
* that value unchanged to Jupiter as {@code inputMint}. No separate
* native-SOL method is required.</p>
*
* <p>The returned amounts are the actual wallet-level amounts reported by
* Jupiter after successful provider execution, not the quoted amounts.
@@ -26,7 +41,8 @@ public interface JupiterSwapService {
* error after submission can leave the transaction outcome unknown and
* must never cause automatic resubmission.</p>
*
* @param inputTokenMint input SPL-token mint address
* @param inputTokenMint input SPL-token mint address, or the canonical
* SOL/WSOL mint representing native SOL
* @param inputTokenAmount exact input amount in human-readable token units
* @param outputTokenMint output SPL-token mint address
* @param maxSlippageBps maximum accepted slippage from 0 through 10000