// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {Assertion} from "credible-std/Assertion.sol";
import {PhEvm} from "credible-std/PhEvm.sol";
// Check that fee invariants are maintained
contract AmmFeeVerificationAssertion is Assertion {
// Hardcoded whitelist of allowed fee values
uint256 private constant STABLE_POOL_FEE_1 = 1; // 0.1%
uint256 private constant STABLE_POOL_FEE_2 = 15; // 0.15%
uint256 private constant NON_STABLE_POOL_FEE_1 = 25; // 0.25%
uint256 private constant NON_STABLE_POOL_FEE_2 = 30; // 0.30%
function triggers() external view override {
// Register trigger for changes to the fee storage slot
registerStorageChangeTrigger(this.assertFeeVerification.selector, bytes32(uint256(1))); // Assuming fee is in slot 1
}
// Verify that any fee change is to an allowed value
function assertFeeVerification() external view {
// Get the assertion adopter address
IPool adopter = IPool(ph.getAssertionAdopter());
// Get the new fee value and pool type
bool isStable = adopter.stable();
uint256 newFee = uint256(ph.load(address(adopter), bytes32(uint256(1))));
// Check if the new fee is in the whitelist
bool isAllowed = isStable
? (newFee == STABLE_POOL_FEE_1 || newFee == STABLE_POOL_FEE_2)
: (newFee == NON_STABLE_POOL_FEE_1 || newFee == NON_STABLE_POOL_FEE_2);
require(isAllowed, "Fee change to unauthorized value");
// If the simple check passes, verify no unauthorized changes in the callstack
uint256[] memory changes = getStateChangesUint(address(adopter), bytes32(uint256(1)));
// Check each change against the whitelist
for (uint256 i = 0; i < changes.length; i++) {
isAllowed = isStable
? (changes[i] == STABLE_POOL_FEE_1 || changes[i] == STABLE_POOL_FEE_2)
: (changes[i] == NON_STABLE_POOL_FEE_1 || changes[i] == NON_STABLE_POOL_FEE_2);
require(isAllowed, "Unauthorized fee change detected in callstack");
}
}
}
// Aerodrome style interface
interface IPool {
function fee() external view returns (uint256);
function stable() external view returns (bool);
}