The Evelyn IOU burner selects any positive input amount above its reserve. With a USDT balance of 0.100001 and reserve 0.1, it attempts a 0.000001 USDT swap before considering SyrupUSDC. This is an unsuitable tiny order and can block useful input selection.
Add a configurable minimum buyback input amount for each accepted currency, expressed in that input token's own units. Below-minimum amounts must be skipped so that the next configured input can be considered in the same iteration.
This is a small follow-up to #90, independent of timeout recovery in #91. Keep Jupiter execution and the other burner behavior unchanged.
Production configuration
Hardcode the per-token minimum amounts in NenjimHubImpl.constructEvelynIOUBurnerProdProcess(), next to the existing reserves and maxima. Use existing MoneyAmount values, not new ValueTags or a burner-specific configuration hierarchy.
Currency
Reserve (unchanged)
Minimum swap input (new)
Maximum swap input (unchanged)
USDT (CurrencyTypeIds.USDT_ID)
0.1 USDT
0.05 USDT
0.25 USDT
SyrupUSDC (CurrencyTypeIds.SYRUPUSDC_ID)
0.095 SyrupUSDC
0.045 SyrupUSDC
0.2 SyrupUSDC
Keep USDT first, SyrupUSDC second, and preserve the existing wallet, hourly interval, slippage and remaining production arguments.
Constructor and selection
Add a List<MoneyAmount> of minimum swap input amounts, for example inputCurrencyMinimumSwapAmounts, alongside the reserve and maximum lists.
Defensively copy the configuration and match minima by canonical currency UUID, independently of list order/name/symbol.
Require exactly one strictly positive minimum per accepted input and no extra currencies. Reject null entries/values/identities, unknown or duplicate UUIDs, missing minima, and a minimum greater than that currency's configured maximum before starting a worker. Preserve the existing validation. Three empty lists remain valid for direct-EVE-only burning.
Calculate spendable balance and the actual candidate amount using the existing logic:
Skip a non-positive amount or amountToSwap < minimum. Compare the actual rounded candidate, so rounding must never produce an attempted swap below the minimum. Equality with the minimum is accepted.
A below-minimum input does not count as a swap attempt: continue to later inputs in the same iteration. Never top up, round up or spend the reserve to reach the minimum.
Minima constrain input selection only. They do not cap or suppress burning an existing EVE balance, and they require no input/USDC price or USD-value assumption.
Acceptance examples
USDT balance 0.14: spendable 0.04 is below 0.05; no USDT swap, and later inputs remain eligible.
USDT balance 0.15: select exactly 0.05 USDT. Balance 0.149999 must be skipped.
USDT balance 0.100001 plus SyrupUSDC balance 0.502048: skip the 0.000001 USDT remainder, then select 0.2 SyrupUSDC (0.407048 is spendable after subtracting its reserve).
SyrupUSDC balance 0.14: select exactly 0.045 SyrupUSDC. Balance 0.139999 must be skipped.
Preserve maximum caps, priority among qualifying inputs, downward precision rounding, at most one attempted swap per iteration, and direct-EVE burning when all inputs are below minimum or input configuration is empty.
Verify reordered minimum lists still match UUIDs correctly, defensive copies and invalid minimum configurations. No swap may occur below the minimum after rounding.
Verification and scope
Update directly affected OpenSpec requirements, constructor/domain JavaDoc and configuration documentation through the normal workflow. Compile relevant sources, perform focused offline checks of the examples/configuration validation, run strict validation and whitespace checks. Do not submit live transactions. No permanent automated tests are requested by this issue.
No change to timeout/pending recovery, Jupiter routing or confirmation, burn/notification rules, Ticker sources/API/history, reserve values, maximum values, process lifecycle, token discovery, private deployment files or unrelated refactoring.
Related work: #90 (per-currency reserves/maxima) and #91 (pending swap recovery). This issue records implementation scope; implementation and deployment are separate tasks.
## Problem and outcome
The Evelyn IOU burner selects any positive input amount above its reserve. With a USDT balance of 0.100001 and reserve 0.1, it attempts a 0.000001 USDT swap before considering SyrupUSDC. This is an unsuitable tiny order and can block useful input selection.
Add a configurable minimum buyback input amount for each accepted currency, expressed in that input token's own units. Below-minimum amounts must be skipped so that the next configured input can be considered in the same iteration.
This is a small follow-up to #90, independent of timeout recovery in #91. Keep Jupiter execution and the other burner behavior unchanged.
## Production configuration
Hardcode the per-token minimum amounts in `NenjimHubImpl.constructEvelynIOUBurnerProdProcess()`, next to the existing reserves and maxima. Use existing `MoneyAmount` values, not new ValueTags or a burner-specific configuration hierarchy.
| Currency | Reserve (unchanged) | Minimum swap input (new) | Maximum swap input (unchanged) |
| --- | ---: | ---: | ---: |
| USDT (`CurrencyTypeIds.USDT_ID`) | 0.1 USDT | **0.05 USDT** | 0.25 USDT |
| SyrupUSDC (`CurrencyTypeIds.SYRUPUSDC_ID`) | 0.095 SyrupUSDC | **0.045 SyrupUSDC** | 0.2 SyrupUSDC |
Keep USDT first, SyrupUSDC second, and preserve the existing wallet, hourly interval, slippage and remaining production arguments.
## Constructor and selection
- Add a `List<MoneyAmount>` of minimum swap input amounts, for example `inputCurrencyMinimumSwapAmounts`, alongside the reserve and maximum lists.
- Defensively copy the configuration and match minima by canonical currency UUID, independently of list order/name/symbol.
- Require exactly one strictly positive minimum per accepted input and no extra currencies. Reject null entries/values/identities, unknown or duplicate UUIDs, missing minima, and a minimum greater than that currency's configured maximum before starting a worker. Preserve the existing validation. Three empty lists remain valid for direct-EVE-only burning.
- Calculate spendable balance and the actual candidate amount using the existing logic:
```text
availableForSwap = max(balance - reserve, 0)
amountToSwap = roundDown(min(availableForSwap, maximum), mintPrecision)
```
- Skip a non-positive amount or `amountToSwap < minimum`. Compare the actual rounded candidate, so rounding must never produce an attempted swap below the minimum. Equality with the minimum is accepted.
- A below-minimum input does not count as a swap attempt: continue to later inputs in the same iteration. Never top up, round up or spend the reserve to reach the minimum.
- Minima constrain input selection only. They do not cap or suppress burning an existing EVE balance, and they require no input/USDC price or USD-value assumption.
## Acceptance examples
- USDT balance 0.14: spendable 0.04 is below 0.05; no USDT swap, and later inputs remain eligible.
- USDT balance 0.15: select exactly 0.05 USDT. Balance 0.149999 must be skipped.
- USDT balance 0.100001 plus SyrupUSDC balance 0.502048: skip the 0.000001 USDT remainder, then select 0.2 SyrupUSDC (0.407048 is spendable after subtracting its reserve).
- SyrupUSDC balance 0.14: select exactly 0.045 SyrupUSDC. Balance 0.139999 must be skipped.
- Preserve maximum caps, priority among qualifying inputs, downward precision rounding, at most one attempted swap per iteration, and direct-EVE burning when all inputs are below minimum or input configuration is empty.
- Verify reordered minimum lists still match UUIDs correctly, defensive copies and invalid minimum configurations. No swap may occur below the minimum after rounding.
## Verification and scope
Update directly affected OpenSpec requirements, constructor/domain JavaDoc and configuration documentation through the normal workflow. Compile relevant sources, perform focused offline checks of the examples/configuration validation, run strict validation and whitespace checks. Do not submit live transactions. No permanent automated tests are requested by this issue.
No change to timeout/pending recovery, Jupiter routing or confirmation, burn/notification rules, Ticker sources/API/history, reserve values, maximum values, process lifecycle, token discovery, private deployment files or unrelated refactoring.
Related work: #90 (per-currency reserves/maxima) and #91 (pending swap recovery). This issue records implementation scope; implementation and deployment are separate tasks.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem and outcome
The Evelyn IOU burner selects any positive input amount above its reserve. With a USDT balance of 0.100001 and reserve 0.1, it attempts a 0.000001 USDT swap before considering SyrupUSDC. This is an unsuitable tiny order and can block useful input selection.
Add a configurable minimum buyback input amount for each accepted currency, expressed in that input token's own units. Below-minimum amounts must be skipped so that the next configured input can be considered in the same iteration.
This is a small follow-up to #90, independent of timeout recovery in #91. Keep Jupiter execution and the other burner behavior unchanged.
Production configuration
Hardcode the per-token minimum amounts in
NenjimHubImpl.constructEvelynIOUBurnerProdProcess(), next to the existing reserves and maxima. Use existingMoneyAmountvalues, not new ValueTags or a burner-specific configuration hierarchy.CurrencyTypeIds.USDT_ID)CurrencyTypeIds.SYRUPUSDC_ID)Keep USDT first, SyrupUSDC second, and preserve the existing wallet, hourly interval, slippage and remaining production arguments.
Constructor and selection
Add a
List<MoneyAmount>of minimum swap input amounts, for exampleinputCurrencyMinimumSwapAmounts, alongside the reserve and maximum lists.Defensively copy the configuration and match minima by canonical currency UUID, independently of list order/name/symbol.
Require exactly one strictly positive minimum per accepted input and no extra currencies. Reject null entries/values/identities, unknown or duplicate UUIDs, missing minima, and a minimum greater than that currency's configured maximum before starting a worker. Preserve the existing validation. Three empty lists remain valid for direct-EVE-only burning.
Calculate spendable balance and the actual candidate amount using the existing logic:
Skip a non-positive amount or
amountToSwap < minimum. Compare the actual rounded candidate, so rounding must never produce an attempted swap below the minimum. Equality with the minimum is accepted.A below-minimum input does not count as a swap attempt: continue to later inputs in the same iteration. Never top up, round up or spend the reserve to reach the minimum.
Minima constrain input selection only. They do not cap or suppress burning an existing EVE balance, and they require no input/USDC price or USD-value assumption.
Acceptance examples
Verification and scope
Update directly affected OpenSpec requirements, constructor/domain JavaDoc and configuration documentation through the normal workflow. Compile relevant sources, perform focused offline checks of the examples/configuration validation, run strict validation and whitespace checks. Do not submit live transactions. No permanent automated tests are requested by this issue.
No change to timeout/pending recovery, Jupiter routing or confirmation, burn/notification rules, Ticker sources/API/history, reserve values, maximum values, process lifecycle, token discovery, private deployment files or unrelated refactoring.
Related work: #90 (per-currency reserves/maxima) and #91 (pending swap recovery). This issue records implementation scope; implementation and deployment are separate tasks.