Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions src/feeAdapters/V4FeeAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.29;

import {Currency} from "v4-core/types/Currency.sol";
import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol";
import {MerkleProof} from "openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol";
import {Owned} from "solmate/src/auth/Owned.sol";
import {PoolKey} from "v4-core/types/PoolKey.sol";

/// @title V4FeeAdapter
/// @notice Triggers the collection of protocol fees to a predefined token jar.
contract V4FeeAdapter is Owned {
/// @notice Thrown when the amount collected is less than the amount expected.
error AmountCollectedTooLow(uint256 amountCollected, uint256 amountExpected);

/// @notice Thrown when the merkle proof is invalid.
error InvalidProof();

IPoolManager public immutable POOL_MANAGER;

address public tokenJar;

bytes32 public merkleRoot;

constructor(address _poolManager, address _tokenJar, address _owner) Owned(_owner) {
POOL_MANAGER = IPoolManager(_poolManager);
tokenJar = _tokenJar;
}

/// @notice Collects the protocol fees for the given currencies to the token jar.
/// @param currency The currencies to collect fees for.
/// @param amountRequested The amount of each currency to request.
/// @param amountExpected The amount of each currency that is expected to be collected.
function collect(
Currency[] calldata currency,
uint256[] calldata amountRequested,
uint256[] calldata amountExpected
) external {
uint256 amountCollected;
for (uint256 i = 0; i < currency.length; i++) {
uint256 _amountRequested = amountRequested[i];
uint256 _amountExpected = amountExpected[i];

amountCollected = POOL_MANAGER.collectProtocolFees(tokenJar, currency[i], _amountRequested);
require(
amountCollected >= _amountExpected, AmountCollectedTooLow(amountCollected, _amountExpected)
);
}
}

/// @notice Sets the merkle root for the fee adapter.
/// @dev only callable by owner
/// @param _merkleRoot The merkle root to set.
function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
merkleRoot = _merkleRoot;
}

/// @notice Triggers the fee update for the given pool key.
/// @param _poolKey The pool key to update the fee for.
/// @param newProtocolFee The new protocol fee to set.
/// @param proof The merkle proof corresponding to the set merkle root. Merkle root is generated
/// from leaves of keccak256(abi.encode(poolKey, protocolFee)).
function triggerFeeUpdate(
PoolKey calldata _poolKey,
uint24 newProtocolFee,
bytes32[] calldata proof
) external {
bytes32 node = keccak256(abi.encode(_poolKey, newProtocolFee));
require(MerkleProof.verify(proof, merkleRoot, node), InvalidProof());

POOL_MANAGER.setProtocolFee(_poolKey, newProtocolFee);
}
}
Loading
Loading