Reality Cards contest - shw's results

The world's first 'outcome ownership' prediction market.

General Information

Platform: Code4rena

Start Date: 10/06/2021

Pot Size: $45,000 USDC

Total HM: 21

Participants: 12

Period: 7 days

Judge: LSDan

Total Solo HM: 13

Id: 13

League: ETH

Reality Cards

Findings Distribution

Researcher Performance

Rank: 5/12

Findings: 5

Award: $3,103.21

🌟 Selected for report: 2

🚀 Solo Findings: 1

Findings Information

🌟 Selected for report: axic

Also found by: JMukesh, a_delamo, cmichel, gpersoon, pauliax, s1m0, shw

Labels

bug
duplicate
3 (High Risk)

Awards

259.5075 USDC - $259.51

External Links

Handle

shw

Vulnerability details

Impact

In the contract RCTreasury, the return values of ERC20 transfer and transferFrom are not checked, which could be false if the transferred token is not ERC20-compliant. In that case, the transfer fails without being noticed by the calling contract.

Proof of Concept

Referenced code: RCTreasury.sol#L350 RCTreasury.sol#L298 RCTreasury.sol#L373 RCTreasury.sol#L478

Use the SafeERC20 library implementation from Openzeppelin and call safeTransfer or safeTransferFrom when transferring ERC20 tokens.

#0 - Splidge

2021-06-17T10:47:29Z

Duplicate of #2

#1 - dmvt

2021-07-11T12:38:14Z

duplicate of #2

Findings Information

🌟 Selected for report: pauliax

Also found by: 0xRajeev, cmichel, shw

Labels

bug
duplicate
3 (High Risk)

Awards

791.0609 USDC - $791.06

External Links

Handle

shw

Vulnerability details

Impact

The function sponsor(address _sponsorAddress, uint256 _amount) in RCMarket is permissionless, which allows a malicious actor to sponsor any market in the name of some sponsor as long as enough tokens are approved. The malicious actor could then add sponsorship to markets where he will likely become the winner to gain more winning awards.

Proof of Concept

  1. Suppose there are two opening markets, MarketA and MarketB. A sponsor, Alice, wants to sponsor MarketA with 100 amounts of DAI. So, after approving the treasury to send her tokens, she calls sponsor(100) on MarketA.
  2. A malicious actor, Bob, listens to the mempool and notices Alice's transaction. He then front-runs the transaction and calls sponsor(Alice, 100) on MarketB.
  3. Bob's transaction is executed, and the treasury transfers 100 DAI from Alice to MarketB, which is not Alice's intention.

Besides front-running, Bob can also check the past transactions to find anyone who approved the treasury before. If the current allowance is greater than zero, he can call sponsor directly with the victim's address as the parameter to sponsor any market he wants.

Referenced code: RCMarket.sol#L817-L822

Should check if the caller of the function sponsor(address _sponsorAddress, uint256 _amount) is the factory.

#0 - Splidge

2021-06-17T10:43:37Z

Duplicate of #40

#1 - dmvt

2021-07-11T12:39:54Z

duplicate of #40

Findings Information

🌟 Selected for report: jvaqa

Also found by: 0xRajeev, pauliax, shw

Labels

bug
duplicate
2 (Med Risk)

Awards

237.3183 USDC - $237.32

External Links

Handle

shw

Vulnerability details

Impact

In the function createMarket of RCFactory, the market opening time is not checked before the market locking time, and thus markets can be created with invalid time configurations accidentally. Besides, if the advancedWarning is non-zero, there are two checks applied, and the first seems unnecessary (which is a requirement of the second one).

Proof of Concept

Referenced code: RCFactory.sol#L520-L527

Check that the market opening time is before both the market locking time. In cases where advancedWarning is non-zero, if the purpose of the first check is to prevent subtraction overflow on the second check, consider removing the first one and re-writing the second one as _timestamps[0] > block.timestamp + advancedWarning.

#0 - Splidge

2021-06-17T10:54:47Z

Duplicate of #61

#1 - dmvt

2021-07-10T13:43:28Z

duplicate of #61

Findings Information

🌟 Selected for report: shw

Labels

bug
2 (Med Risk)
sponsor confirmed
resolved

Awards

1302.1578 USDC - $1,302.16

External Links

Handle

shw

Vulnerability details

Impact

The function foreclosureTimeUser of RCTreasury underestimates the user's foreclosure time if the current time is not the user's last rent calculation time. The underestimation of the foreclosure time could cause wrong results when determining the new owner of the card.

Proof of Concept

The variable timeLeftOfDeposit at line 668 is calculated based on depositAbleToWithdraw(_user), the user's deposit minus the rent from the last rent calculation to the current time. Thus, the variable timeLeftOfDeposit indicates the time left of deposit, starting from now. However, at line 672, the foreclosureTimeWithoutNewCard is calculated by timeLeftOfDeposit plus the user's last rent calculation time instead of the current time. As a result, the user's foreclosure time is reduced. From another perspective, the rent between the last rent calculation time and the current time is counted twice.

Referenced code: RCTreasury.sol#L642-L653 RCTreasury.sol#L669 RCTreasury.sol#L672 RCTreasury.sol#L678 RCOrderbook.sol#L553-L557

Change depositAbleToWithdraw(_user) at line 669 to user[_user].deposit. Or, change user[_user].lastRentCalc at both line 672 and 678 to block.timestamp.

#0 - Splidge

2021-06-22T09:58:07Z

phew, this was one to wrap your head around. I went with the first recommended mitigation because I believe the second one could causes issues if the user had already foreclosed, depositAbleToWithdraw would return 0 and so foreclosureTimeWithoutNewCard would incorrectly show as block.timestamp. Fix implemented here

Really nice spot this one. Many thanks for such an in-depth look into the maths.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter