Tracer contest - a_delamo'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: 11/12

Findings: 3

Award: $881.38

🌟 Selected for report: 1

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: 0xRajeev

Also found by: a_delamo, cmichel, shw

Labels

bug
duplicate
2 (Med Risk)

Awards

366.8789 USDC - $366.88

External Links

Handle

a_delamo

Vulnerability details

Impact

Use latestRoundData instead of latestAnswer for chainlink Oracles in order to be able to run more validations like

( roundId, rawPrice, , updateTime, answeredInRound ) = AggregatorV3Interface(source.source).latestRoundData(); require(rawPrice > 0, "Chainlink price <= 0"); require(updateTime != 0, "Incomplete round"); require(answeredInRound >= roundId, "Stale price");

Proof of Concept

Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

Tools Used

#0 - raymogg

2021-07-05T06:10:19Z

Duplicate of #145

#1 - loudoguno

2021-08-24T16:06:41Z

changed risk from 1 to 2 as per judges sheet

Findings Information

🌟 Selected for report: 0xRajeev

Also found by: a_delamo, pauliax

Labels

bug
duplicate
1 (Low Risk)
sponsor confirmed

Awards

181.1748 USDC - $181.17

External Links

Handle

a_delamo

Vulnerability details

Impact

The method executeTrade on Trader.sol is calling matchOrders method of the TracerPerpetualSwaps contract. executeTrade is validating that the call was successful, but is missing to validate the return result == true. As a result, we will be adding invalid trade.


            (bool success, ) = makeOrder.market.call(
                abi.encodePacked(
                    ITracerPerpetualSwaps(makeOrder.market).matchOrders.selector,
                    abi.encode(makeOrder, takeOrder, fillAmount)
                )
            );

            // ignore orders that cannot be executed
            //FIXME: We should also check if return == false
            if (!success) continue;

            // update order state
            filled[makerOrderId] = makeOrderFilled + fillAmount;
            filled[takerOrderId] = takeOrderFilled + fillAmount;
            averageExecutionPrice[makerOrderId] = newMakeAverage;
            averageExecutionPrice[takerOrderId] = newTakeAverage;
                ....
                // validate orders can match, and outcome state is valid
		if (
			!Perpetuals.canMatch(order1, filled1, order2, filled2) ||
			!Balances.marginIsValid(
				newPos1,
				balances[order1.maker].lastUpdatedGasPrice *
					LIQUIDATION_GAS_COST,
				pricingContract.fairPrice(),
				trueMaxLeverage()
			) ||
			!Balances.marginIsValid(
				newPos2,
				balances[order2.maker].lastUpdatedGasPrice *
					LIQUIDATION_GAS_COST,
				pricingContract.fairPrice(),
				trueMaxLeverage()
			)
		) {
			// emit failed to match event and return false
			if (order1.side == Perpetuals.Side.Long) {
				emit FailedOrders(
					order1.maker,
					order2.maker,
					order1Id,
					order2Id
				);
			} else {
				emit FailedOrders(
					order2.maker,
					order1.maker,
					order2Id,
					order1Id
				);
			}
			return false;
		}
                ....

#0 - loudoguno

2021-08-24T16:55:10Z

adding duplicate label (of #71 ) and closing as per judges sheet

Findings Information

🌟 Selected for report: a_delamo

Labels

bug
G (Gas Optimization)
sponsor confirmed

Awards

333.3333 USDC - $333.33

External Links

Handle

a_delamo

Vulnerability details

Impact

For every new TracerPerpetualSwaps contract, we need to deploy a new Liquidation, Insurance, and Pricing contract. All these deployments are really gas-intensive, so it would be recommended to use EIP-1167: Minimal Proxy Contract to reduce the gas cost of the deployments.

function _deployTracer(
        bytes calldata _data,
        address tracerOwner,
        address oracle,
        address fastGasOracle,
        uint256 maxLiquidationSlippage
    ) internal returns (address) {
        // Create and link tracer to factory
        address market = IPerpsDeployer(perpsDeployer).deploy(_data);
        ITracerPerpetualSwaps tracer = ITracerPerpetualSwaps(market);

        validTracers[market] = true;
        tracersByIndex[tracerCounter] = market;
        tracerCounter++;

        // Instantiate Insurance contract for tracer
        address insurance = IInsuranceDeployer(insuranceDeployer).deploy(market);
        address pricing = IPricingDeployer(pricingDeployer).deploy(market, insurance, oracle);
        address liquidation = ILiquidationDeployer(liquidationDeployer).deploy(
            pricing,
            market,
            insurance,
            fastGasOracle,
            maxLiquidationSlippage
        );

        // Perform admin operations on the tracer to finalise linking
        tracer.setInsuranceContract(insurance);
        tracer.setPricingContract(pricing);
        tracer.setLiquidationContract(liquidation);

        // Ownership either to the deployer or the DAO
        tracer.transferOwnership(tracerOwner);
        ILiquidation(liquidation).transferOwnership(tracerOwner);
        emit TracerDeployed(tracer.marketId(), address(tracer));
        return market;
    }

More info: https://blog.openzeppelin.com/deep-dive-into-the-minimal-proxy-contract/ https://eips.ethereum.org/EIPS/eip-1167

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