Description
The RAACHousePrices contract tracks house prices and their update timestamps for each token ID. The contract uses a single global lastUpdateTimestamp variable for all tokens, causing the timestamp of previous token updates to be overwritten when any token's price is created or updated.
function setHousePrice(
uint256 _tokenId,
uint256 _amount
) external onlyOracle {
tokenToHousePrice[_tokenId] = _amount;
@> lastUpdateTimestamp = block.timestamp;
emit PriceUpdated(_tokenId, _amount);
}
Risk
Likelihood: High
Impact: Low
Proof of Concept
function testGetLastestPriceFromHousePrices() public {
vm.startPrank(owner);
RAACHousePrices housePrices = new RAACHousePrices(owner);
housePrices.setOracle(owner);
vm.stopPrank();
uint256 tokenId = 1;
uint256 tokenId2 = 2;
uint256 price = 100 ether;
uint256 price2 = 200 ether;
address oracle = housePrices.oracle();
vm.startPrank(oracle);
housePrices.setHousePrice(tokenId, price);
vm.warp(block.timestamp + 30 days);
housePrices.setHousePrice(tokenId2, price2);
vm.stopPrank();
(, uint256 firstHousePriceTimestamp) = housePrices.getLatestPrice(tokenId);
console.log("firstHousePriceTimestamp", firstHousePriceTimestamp);
(, uint256 secondHousePriceTimestamp) = housePrices.getLatestPrice(tokenId2);
console.log("secondHousePriceTimestamp", secondHousePriceTimestamp);
assertEq(firstHousePriceTimestamp, secondHousePriceTimestamp, "Timestamp should not be identical");
}
Recommended Mitigation
contract RAACHousePrices {
- mapping(uint256 => uint256) public tokenToHousePrice;
- uint256 public lastUpdateTimestamp;
+ struct PriceData {
+ uint256 price;
+ uint256 timestamp;
+ }
+ mapping(uint256 => PriceData) public tokenToPriceData;
function setHousePrice(uint256 _tokenId, uint256 _price) external onlyOracle {
- tokenToHousePrice[tokenId] = price;
- lastUpdateTimestamp = block.timestamp;
+ tokenToPriceData[_tokenId] = PriceData({
+ price: _price,
+ timestamp: block.timestamp
+ });
}
function getLatestPrice(uint256 _tokenId) external view returns (uint256, uint256) {
- return (tokenToHousePrice[_tokenId], lastUpdateTimestamp);
+ PriceData memory data = tokenToPriceData[_tokenId];
+ return (data.price, data.timestamp);
}
}