Summary
The contract lacks proper oracle initialization, creating a potential non-functional state after deployment.
Vulnerability Details
The constructor doesn't initialize the oracle address:
constructor(address initialOwner) Ownable(initialOwner) {
}
Impact
Severity: Medium
Contract starts in non-functional state
All price updates will revert until oracle is set
Integration issues with dependent protocols
Proof of Concept
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("RAACHousePrices", function () {
let prices;
let owner;
let oracle;
let other;
beforeEach(async function () {
[owner, oracle, other] = await ethers.getSigners();
const RAACHousePrices = await ethers.getContractFactory("RAACHousePrices");
prices = await RAACHousePrices.deploy(owner.address);
await prices.deployed();
});
it("should start with uninitialized oracle", async function () {
expect(await prices.oracle()).to.equal(ethers.constants.AddressZero);
});
it("should revert price updates when oracle not set", async function () {
await expect(
prices.connect(oracle).setHousePrice(1, ethers.utils.parseEther("100"))
).to.be.revertedWith("RAACHousePrices: caller is not the oracle");
});
});
Recommendations
Add events and initialization checks:
event OracleUpdated(address indexed previousOracle, address indexed newOracle);
event PriceUpdated(uint256 indexed tokenId, uint256 newPrice, uint256 timestamp);
constructor(address initialOwner, address _oracle) Ownable(initialOwner) {
require(initialOwner != address(0), "RAACHousePrices: owner cannot be zero address");
require(_oracle != address(0), "RAACHousePrices: oracle cannot be zero address");
oracle = _oracle;
emit OracleUpdated(address(0), _oracle);
}
Add token-specific timestamps:
mapping(uint256 => uint256) public tokenUpdateTimestamps;
function setHousePrice(uint256 _tokenId, uint256 _amount) external onlyOracle {
require(_amount > 0, "RAACHousePrices: price cannot be zero");
tokenToHousePrice[_tokenId] = _amount;
tokenUpdateTimestamps[_tokenId] = block.timestamp;
lastUpdateTimestamp = block.timestamp;
emit PriceUpdated(_tokenId, _amount, block.timestamp);
}
Improve oracle management:
function setOracle(address _oracle) external onlyOwner {
require(_oracle != address(0), "RAACHousePrices: oracle cannot be zero address");
address oldOracle = oracle;
oracle = _oracle;
emit OracleUpdated(oldOracle, _oracle);
}
Test Implementation
describe("RAACHousePrices Constructor", function () {
it("should revert with zero addresses", async function () {
const RAACHousePrices = await ethers.getContractFactory("RAACHousePrices");
await expect(
RAACHousePrices.deploy(ethers.constants.AddressZero, oracle.address)
).to.be.revertedWith("RAACHousePrices: owner cannot be zero address");
await expect(
RAACHousePrices.deploy(owner.address, ethers.constants.AddressZero)
).to.be.revertedWith("RAACHousePrices: oracle cannot be zero address");
});
});