Summary
Incorrect horse happiness check in IS_HAPPY_HORSE() macro.
It makes the horse happy if it hasn't eaten for more than 1 day
Vulnerability Details
The logic error in macro IS_HAPPY_HORSE()
lt
start_return_true jumpi
HORSE_HAPPY_IF_FED_WITHIN < timestamp - horseFedTimestamp = timestamp > HORSE_HAPPY_IF_FED_WITHIN + horseFedTimestamp
,
but it is not correct
The correct condition is
timestamp < HORSE_HAPPY_IF_FED_WITHIN + horseFedTimestamp = HORSE_HAPPY_IF_FED_WITHIN > timestamp - horseFedTimestamp
PoC:
abstract contract Base_Test is Test {
HorseStore horseStore;
address user = makeAddr("user");
string public constant NFT_NAME = "HorseStore";
string public constant NFT_SYMBOL = "HS";
function setUp() public virtual {
horseStore = new HorseStore();
vm.warp(horseStore.HORSE_HAPPY_IF_FED_WITHIN());
}
function testFeedingMakesHappyHorse() public {
uint256 horseId = horseStore.totalSupply();
vm.prank(user);
horseStore.mintHorse();
horseStore.feedHorse(horseId);
vm.warp(block.timestamp + 10);
assertEq(horseStore.isHappyHorse(horseId), true);
}
}
Run:
forge test --mt testFeedingMakesHappyHorse -vvv
Result:
Running 1 test for test/HorseStoreSolidity.t.sol:HorseStoreSolidity
[PASS] testFeedingMakesHappyHorse() (gas: 114916)
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 32.67ms
Running 1 test for test/HorseStoreHuff.t.sol:HorseStoreHuff
[FAIL. Reason: assertion failed] testFeedingMakesHappyHorse() (gas: 99708)
Logs:
Error: a == b not satisfied [bool]
Left: false
Right: true
Traces:
[99708] HorseStoreHuff::testFeedingMakesHappyHorse()
├─ [2149] 0x6d2eed85750d316088343D6d5e91ca59eb052768::totalSupply() [staticcall]
│ └─ ← 0x0000000000000000000000000000000000000000000000000000000000000000
├─ [0] VM::prank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← ()
├─ [48831] 0x6d2eed85750d316088343D6d5e91ca59eb052768::61fc6a67()
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], tokenId: 0)
│ └─ ← ()
├─ [22239] 0x6d2eed85750d316088343D6d5e91ca59eb052768::c65e2eaa(0000000000000000000000000000000000000000000000000000000000000000)
│ └─ ← ()
├─ [0] VM::warp(11)
│ └─ ← ()
├─ [290] 0x6d2eed85750d316088343D6d5e91ca59eb052768::62134726(0000000000000000000000000000000000000000000000000000000000000000) [staticcall]
│ └─ ← 0x0000000000000000000000000000000000000000000000000000000000000000
├─ emit log(val: "Error: a == b not satisfied [bool]")
├─ emit log_named_string(key: " Left", val: "false")
├─ emit log_named_string(key: " Right", val: "true")
├─ [0] VM::store(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 0x6661696c65640000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000001)
│ └─ ← ()
└─ ← ()
Test result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 1.72s
Ran 2 test suites: 1 tests passed, 1 failed, 0 skipped (2 total tests)
Failing tests:
Encountered 1 failing test in test/HorseStoreHuff.t.sol:HorseStoreHuff
[FAIL. Reason: assertion failed] testFeedingMakesHappyHorse() (gas: 99708)
So it passed for solidity version and failed for Huff version.
Impact
Incorrect condition check brakes business logic.
Tools Used
forge test
Recommendations
Update IS_HAPPY_HORSE() macro:
[HORSE_HAPPY_IF_FED_WITHIN_CONST] // [HORSE_HAPPY_IF_FED_WITHIN, timestamp - horseFedTimestamp, timestamp, horseFedTimestamp]
- lt // [HORSE_HAPPY_IF_FED_WITHIN < timestamp - horseFedTimestamp, timestamp, horseFedTimestamp]
+ gt // [HORSE_HAPPY_IF_FED_WITHIN > timestamp - horseFedTimestamp, timestamp, horseFedTimestamp]
start_return_true jumpi // [timestamp, horseFedTimestamp]```