V3FactoryOwner
Git Source (opens in a new tab)
Author: ScopeLift (opens in a new tab)
A contract that can serve as the owner of the Uniswap v3 Factory. This contract itself
has an admin. That admin retains the exclusive right to call privileged methods on the v3
Factory, and on pools which it has deployed, via passthrough methods. This includes the ability
to enable fee amounts on the factory, and set protocol fees on individual pools. The admin can
also set a new admin.
One privileged function that is not reserved exclusively for the admin is the ability to
collect protocol fees from a pool. This method is instead exposed publicly by this contract's
claimFees
method. That method collects fees from the protocol as long as the caller pays for
them with a transfer of a designated amount of a designated token. That payout is forwarded
to a REWARD_RECEIVER.
In the context of the broader system, if it is adopted by Uniswap Governance via a successful governance proposal, it is expected that:
- Governance will transfer ownership of the Factory to an instance of this contract
- this contract's REWARD_RECEIVER is a deployment of the
UniStaker
contract - the admin of this contract will be the Uniswap Governance timelock
Further, is it expected that:
- subsequent proposals will turn on protocol fees for select pools
- a competitive market of seekers will emerge racing to "buy" the fees for an arbitrage opportunity.
State Variables
FACTORY
The instance of the Uniswap v3 factory contract which this contract will own.
IUniswapV3FactoryOwnerActions public immutable FACTORY;
PAYOUT_TOKEN
The ERC-20 token which must be used to pay for fees when claiming pool fees.
IERC20 public immutable PAYOUT_TOKEN;
payoutAmount
The raw amount of the payout token which is paid by a user when claiming pool fees.
uint256 public payoutAmount;
REWARD_RECEIVER
The contract that receives the payout and is notified via method call, when pool fees are claimed.
INotifiableRewardReceiver public immutable REWARD_RECEIVER;
admin
The address that can call privileged methods, including passthrough owner functions to the factory itself.
address public admin;
Functions
constructor
constructor(
address _admin,
IUniswapV3FactoryOwnerActions _factory,
IERC20 _payoutToken,
uint256 _payoutAmount,
INotifiableRewardReceiver _rewardReceiver
);
Parameters
Name | Type | Description |
---|---|---|
_admin | address | The initial admin address for this deployment. Cannot be zero address. |
_factory | IUniswapV3FactoryOwnerActions | The v3 factory instance for which this deployment will serve as owner. |
_payoutToken | IERC20 | The ERC-20 token in which payouts will be denominated. |
_payoutAmount | uint256 | The initial raw amount of the payout token required to claim fees from a pool. |
_rewardReceiver | INotifiableRewardReceiver | The contract that will receive the payout when fees are claimed. |
setAdmin
Pass the admin role to a new address. Must be called by the existing admin.
function setAdmin(address _newAdmin) external;
Parameters
Name | Type | Description |
---|---|---|
_newAdmin | address | The address that will be the admin after this call completes. |
setPayoutAmount
Update the payout amount to a new value. Must be called by admin.
function setPayoutAmount(uint256 _newPayoutAmount) external;
Parameters
Name | Type | Description |
---|---|---|
_newPayoutAmount | uint256 | The value that will be the new payout amount. |
enableFeeAmount
Passthrough method that enables a fee amount on the factory. Must be called by the admin.
See docs on IUniswapV3FactoryOwnerActions for more information on forwarded params.
function enableFeeAmount(uint24 _fee, int24 _tickSpacing) external;
Parameters
Name | Type | Description |
---|---|---|
_fee | uint24 | The fee param to forward to the factory. |
_tickSpacing | int24 | The tick spacing param to forward to the factory. |
setFeeProtocol
Passthrough method that sets the protocol fee on a v3 pool. Must be called by the admin.
See docs on IUniswapV3PoolOwnerActions for more information on forwarded params.
function setFeeProtocol(IUniswapV3PoolOwnerActions _pool, uint8 _feeProtocol0, uint8 _feeProtocol1)
external;
Parameters
Name | Type | Description |
---|---|---|
_pool | IUniswapV3PoolOwnerActions | The Uniswap v3 pool on which the protocol fee is being set. |
_feeProtocol0 | uint8 | The fee protocol 0 param to forward to the pool. |
_feeProtocol1 | uint8 | The fee protocol 1 parm to forward to the pool. |
claimFees
Public method that allows any caller to claim the protocol fees accrued by a given Uniswap v3 pool contract. Caller must pre-approve this factory owner contract on the payout token contract for at least the payout amount, which is transferred from the caller to the reward receiver. The reward receiver is "notified" of the payout via a method call. The protocol fees collected are sent to a receiver of the caller's specification. A quick example can help illustrate why an external party, such as an MEV searcher, would be incentivized to call this method. Imagine, purely for the sake of example, that protocol fees have been activated for the USDC/USDT stablecoin v3 pool. Imagine also the payout token and payout amount are WETH and 10e18 respectively. Finally, assume the spot USD price of ETH is $2,500, and both stablecoins are trading at their $1 peg. As regular users trade against the USDC/USDT pool, protocol fees amass in the pool contract in both stablecoins. Once the fees in the pool total more than 25,000 in stablecoins, it becomes profitable for an external party to arbitrage the fees by calling this method, paying 10 WETH (worth $25K) and getting more than $25K worth of stablecoins. (This ignores other details, which real searchers would take into consideration, such as the gas/builder fee they would pay to call the method). The same mechanic applies regardless of what the pool currencies, payout token, or payout amount are. Effectively, as each pool accrues fees, it eventually becomes possible to "buy" the pool fees for less than they are valued by "paying" the the payout amount of the payout token.
See docs on IUniswapV3PoolOwnerActions for more information on forwarded params.
function claimFees(
IUniswapV3PoolOwnerActions _pool,
address _recipient,
uint128 _amount0Requested,
uint128 _amount1Requested
) external returns (uint128, uint128);
Parameters
Name | Type | Description |
---|---|---|
_pool | IUniswapV3PoolOwnerActions | The Uniswap v3 pool contract from which protocol fees are being collected. |
_recipient | address | The address to which collected protocol fees will be transferred. |
_amount0Requested | uint128 | The amount0Requested param to forward to the pool's collectProtocol method. |
_amount1Requested | uint128 | The amount1Requested param to forward to the pool's collectProtocol method. |
Returns
Name | Type | Description |
---|---|---|
<none> | uint128 | _amount0 The amount0 fees collected, returned by the pool's collectProtocol method. |
<none> | uint128 | _amount1 The amount1 fees collected, returned by the pool's collectProtocol method. |
_revertIfNotAdmin
Ensures the msg.sender is the contract admin and reverts otherwise.
Place inside external methods to make them admin-only.
function _revertIfNotAdmin() internal view;
Events
FeesClaimed
Emitted when a user pays the payout and claims the fees from a given v3 pool.
event FeesClaimed(
address indexed pool,
address indexed caller,
address indexed recipient,
uint256 amount0,
uint256 amount1
);
Parameters
Name | Type | Description |
---|---|---|
pool | address | The v3 pool from which protocol fees were claimed. |
caller | address | The address which executes the call to claim the fees. |
recipient | address | The address to which the claimed pool fees are sent. |
amount0 | uint256 | The raw amount of token0 fees claimed from the pool. |
amount1 | uint256 | The raw amount token1 fees claimed from the pool. |
AdminSet
Emitted when the existing admin designates a new address as the admin.
event AdminSet(address indexed oldAmin, address indexed newAdmin);
PayoutAmountSet
Emitted when the admin updates the payout amount.
event PayoutAmountSet(uint256 indexed oldPayoutAmount, uint256 indexed newPayoutAmount);
Errors
V3FactoryOwner__Unauthorized
Thrown when an unauthorized account calls a privileged function.
error V3FactoryOwner__Unauthorized();
V3FactoryOwner__InvalidAddress
Thrown if the proposed admin is the zero address.
error V3FactoryOwner__InvalidAddress();
V3FactoryOwner__InvalidPayoutAmount
Thrown if the proposed payout amount is zero.
error V3FactoryOwner__InvalidPayoutAmount();
V3FactoryOwner__InsufficientFeesCollected
Thrown when the fees collected from a pool are less than the caller expects.
error V3FactoryOwner__InsufficientFeesCollected();