Decay is an instruction in SwapVM, the swap engine behind 1inch Aqua. It is one of the opcodes exposed by the deployed Aqua swap router (AquaSwapVMRouter).
Decay applies a Mooniswap-style virtual balance adjustment: after a swap it temporarily inflates balanceIn and deflates balanceOut, then gradually restores them over a decay period. This creates a spread that discourages sandwich attacks.
Decay is one of the SwapVM opcodes registered on the Aqua router (AquaOpcodes): Controls, XYCSwap, XYCConcentrate, Decay, Fee, PeggedSwap, and Extruction.
Source: src/instructions/Decay.sol
Args encoding
| Field | Offset | Size | Description |
|---|---|---|---|
period |
0 | 2 bytes (uint16) |
Decay period in seconds |
Build with DecayArgsBuilder.build(uint16 decayPeriod).
Instructions
_decayXD
function _decayXD(Context memory ctx, bytes calldata args) internal
Applies time-decaying offsets to virtual balances before running the nested swap formula.
Behavior
- Reads
periodfrom args - Reads decaying offsets from storage:
_offsets[orderHash][tokenIn][true]→ added tobalanceIn(making input look more expensive)_offsets[orderHash][tokenOut][false]→ subtracted frombalanceOut(making output look smaller)
- Calls
ctx.runLoop()to execute the nested swap formula with adjusted balances - In swap mode, records new offsets for the amounts transacted:
- Adds
swapAmountInto_offsets[orderHash][tokenIn][false] - Adds
swapAmountOutto_offsets[orderHash][tokenOut][true]
Offset decay formula (per stored DecayingOffset { offset, timestamp }):
timeLeft = (timestamp + period) - block.timestamp // 0 if expired
currentOffset = offset * timeLeft / period
Offsets decay linearly to zero over period seconds. Expired offsets return zero.
Constraint: Must be placed before swap amounts are computed (amountIn == 0 || amountOut == 0).
Quote/swap divergence: In quote mode, offsets are read but not updated. A quote reflects the current spread; the swap applies and records new offsets. Do not use backward jumps to this instruction.
Errors: DecayShouldBeCalledBeforeSwapAmountsComputation(amountIn, amountOut).
Storage layout
mapping(bytes32 orderHash =>
mapping(address token =>
mapping(bool buyOrSell => DecayingOffset))) internal _offsets;
struct DecayingOffset {
uint216 offset;
uint40 timestamp;
}
Packed into a single storage slot (216 + 40 = 256 bits). Uses assembly for single-slot SLOAD/SSTORE.
Related
- Balances: sets the initial reserves;
_decayXDadjusts them further. - XYCSwap: the typical swap formula nested after decay.