Description:Description\
Seer uses Reality.eth oracle for resolving market outcomes. the RealityProxy.sol is responsible for resolving markets based on the results provided by the Reality.eth oracle. here resolve() function in RealityProxy.sol Resolves the specified market
function resolve(Market market) external {
bytes32[] memory questionsIds = market.questionsIds();
uint256 numOutcomes = market.numOutcomes();
uint256 templateId = market.templateId();
uint256 low = market.lowerBound();
uint256 high = market.upperBound();
// questionId must be a hash of all the values used to resolve a market, this way if an attacker tries to resolve a fake market by changing some value its questionId will not match the id of a valid market.
bytes32 questionId = keccak256(abi.encode(questionsIds, numOutcomes, templateId, low, high));
if (templateId == REALITY_SINGLE_SELECT_TEMPLATE) {
resolveCategoricalMarket(questionId, questionsIds, numOutcomes);//@audit
return;
}
if (templateId == REALITY_MULTI_SELECT_TEMPLATE) {
resolveMultiCategoricalMarket(questionId, questionsIds, numOutcomes);//@audit
return;
}
if (questionsIds.length > 1) {
resolveMultiScalarMarket(questionId, questionsIds, numOutcomes);//@audit
return;
}
resolveScalarMarket(questionId, questionsIds, low, high);
}
the resolve function calls the resolveCategoricalMarket() , resolveMultiCategoricalMarket() and resolveMultiScalarMarket() functions internally and this function uses/calls the realitio for the answer as we can see below
function resolveCategoricalMarket(
bytes32 questionId,
bytes32[] memory questionsIds,
uint256 numOutcomes
) internal {
uint256 answer = uint256(realitio.resultForOnceSettled(questionsIds[0]));//@audit-force typecasting
uint256[] memory payouts = new uint256[](numOutcomes + 1);
if (answer == uint256(INVALID_RESULT) || answer >= numOutcomes) {
// the last outcome is INVALID_RESULT.
payouts[numOutcomes] = 1;
} else {
payouts[answer] = 1;
}
conditionalTokens.reportPayouts(questionId, payouts);
}
but here the function assumes/expects that the resultForOnceSettled returns uint256 but the function actually returns bytes32
function resultForOnceSettled(bytes32 question_id) external view returns (bytes32);
.i.e here the function directly(force) cast the return value(bytes32) to uint256.this issue can lead to unexpected outcomes and it completly depends on the questionId's .the function indeed checks for if (answer == uint256(INVALID_RESULT) || answer >= numOutcomes) i.e for invalid result but this will not enough as mentioned in the dxdao report i.e users submitting answers to oracle questions
may not have any knowledge of the internal workings of Carrot KPI contracts.
i am digging deep in this issue for high impact,i will comment below if i
find any leads.
below is the same issue found in dxdao carrot-kpi contracts
Attack Scenario\
Describe how the vulnerability can be exploited.
Attachments
Proof of Concept (PoC) File
function resolve(Market market) external {
bytes32[] memory questionsIds = market.questionsIds();
uint256 numOutcomes = market.numOutcomes();
uint256 templateId = market.templateId();
uint256 low = market.lowerBound();
uint256 high = market.upperBound();
// questionId must be a hash of all the values used to resolve a market, this way if an attacker tries to resolve a fake market by changing some value its questionId will not match the id of a valid market.
bytes32 questionId = keccak256(abi.encode(questionsIds, numOutcomes, templateId, low, high));
if (templateId == REALITY_SINGLE_SELECT_TEMPLATE) {
resolveCategoricalMarket(questionId, questionsIds, numOutcomes);
return;
}
if (templateId == REALITY_MULTI_SELECT_TEMPLATE) {
resolveMultiCategoricalMarket(questionId, questionsIds, numOutcomes);
return;
}
if (questionsIds.length > 1) {
resolveMultiScalarMarket(questionId, questionsIds, numOutcomes);//@audit
return;
}
resolveScalarMarket(questionId, questionsIds, low, high);
}
function resolveCategoricalMarket(
bytes32 questionId,
bytes32[] memory questionsIds,
uint256 numOutcomes
) internal {
uint256 answer = uint256(realitio.resultForOnceSettled(questionsIds[0]));//@audit-force typecasting
uint256[] memory payouts = new uint256[](numOutcomes + 1);
if (answer == uint256(INVALID_RESULT) || answer >= numOutcomes) {
// the last outcome is INVALID_RESULT.
payouts[numOutcomes] = 1;
} else {
payouts[answer] = 1;
}
conditionalTokens.reportPayouts(questionId, payouts);
}
Github username: -- Twitter username: -- Submission hash (on-chain): 0x47589bae62963903162ca8d2f4c437c889135d38e9bcf7e29b3dfec6810c06f9 Severity: medium
Description: Description\
Seer
usesReality.eth
oracle for resolving market outcomes. theRealityProxy.sol
is responsible for resolving markets based on the results provided by theReality.eth
oracle. hereresolve()
function in RealityProxy.sol Resolves the specified marketthe
resolve
function calls theresolveCategoricalMarket()
,resolveMultiCategoricalMarket()
andresolveMultiScalarMarket()
functions internally and this function uses/calls therealitio
for theanswer
as we can see belowbut here the function assumes/expects that the
resultForOnceSettled
returnsuint256
but the function actually returnsbytes32
.i.e here the function directly(force) cast the return value(
bytes32
) touint256
.this issue can lead to unexpected outcomes and it completly depends on thequestionId's
.the function indeed checks forif (answer == uint256(INVALID_RESULT) || answer >= numOutcomes)
i.e for invalid result but this will not enough as mentioned in the dxdao report i.e users submitting answers to oracle questions may not have any knowledge of the internal workings of Carrot KPI contracts.i am digging deep in this issue for high impact,i will comment below if i find any leads.
below is the same issue found in
dxdao
carrot-kpi contractsissue id: CAR-01
https://github.com/sigp/public-audits/blob/master/reports/dxdao/carrot-kpi/review.pdf
https://github.com/carrot-kpi/contracts/commit/a642398b5d71aaf55f9c52ba3632d3fb30865855
Attack Scenario\ Describe how the vulnerability can be exploited.
Attachments
Proof of Concept (PoC) File
Revised Code File (Optional)
will provide in the comments