Skip to content

Clement/fee on swap#215

Closed
clement-ux wants to merge 5 commits into
nicka/withdraw-on-swapfrom
clement/fee-on-swap
Closed

Clement/fee on swap#215
clement-ux wants to merge 5 commits into
nicka/withdraw-on-swapfrom
clement/fee-on-swap

Conversation

@clement-ux
Copy link
Copy Markdown
Contributor

@clement-ux clement-ux commented Apr 30, 2026

Summary

Replaces the performance-fee-on-asset-growth model with a simpler swap fee charged at swap time.

New fee logic

The fee is now applied directly inside _accrueSwapFee (AbstractARM.sol), called at the end of every swap:

  • Charged only when the ARM buys the base asset (i.e. the trader sells base asset into the ARM). When the ARM sells the base asset, no fee is charged.
  • Taken in the base asset itself (e.g. stETH, sUSDe, OETH, weETH) — not in the liquidity asset. This avoids an extra internal conversion on the fee path.
  • Flat percentage of amountIn: fees = amountIn * fee / FEE_SCALE.
  • Transferred immediately to feeCollector during the swap — no storage accumulation, no feesAccrued tracking, no separate collectFees() call to coordinate.

As a result, totalAssets() no longer needs to net out outstanding fees, setFee() no longer auto-collects, and the contract surface is significantly smaller.

Storage / API changes

  • Removed: feesAccrued(), collectFees(), lastAvailableAssets (storage).
  • Renamed: lastAvailableAssets_deprecated_lastAvailableAssets to preserve the storage layout. A backwards-compatibility getter lastAvailableAssets() now simply returns int128(totalAssets()).

Migration

Upgrade scripts ship for each ARM:

  • 028_UpgradeLidoARMSwapFeeScript
  • 029_UpgradeEtherFiARMSwapFeeScript
  • 030_UpgradeOETHARMSwapFeeScript
  • sonic/006_UpgradeOriginARMSwapFeeScript

Each proposal calls collectFees() first to drain any legacy accrued fees, then upgradeTo(newImpl).

Gas consumption

  +--------------+---------+--------+
  | Scenario     | Gas     | Delta  |
  +--------------+---------+--------+
  | Current      | 132,249 |   -    |
  | StoreFee EL  | 143,355 |   +8%  |
  | TransFee EL  | 176,697 |  +33%  |
  | StoreFee NEL | 554,185 | +319%  |
  | TransFee NEL | 587,527 | +344%  |
  +--------------+---------+--------+
  EL -> EnoughLiquidity  
  Delta against "Current"

clement-ux and others added 5 commits April 30, 2026 17:16
Co-authored-by: Copilot <copilot@github.com>
- Removed fee collection logic from LidoARM tests and contracts, transitioning to immediate fee transfers during swaps.
- Updated tests to reflect changes in fee accrual and total asset calculations, ensuring accurate assertions without relying on accrued fees.
- Simplified modifiers and removed unnecessary fee-related assertions and functions across various test files.
- Introduced a new deployment script for upgrading the OETH ARM to the swap-only fee accrual model.
FeeData memory feeDataMem = feeData;
if (feeDataMem.fee == 0) return;
// Calculate the amount of fees to take in baseAsset terms
uint256 fees = amountIn * fee / FEE_SCALE;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is charging a fee on the full base amount rather than just a fee on the discounted rate. Using Ethena as an example, if the ARM buys sUSDe, it will convert to a fair USDe amount by dividing by 1.23. It then only charges a 20% performance fee on the discounted amount.
performance fee = (sUSDe converted to fair USDe value - discounted USDe) * 20%

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we ensure that the fee % is lower than half of the spread, then we have almost the same at the end no?
The idea behind using amountIn is that it reduces gas consumption because we don't convert sUSDe in USDe.
(sUSDe converted to fair USDe value - discounted USDe) * 20% is a % of the spread, while amountIn * fee / FEE_SCALE is a % of the amountIn but we ensure that this is lower than half of the spread.
I agree that fee will change slightly because of the increase of sUSDe value, but we can change the fee every 6 months to match that?

@clement-ux clement-ux closed this May 5, 2026
@clement-ux clement-ux deleted the clement/fee-on-swap branch May 5, 2026 11:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants