// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {Test} from "forge-std/Test.sol"; import {Aggregator} from "../contracts/oracle/Aggregator.sol"; contract AggregatorFuzzTest is Test { Aggregator aggregator; address admin; address transmitter; address user; function setUp() public { admin = address(1); transmitter = address(2); user = address(3); vm.prank(admin); aggregator = new Aggregator( "ETH/USD Price Feed", admin, 60, // heartbeat: 60 seconds 50 // deviationThreshold: 0.5% (50 basis points) ); vm.prank(admin); aggregator.addTransmitter(transmitter); } function testFuzzUpdateAnswer(uint256 answer) public { vm.assume(answer > 0); vm.assume(answer < type(uint256).max / 100000000); // Prevent overflow vm.prank(transmitter); aggregator.updateAnswer(answer); // forge-lint: disable-next-line(unsafe-typecast) // casting to 'int256' is safe because answer is constrained to prevent overflow assertEq(aggregator.latestAnswer(), int256(answer)); } function testFuzzMultipleUpdates(uint256[10] memory answers) public { uint256 lastAnswer = 0; for (uint i = 0; i < answers.length; i++) { vm.assume(answers[i] > 0); vm.assume(answers[i] < type(uint256).max / 100000000); // Ensure sufficient deviation (0.5% = 50 basis points) to trigger update // If this is the first update or deviation is >= 0.5%, it will update if (lastAnswer == 0 || (answers[i] > lastAnswer ? ((answers[i] - lastAnswer) * 10000) / lastAnswer >= 50 : ((lastAnswer - answers[i]) * 10000) / lastAnswer >= 50)) { vm.prank(transmitter); aggregator.updateAnswer(answers[i]); // forge-lint: disable-next-line(unsafe-typecast) // casting to 'int256' is safe because answers[i] is constrained to prevent overflow assertEq(aggregator.latestAnswer(), int256(answers[i])); lastAnswer = answers[i]; } else { // If deviation is too small, the answer won't update // Skip this iteration or use a different answer continue; } } } function testFuzzAddTransmitter(address newTransmitter) public { vm.assume(newTransmitter != address(0)); vm.assume(newTransmitter != admin); vm.assume(newTransmitter != transmitter); vm.prank(admin); aggregator.addTransmitter(newTransmitter); assertTrue(aggregator.isTransmitter(newTransmitter)); } function testFuzzSetHeartbeat(uint256 heartbeat) public { vm.assume(heartbeat > 0); vm.assume(heartbeat < type(uint256).max / 2); vm.prank(admin); aggregator.updateHeartbeat(heartbeat); assertEq(aggregator.heartbeat(), heartbeat); } function testFuzzSetDeviationThreshold(uint256 threshold) public { vm.assume(threshold <= 10000); // Max 100% vm.prank(admin); aggregator.updateDeviationThreshold(threshold); assertEq(aggregator.deviationThreshold(), threshold); } }