94: Buy back Evelyn IOU tokens only below the Evelyn reference price
This commit is contained in:
@@ -51,7 +51,15 @@ import java.util.List;
|
||||
* below that input's minimum and continue to later inputs in the same
|
||||
* iteration; equality qualifies. Never round upward or use the reserve
|
||||
* to reach a minimum. Input minima do not suppress EVE burns.</li>
|
||||
* <li>Attempt no more than one exact-input Jupiter swap. Normal return is
|
||||
* <li>Immediately before a new purchase, require a fresh canonical
|
||||
* EVE/USDT price strictly below the corresponding Evelyn status service's
|
||||
* reference price at the current decision instant. Equality, higher price,
|
||||
* unavailable reference or unusable price data skips all new purchases
|
||||
* for this iteration and continues to independent EVE burn processing.
|
||||
* A price skip does not suspend subsequent iterations. Pending transaction
|
||||
* reconciliation is independent of this new-purchase condition.</li>
|
||||
* <li>When the price condition permits, 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 or proven pre-submission error permits a later iteration to try
|
||||
* again. A known-signature timeout or communication error retains pending
|
||||
@@ -60,11 +68,13 @@ import java.util.List;
|
||||
* unknown swap is rebuilt, re-signed or resubmitted automatically.</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 input buyback limit never caps
|
||||
* swap, including a price-condition skip, does not suppress this step,
|
||||
* and the input buyback limit never caps
|
||||
* the amount eligible for burning. Subtract the retained EVE reserve and
|
||||
* round the positive remainder down to EVE mint precision. If the actual
|
||||
* rounded amount is zero or below the burn minimum, keep the EVE for a
|
||||
* later iteration and send no burn notification. Equality qualifies;</n+ * never round upward or consume reserve to reach the minimum.</li>
|
||||
* later iteration and send no burn notification. Equality qualifies;
|
||||
* never round upward or consume reserve to reach the minimum.</li>
|
||||
* <li>Require a positive, sufficiently fresh canonical EVE/USDT price and
|
||||
* calculate the actual eligible burn amount's dollar value, excluding
|
||||
* the retained reserve, before submitting a burn.
|
||||
|
||||
+85
-1
@@ -7,6 +7,7 @@ import com.r35157.assetaz.services.ticker.PriceObservation;
|
||||
import com.r35157.assetaz.services.ticker.TickerService;
|
||||
import com.r35157.assetaz.valuetypes.CurrencyType;
|
||||
import com.r35157.cryptowallet.solana.SolanaWallet;
|
||||
import com.r35157.evelyn.service.status.EvelynStatusService;
|
||||
import com.r35157.libs.jupiter.JupiterTransactionOutcomeException;
|
||||
import com.r35157.libs.jupiter.swap.JupiterSwapService;
|
||||
import com.r35157.libs.jupiter.swap.JupiterSwapSubmissionException;
|
||||
@@ -93,13 +94,23 @@ public final class EvelynIOUBurnerServiceImpl
|
||||
* qualifies; fractional remainders stay in the wallet. This policy does
|
||||
* not suppress independent small buybacks or re-evaluate pending burns.</p>
|
||||
*
|
||||
* <p>A fully eligible new buyback additionally requires a fresh canonical
|
||||
* EVE/USDT price strictly below the corresponding status service's
|
||||
* reference price at the current decision instant. Equality, unavailable
|
||||
* or invalid prices skip purchases only, without suspending later
|
||||
* iterations or suppressing independent EVE burn processing. Pending
|
||||
* burn priority and read-only swap reconciliation remain unchanged.</p>
|
||||
*
|
||||
* @param burnerWallet dedicated wallet whose balances are inspected and
|
||||
* whose eligible EVE above reserve is burned
|
||||
* @param swapService exact-input Jupiter service; normal return already
|
||||
* means the swap reached {@code CONFIRMED}
|
||||
* @param solanaBlockChain Solana access used for mint ownership, token
|
||||
* precision, and burn finalization
|
||||
* @param tickerService latest-price source for EVE/USDT before burning
|
||||
* @param tickerService latest-price source for EVE/USDT before new
|
||||
* buybacks and independently before burning
|
||||
* @param evelynStatusService corresponding Evelyn instance's reference
|
||||
* price source for new buyback decisions
|
||||
* @param currencyIdentityService authoritative resolver for AssetAZ UUIDs
|
||||
* and Solana mint references
|
||||
* @param notificationService fully bound synchronous destination for the
|
||||
@@ -147,6 +158,7 @@ public final class EvelynIOUBurnerServiceImpl
|
||||
@NotNull JupiterSwapService swapService,
|
||||
@NotNull SolanaBlockChain solanaBlockChain,
|
||||
@NotNull TickerService tickerService,
|
||||
@NotNull EvelynStatusService evelynStatusService,
|
||||
@NotNull CurrencyIdentityService currencyIdentityService,
|
||||
@NotNull BoundNotificationService notificationService,
|
||||
@NotNull List<MoneyAmount> inputCurrencyMinimumReserves,
|
||||
@@ -175,6 +187,10 @@ public final class EvelynIOUBurnerServiceImpl
|
||||
tickerService,
|
||||
"tickerService"
|
||||
);
|
||||
this.evelynStatusService = Objects.requireNonNull(
|
||||
evelynStatusService,
|
||||
"evelynStatusService"
|
||||
);
|
||||
this.currencyIdentityService = Objects.requireNonNull(
|
||||
currencyIdentityService,
|
||||
"currencyIdentityService"
|
||||
@@ -436,6 +452,9 @@ public final class EvelynIOUBurnerServiceImpl
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isBuybackBelowReferencePrice()) {
|
||||
return;
|
||||
}
|
||||
attemptSwap(
|
||||
canonicalCurrency,
|
||||
inputMint,
|
||||
@@ -445,6 +464,70 @@ public final class EvelynIOUBurnerServiceImpl
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBuybackBelowReferencePrice() {
|
||||
ΩPriceΩ actualPrice = findFreshPrice(eveUsdtTradingPair);
|
||||
if (actualPrice == null) {
|
||||
log.warn(
|
||||
"Skipping buyback as no fresh valid EVE/USDT price "
|
||||
+ "is available; nextAction=burn "
|
||||
+ "evaluation and price recheck next iteration"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
Instant decisionInstant = Instant.now();
|
||||
AssetPrice referencePrice;
|
||||
try {
|
||||
referencePrice = evelynStatusService.getReferencePrice(
|
||||
decisionInstant
|
||||
);
|
||||
} catch (RuntimeException exception) {
|
||||
log.warn(
|
||||
"Skipping buyback as reference price is unavailable "
|
||||
+ "(market={} USDT/EVE); decisionInstant={}, "
|
||||
+ "failureType={}; "
|
||||
+ "nextAction=burn evaluation and price recheck "
|
||||
+ "next iteration",
|
||||
actualPrice.stripTrailingZeros().toPlainString(),
|
||||
decisionInstant,
|
||||
exception.getClass().getName()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (referencePrice == null
|
||||
|| !eveUsdtTradingPair.equals(referencePrice.tradingPair())
|
||||
|| referencePrice.price() == null
|
||||
|| referencePrice.price().signum() <= 0) {
|
||||
log.warn(
|
||||
"Skipping buyback as reference price is missing or "
|
||||
+ "invalid (market={} USDT/EVE); tradingPair={}, "
|
||||
+ "decisionInstant={}; nextAction=burn evaluation "
|
||||
+ "and price recheck next iteration",
|
||||
actualPrice.stripTrailingZeros().toPlainString(),
|
||||
eveUsdtTradingPair,
|
||||
decisionInstant
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (actualPrice.compareTo(referencePrice.price()) >= 0) {
|
||||
log.info(
|
||||
"Skipping buyback as EVE price is at or above reference "
|
||||
+ "(market={} >= reference={} USDT/EVE); "
|
||||
+ "tradingPair={}, "
|
||||
+ "decisionInstant={}; nextAction=burn evaluation "
|
||||
+ "and price recheck next iteration",
|
||||
actualPrice.stripTrailingZeros().toPlainString(),
|
||||
referencePrice.price().stripTrailingZeros().toPlainString(),
|
||||
eveUsdtTradingPair,
|
||||
decisionInstant
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void attemptSwap(
|
||||
CurrencyType canonicalCurrency,
|
||||
ΩSPLMintAddressΩ inputMint,
|
||||
@@ -1124,6 +1207,7 @@ public final class EvelynIOUBurnerServiceImpl
|
||||
private final JupiterSwapService swapService;
|
||||
private final SolanaBlockChain solanaBlockChain;
|
||||
private final TickerService tickerService;
|
||||
private final EvelynStatusService evelynStatusService;
|
||||
private final CurrencyIdentityService currencyIdentityService;
|
||||
private final BoundNotificationService notificationService;
|
||||
private final List<MoneyAmount> inputCurrencyMinimumReserves;
|
||||
|
||||
@@ -324,6 +324,10 @@ public final class NenjimHubImpl implements NenjimHub {
|
||||
tickerService,
|
||||
EVELYN_IOU_BURNER_PROD_ID,
|
||||
TICKER_SERVICE_ID),
|
||||
requireProcessDependency(
|
||||
evelynStatusServiceProd,
|
||||
EVELYN_IOU_BURNER_PROD_ID,
|
||||
EVELYN_STATUS_PROD_ID),
|
||||
cis,
|
||||
discordAssetAZTokenNotificationService,
|
||||
inputCurrencyMinimumReserves,
|
||||
|
||||
Reference in New Issue
Block a user