Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Valid

Simultaneous oracle requests might retrieve incorrect house prices

Summary

When house appraisals are requested via Chainlink functions oracle, a hook is triggered to store the house to which the price will be assigned. If a second request is made before completing the first one, in the worst scenario, the second request will be processed first and subsequently the first request. We will end up in a situation where the price of the first house is 0 and the price of the second house is that of the first one.

Vulnerability Details

Inaccurate collateral valuations in the lending pool which can ultimately result in unfair liquidations and loss of users assets or unhealthy users borrowing funds against overvalued collateral.

Impact

Add this test to the house price oracle test:

it("Should simulate fulfillment and update housePrice", async function () {
const lastRequestId = await testOracle.s_lastRequestId();
const fakePriceHouseId1 = 129999; // the response is the house price
const fakePriceHouseId2 = 129999 - 1; // the response is the house price
const responseBytes = new ethers.AbiCoder().encode(["uint256"], [fakePriceHouseId1]);
const responseBytes2 = new ethers.AbiCoder().encode(["uint256"], [fakePriceHouseId2]);
const tx = await testOracle.sendRequest(
"console.log('hello world'); return 129999.99;", // Some JS source
1, // secretsLocation
"0x", // no secrets
["1"], // string[] args - [houseId]
[], // bytes[] bytesArgs
1, // subscriptionId
200000 // callbackGasLimit
);
await tx.wait();
const lastRequestId2 = await testOracle.s_lastRequestId();
const tx2 = await testOracle.sendRequest(
"console.log('hello world'); return 129999.99 - 1;", // Some JS source
1, // secretsLocation
"0x", // no secrets
["2"], // string[] args - [houseId]
[], // bytes[] bytesArgs
1, // subscriptionId
200000 // callbackGasLimit
);
await tx2.wait();
// Simulate the DON calling fulfillRequest for second request
await mockOracle.fulfillRequest(
await testOracle.getAddress(),
lastRequestId2,
responseBytes2,
"0x"
);
// Simulate the DON calling fulfillRequest
await mockOracle.fulfillRequest(
await testOracle.getAddress(),
lastRequestId,
responseBytes,
"0x"
);
// check that the house price has been updated
const [housePrice,] = await housePrices.getLatestPrice(1);
expect(housePrice).to.equal(0);
const [housePrice2,] = await housePrices.getLatestPrice(2);
expect(housePrice2).to.equal(fakePriceHouseId1);
});

Tools Used

Manual review.

Recommendations

Halt requests until the current is processed or store in a mapping the house id using the request id as the key.

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Oracle Race Condition in RAACHousePriceOracle causes price misassignment between NFTs

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Oracle Race Condition in RAACHousePriceOracle causes price misassignment between NFTs

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!