Tracer contest - shw's results

Build and trade with Tracer’s Perpetual Swaps and gain leveraged exposure to any market in the world.

General Information

Platform: Code4rena

Start Date: 24/06/2021

Pot Size: $80,000 USDC

Total HM: 18

Participants: 12

Period: 7 days

Judge: cemozer

Total Solo HM: 11

Id: 16

League: ETH

Tracer

Findings Distribution

Researcher Performance

Rank: 5/12

Findings: 5

Award: $7,250.47

🌟 Selected for report: 6

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: 0xsanson

Also found by: shw

Labels

bug
duplicate
3 (High Risk)

Awards

3019.5792 USDC - $3,019.58

External Links

Handle

shw

Vulnerability details

Impact

An attacker can artificially move a market's hourly average price (i.e., the result of getHourlyAvgTracerPrice) by executing a large number of trades on the market with only paying gas fees.

Proof of Concept

The hourly average price is calculated by the cumulativePrice divided by the number of trades in the given hour (i.e., the average of all trade prices). Therefore, an attacker can bias this average price by executing a large number of trades (i.e., calling executeTrade on Trader with many matched orders), and all of them have an extremely high (or low) trade price, as long as the maker and taker's positions are valid after the trade.

The attacker only pays the gas fees without losing the assets since the makers and takers are all his accounts. Besides, the attacker can avoid paying the trade fees if the fillAmount of trade is 0.

Referenced code: Trader.sol#L121-L126 TracerPerpetualSwaps.sol#L280 Pricing.sol#L100 Pricing.sol#L126-L129 Pricing.sol#L254-L256 LibPrices.sol#L41-L49

This attack is generally difficult to prevent since anyone can execute trades and match orders generated by him. A possible mitigation is to modify the hourly average price formula: increase the cumulativePrice by the trade price multiply the fill amount of each trade. As a result, the attacker has to increase the trade volume to move the average price effectively, and thus the charged trade fees are increased for launching such attacks.

#0 - raymogg

2021-07-05T02:58:32Z

Duplicate of issue #119. Worded slightly differently but it comes down to the fact that

  • volume isn't taken into account when computing average price
  • arbitrary execution of orders is possible through the trader

Findings Information

🌟 Selected for report: 0xRajeev

Also found by: a_delamo, cmichel, shw

Labels

bug
duplicate
2 (Med Risk)
sponsor confirmed

Awards

366.8789 USDC - $366.88

External Links

Handle

shw

Vulnerability details

Impact

According to Chainlink's documentation, the latestAnswer function is deprecated. This function does not error if no answer has been reached but returns 0. Besides, the latestAnswer is reported with 18 decimals for crypto quotes but 8 decimals for FX quotes (See Chainlink FAQ for more details). A best practice is to get the decimals from the oracles instead of hard-coding them in the contract.

Proof of Concept

Referenced code: ChainlinkOracleAdapter.sol#L30 GasOracle.sol#L32-L33

Referenced documentation: Chainlink - Deprecated API Reference Chainlink - FAQ Chainlink - Migration Instructions Chainlink - API Reference

Use the latestRoundData function to get the price instead. Add checks on the return data with proper revert messages if the price is stale or the round is uncomplete, for example:

(uint80 roundID, int256 price, , uint256 timeStamp, uint80 answeredInRound) = oracle.latestRoundData();
require(answeredInRound >= roundID, "...");
require(timeStamp != 0, "...");

#0 - loudoguno

2021-08-23T22:47:54Z

closing as duplicate of #73

Findings Information

🌟 Selected for report: s1m0

Also found by: 0xRajeev, JMukesh, Lucius, cmichel, pauliax, shw

Labels

bug
duplicate
2 (Med Risk)

Awards

152.8313 USDC - $152.83

External Links

Handle

shw

Vulnerability details

Impact

In some contracts (e.g., TracerPerpetualSwaps.sol), the return values of ERC20 transfer and transferFrom are not checked to be true, which could be false if the transferred tokens are not ERC20-compliant. In that case, the transfer fails without being noticed by the calling contract.

Proof of Concept

Referenced code: Code using transfer: TracerPerpetualSwaps.sol#L203 TracerPerpetualSwaps.sol#L514 Insurance.sol#L97 SafetyWithdraw.sol#L13

Code using transferFrom: TracerPerpetualSwaps.sol#L151 Insurance.sol#L51

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

#0 - raymogg

2021-07-05T06:08:50Z

Duplicate of #115

#1 - loudoguno

2021-08-24T16:10:41Z

change risk from 1 to 2 as per judges sheet

Findings Information

🌟 Selected for report: shw

Also found by: 0xRajeev

Labels

bug
2 (Med Risk)
sponsor dispute

Awards

905.8738 USDC - $905.87

External Links

Handle

shw

Vulnerability details

Impact

As written in the to-do comments, reentrancy could happen in the executeTrade function of Trader since the makeOrder.market can be a user-controlled external contract.

Proof of Concept

Referenced code: Trader.sol#L121-L126

Add a reentrancy guard (e.g., the implementation from OpenZeppelin) to prevent the users from reentering critical functions.

#0 - raymogg

2021-07-06T01:58:47Z

Disputing just as while this is important, its quite explicitly stated in the todo comment and as such is already known by the team as a potential issue.

Realistically shouldn't be too much of a problem with whitelisting of the trader.

#1 - cemozerr

2021-07-18T19:20:34Z

Marking this as medium risk as, regardless of being noted by the team, still poses a security threat.

#2 - OsmanBran

2021-07-21T02:57:02Z

Duplicate of #72

#3 - loudoguno

2021-08-24T06:04:21Z

removing duplicate label as per judge

#4 - loudoguno

2021-08-24T16:38:44Z

changing risk from 1 to 2 as per judges sheet

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