File(s) affected: cadence/contracts/connectors/SwapConnectors.cdc ,
cadence/contracts/connectors/evm/ERC4626SwapConnectors.cdc
Description: SwapSink.depositCapacity() unconditionally calls swapper.swapBack() when residual tokens remain after
depositing to the inner sink:
if swappedTokens.balance > 0.0 { // swap back any residual to the originating vault let residual
<- self.swapper.swapBack(quote: nil, residual: <-swappedTokens) from.deposit(from: <-residual) }
However, ERC4626SwapConnectors.Swapper is explicitly a one-way swapper that does not support swapBack() as mentioned
by this comment :
/// NOTE: Since ERC4626 vaults typically do not support synchronous withdrawals, this Swapper
only supports the default inType -> outType path via swap() and reverts on swapBack() since the
withdrawal cannot be returned synchronously.
This is a documented design limitation (the panic message is clear), but SwapSink has no guard rails to prevent this incompatible
combination. The issue is that SwapSink 's semantics implicitly assume swapBack() is a valid residual-management path for any
swapper, which is false for one-way swappers by design. Since DeFiActions.Sink explicitly supports partial intake ("deposit up to
capacity"), residuals are always a realistic outcome with any sink type.
Recommendation: Add a guard in SwapSink to enforce that the swapper supports swapBack() , or document the incompatibility
with one-way swappers.
File(s) affected: cadence/contracts/connectors/SwapConnectors.cdc ,
cadence/contracts/connectors/evm/ERC4626SwapConnectors.cdc
Description: SwapSink.depositCapacity() unconditionally calls swapper.swapBack() when residual tokens remain after
depositing to the inner sink:
However, ERC4626SwapConnectors.Swapper is explicitly a one-way swapper that does not support swapBack() as mentioned
by this comment :
This is a documented design limitation (the panic message is clear), but SwapSink has no guard rails to prevent this incompatible
combination. The issue is that SwapSink 's semantics implicitly assume swapBack() is a valid residual-management path for any
swapper, which is false for one-way swappers by design. Since DeFiActions.Sink explicitly supports partial intake ("deposit up to
capacity"), residuals are always a realistic outcome with any sink type.
Recommendation: Add a guard in SwapSink to enforce that the swapper supports swapBack() , or document the incompatibility
with one-way swappers.