The Evelyn IOU burner currently accepts only USDT in its production Hub configuration. Its common USDC-equivalent swap ceiling also requires a fresh input-token/USDC price for any other token. Add SyrupUSDC as an accepted input and replace that common ceiling with a maximum input amount for each configured currency, expressed in that currency's own units.
This lets SyrupUSDC deposited into the existing burner wallet be exchanged for EVE and burned using the existing Jupiter pipeline, without adding SyrupUSDC price sources or changing the Ticker.
Production configuration
Keep configuration in NenjimHubImpl.constructEvelynIOUBurnerProdProcess() and use the existing MoneyAmount type for both reserves and maximum amounts.
Currency
Minimum reserve
Maximum swap input per iteration
USDT (CurrencyTypeIds.USDT_ID)
0.1 USDT
0.25 USDT
SyrupUSDC (CurrencyTypeIds.SYRUPUSDC_ID)
0.095 SyrupUSDC
0.2 SyrupUSDC
Preserve USDT as the first priority and add SyrupUSDC after it. Preserve the existing burner wallet, process registration and all other production settings, including the hourly interval and slippage limit.
These are token-denominated limits. In particular, 0.2 SyrupUSDC is not a guaranteed USD or USDC value. Do not treat SyrupUSDC as equal to USDC.
Constructor and amount calculation
Replace the scalar maximumSwapAmountInUSDC constructor argument with a List<MoneyAmount> of per-currency maximum input amounts, for example inputCurrencyMaximumSwapAmounts.
Keep the ordered inputCurrencyMinimumReserves list as the authoritative accepted-input list and priority order. Match maxima by canonical currency UUID, not by list position, name or symbol.
Defensively copy the configuration. Require exactly one strictly positive maximum for every accepted input, with no duplicates or extra currencies. Reject null entries, amounts, currencies or UUIDs and invalid/unknown identities before starting a worker. Preserve the existing reserve and input validation. Empty reserves and maxima lists remain valid and permit direct EVE deposits to be burned.
Remove input-token/USDC price lookup and the conversion from the common USDC ceiling. Remove configuration names, fields and documentation that imply the swap limit is denominated in USD or USDC.
Round downward to the input mint's precision using the existing precision handling. Skip a non-positive amount, including one that rounds to zero. Never round upward beyond the spendable balance or maximum.
Preserve the existing execution and burn behavior
All swaps continue through the existing exact-input JupiterSwapService, from the selected input mint to the fixed EVE mint. Jupiter chooses the pool and route; this issue does not constrain it to one hop or a specific Raydium pool.
Keep the existing behavior for ordered input selection, at most one swap attempt per iteration, SOL/SPL balance and mint resolution, confirmed swap outcomes, suspension after unknown swap outcomes, reloading and burning the complete EVE balance, pending burn handling, FINALIZED confirmation and notifications.
The Ticker dependency remains necessary: preserve the fresh EVE/USDT observation required before burning and used to calculate the notification value. Only the input-token/USDC price dependency is removed. Preserve direct-EVE deposit handling and the existing Hub-owned NenjimProcess lifecycle.
Verification and acceptance
Production configuration contains the exact reserves and maxima above, including 0.095, not 0.1, for SyrupUSDC.
With SyrupUSDC balance 0.5, select 0.2 SyrupUSDC. With balance 0.245, select 0.150. At or below 0.095, skip SyrupUSDC.
With USDT balance 0.35, select 0.25 USDT, preserving the existing reserve and maximum.
Verify matching by UUID even when the maxima list uses a different order, invalid/missing/duplicate maxima rejection, and downward mint-precision rounding.
SyrupUSDC selection requires no SyrupUSDC/USDC Ticker observation. Missing or stale EVE/USDT observations still postpone burning exactly as before.
Verify that the existing swap and burn failure/recovery behavior is preserved using controlled dependencies or offline verification. Do not submit live financial transactions for verification.
Update directly affected OpenSpec requirements, constructor JavaDoc and documentation to describe per-currency token limits. Compile the relevant sources, validate the OpenSpec change and run the normal diff/whitespace checks.
Scope
No new PriceSource implementation or instances, Ticker API/selection changes, price history files or directories, derived cross-prices, direct Raydium swaps, generic token discovery, new configuration framework, new ValueTags, burner package rename, input-priority changes or unrelated burner refactoring.
Related work: #72 (original burner) and #83 (domain/lifecycle separation). This issue records the agreed implementation scope; implementation and deployment are separate tasks.
## Problem and outcome
The Evelyn IOU burner currently accepts only USDT in its production Hub configuration. Its common USDC-equivalent swap ceiling also requires a fresh input-token/USDC price for any other token. Add SyrupUSDC as an accepted input and replace that common ceiling with a maximum input amount for each configured currency, expressed in that currency's own units.
This lets SyrupUSDC deposited into the existing burner wallet be exchanged for EVE and burned using the existing Jupiter pipeline, without adding SyrupUSDC price sources or changing the Ticker.
## Production configuration
Keep configuration in `NenjimHubImpl.constructEvelynIOUBurnerProdProcess()` and use the existing `MoneyAmount` type for both reserves and maximum amounts.
| Currency | Minimum reserve | Maximum swap input per iteration |
| --- | ---: | ---: |
| USDT (`CurrencyTypeIds.USDT_ID`) | 0.1 USDT | 0.25 USDT |
| SyrupUSDC (`CurrencyTypeIds.SYRUPUSDC_ID`) | **0.095 SyrupUSDC** | **0.2 SyrupUSDC** |
Preserve USDT as the first priority and add SyrupUSDC after it. Preserve the existing burner wallet, process registration and all other production settings, including the hourly interval and slippage limit.
These are token-denominated limits. In particular, 0.2 SyrupUSDC is not a guaranteed USD or USDC value. Do not treat SyrupUSDC as equal to USDC.
## Constructor and amount calculation
- Replace the scalar `maximumSwapAmountInUSDC` constructor argument with a `List<MoneyAmount>` of per-currency maximum input amounts, for example `inputCurrencyMaximumSwapAmounts`.
- Keep the ordered `inputCurrencyMinimumReserves` list as the authoritative accepted-input list and priority order. Match maxima by canonical currency UUID, not by list position, name or symbol.
- Defensively copy the configuration. Require exactly one strictly positive maximum for every accepted input, with no duplicates or extra currencies. Reject null entries, amounts, currencies or UUIDs and invalid/unknown identities before starting a worker. Preserve the existing reserve and input validation. Empty reserves and maxima lists remain valid and permit direct EVE deposits to be burned.
- Remove input-token/USDC price lookup and the conversion from the common USDC ceiling. Remove configuration names, fields and documentation that imply the swap limit is denominated in USD or USDC.
- For each input, calculate:
```text
availableForSwap = max(balance - minimumReserve, 0)
amountToSwap = min(availableForSwap, maximumAmountForThisCurrency)
```
Round downward to the input mint's precision using the existing precision handling. Skip a non-positive amount, including one that rounds to zero. Never round upward beyond the spendable balance or maximum.
## Preserve the existing execution and burn behavior
All swaps continue through the existing exact-input `JupiterSwapService`, from the selected input mint to the fixed EVE mint. Jupiter chooses the pool and route; this issue does not constrain it to one hop or a specific Raydium pool.
Keep the existing behavior for ordered input selection, at most one swap attempt per iteration, SOL/SPL balance and mint resolution, confirmed swap outcomes, suspension after unknown swap outcomes, reloading and burning the complete EVE balance, pending burn handling, `FINALIZED` confirmation and notifications.
The Ticker dependency remains necessary: preserve the fresh EVE/USDT observation required before burning and used to calculate the notification value. Only the input-token/USDC price dependency is removed. Preserve direct-EVE deposit handling and the existing Hub-owned `NenjimProcess` lifecycle.
## Verification and acceptance
- Production configuration contains the exact reserves and maxima above, including **0.095**, not 0.1, for SyrupUSDC.
- With SyrupUSDC balance 0.5, select 0.2 SyrupUSDC. With balance 0.245, select 0.150. At or below 0.095, skip SyrupUSDC.
- With USDT balance 0.35, select 0.25 USDT, preserving the existing reserve and maximum.
- Verify matching by UUID even when the maxima list uses a different order, invalid/missing/duplicate maxima rejection, and downward mint-precision rounding.
- SyrupUSDC selection requires no SyrupUSDC/USDC Ticker observation. Missing or stale EVE/USDT observations still postpone burning exactly as before.
- Verify that the existing swap and burn failure/recovery behavior is preserved using controlled dependencies or offline verification. Do not submit live financial transactions for verification.
- Update directly affected OpenSpec requirements, constructor JavaDoc and documentation to describe per-currency token limits. Compile the relevant sources, validate the OpenSpec change and run the normal diff/whitespace checks.
## Scope
No new PriceSource implementation or instances, Ticker API/selection changes, price history files or directories, derived cross-prices, direct Raydium swaps, generic token discovery, new configuration framework, new ValueTags, burner package rename, input-priority changes or unrelated burner refactoring.
Related work: #72 (original burner) and #83 (domain/lifecycle separation). This issue records the agreed 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 currently accepts only USDT in its production Hub configuration. Its common USDC-equivalent swap ceiling also requires a fresh input-token/USDC price for any other token. Add SyrupUSDC as an accepted input and replace that common ceiling with a maximum input amount for each configured currency, expressed in that currency's own units.
This lets SyrupUSDC deposited into the existing burner wallet be exchanged for EVE and burned using the existing Jupiter pipeline, without adding SyrupUSDC price sources or changing the Ticker.
Production configuration
Keep configuration in
NenjimHubImpl.constructEvelynIOUBurnerProdProcess()and use the existingMoneyAmounttype for both reserves and maximum amounts.CurrencyTypeIds.USDT_ID)CurrencyTypeIds.SYRUPUSDC_ID)Preserve USDT as the first priority and add SyrupUSDC after it. Preserve the existing burner wallet, process registration and all other production settings, including the hourly interval and slippage limit.
These are token-denominated limits. In particular, 0.2 SyrupUSDC is not a guaranteed USD or USDC value. Do not treat SyrupUSDC as equal to USDC.
Constructor and amount calculation
Replace the scalar
maximumSwapAmountInUSDCconstructor argument with aList<MoneyAmount>of per-currency maximum input amounts, for exampleinputCurrencyMaximumSwapAmounts.Keep the ordered
inputCurrencyMinimumReserveslist as the authoritative accepted-input list and priority order. Match maxima by canonical currency UUID, not by list position, name or symbol.Defensively copy the configuration. Require exactly one strictly positive maximum for every accepted input, with no duplicates or extra currencies. Reject null entries, amounts, currencies or UUIDs and invalid/unknown identities before starting a worker. Preserve the existing reserve and input validation. Empty reserves and maxima lists remain valid and permit direct EVE deposits to be burned.
Remove input-token/USDC price lookup and the conversion from the common USDC ceiling. Remove configuration names, fields and documentation that imply the swap limit is denominated in USD or USDC.
For each input, calculate:
Round downward to the input mint's precision using the existing precision handling. Skip a non-positive amount, including one that rounds to zero. Never round upward beyond the spendable balance or maximum.
Preserve the existing execution and burn behavior
All swaps continue through the existing exact-input
JupiterSwapService, from the selected input mint to the fixed EVE mint. Jupiter chooses the pool and route; this issue does not constrain it to one hop or a specific Raydium pool.Keep the existing behavior for ordered input selection, at most one swap attempt per iteration, SOL/SPL balance and mint resolution, confirmed swap outcomes, suspension after unknown swap outcomes, reloading and burning the complete EVE balance, pending burn handling,
FINALIZEDconfirmation and notifications.The Ticker dependency remains necessary: preserve the fresh EVE/USDT observation required before burning and used to calculate the notification value. Only the input-token/USDC price dependency is removed. Preserve direct-EVE deposit handling and the existing Hub-owned
NenjimProcesslifecycle.Verification and acceptance
Scope
No new PriceSource implementation or instances, Ticker API/selection changes, price history files or directories, derived cross-prices, direct Raydium swaps, generic token discovery, new configuration framework, new ValueTags, burner package rename, input-priority changes or unrelated burner refactoring.
Related work: #72 (original burner) and #83 (domain/lifecycle separation). This issue records the agreed implementation scope; implementation and deployment are separate tasks.