add swap fee minimizer and factory with tests#1577
add swap fee minimizer and factory with tests#1577gerrrg wants to merge 4 commits intobalancer:mainfrom
Conversation
…e and actionable args to internal function to handle remainder of logic and calls while avoiding stack too deep errors
|
Hey @gerrrg , one question about this PR: why did we opt for a router instead of a hook? The idea would be to fetch the sender of a transaction from the router, which is passed through PoolSwapParams, and compare with the owner. If it's equal and the token out is the discounted token out, we return the minimized swap fee. Else, return the nominal swap fee. This would allow the DAO, or the owner of the hook, to use any existing rpouter, including in batch swaps, to trade with the discounted swap fee in the pool. Does it make sense? I know it's some rework, but the code size will be much shorter and easy to maintain, the gas costs of swaps will be smaller and it'll integrate better with all existing routers, which also seems like a better UX, so I didn't see a drawback. But, I may be missing a requirement or another detail, so let me know if it doesn't make sense. |
|
Thanks for checking in @joaobrunoah! I completely agree that the intuitive implementation of this is for it to be a hook! In fact, that was what I suggested at first (and yes, implementing this as a hook would've been MUCH easier). The reason that the grants committee requested this be at the router level (feel free to correct me if I'm wrong @mendesfabio) was to avoid typical swaps by normal users going through this code path. This feature is intended to be used far less frequently than normal swaps are expected to be made through this pool, so the thinking was that it would be better to keep the "normal" swap path streamlined and gas minimized by not needing to make an external call to a hook contract on every transaction. Instead, the pool owner/DAO absorbs the slightly higher gas cost while gaining the benefits of the near-zero fees on their swap. The expectation is that the pool owner will use this only occasionally, and as such, they will likely be quite large relative to typical swap size, so the fee minimization will be quite meaningful. |
Description
This PR adds a new contract,
SwapFeeMinimizer(with accompanying factory), that allows theownerto swap out one specificoutputTokenwith as low of a swap fee as possible, regardless of the nominal swap fee of the pool. All other operations with the pool are unchanged, and anyone (ownerincluded) can swap with the nominal swap fees in the pool via a typical router. There are a few potential use cases for this functionality, though one notable use case is the ability for a DAO to perform token buybacks on a primary liquidity pool w/o needing to pay the typical swap fee.Details
SwapFeeMinimizeris deployed atomically alongside a newWeightedPoolSwapFeeMinimizerare constrained to its specificpoolandoutputTokenownerperforms a swap, the contract stores the pool's current swap fee, then pool swap fees are set to_minimalSwapFee, the swap occurs, and then the fee is returned to its original levelSwapFeeManageris registered as the pool'sPoolRoleAccounts.swapFeeManagerSwapFeeManagercontract has a passthrough function forvault.setStaticSwapFeePercentage(...), though there is an argument to be made for removing thisSwapFeeMinimizerisOwnable2StepArchitectural Context
The initial plan was for this contract itself to be a router. Changing the architecture from an "is a" context to a "has a" context had significant improvements for simplicity and security, but they come with a few small concessions. With this setup, the
SwapFeeMinimizeritself has to transfer tokens from theownerand be an intermediary with the router, which introduces some allowance handling and minor token accounting. It would have been nice to be able to inherit small parts of the broader router contract, but short of fundamentally rearchitecting the core Balancer router, this was impractical, and the realistic options here came down to:ownerI went with Option 3 to keep the contract as small as practical, offering simplicity and minimized attack surface. The gas for a fee-minimized swap is a little higher, most notably due to the increased token transfers.
Type of change
Checklist:
main, or there's a description of how to mergeIssue Resolution
cc: grants committee @mendesfabio