Rubicon contest - z3s's results

An order book protocol for Ethereum, built on L2s.

General Information

Platform: Code4rena

Start Date: 23/05/2022

Pot Size: $50,000 USDC

Total HM: 44

Participants: 99

Period: 5 days

Judge: hickuphh3

Total Solo HM: 11

Id: 129

League: ETH

Rubicon

Findings Distribution

Researcher Performance

Rank: 86/99

Findings: 3

Award: $39.20

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Awards

8.2687 USDC - $8.27

Labels

bug
duplicate
2 (Med Risk)
upgraded by judge

External Links

Judge has assessed an item in Issue #408 as Medium risk. The relevant finding follows:

#0 - HickupHH3

2022-06-27T16:04:31Z

[L02] Instead of call(), transfer() is used to withdraw ETH: To withdraw ETH, it uses transfer(), this transaction will fail inevitably when:

The withdrawer smart contract does not implement a payable function. Withdrawer smart contract does implement a payable fallback which uses more than 2300 gas unit. The withdrawer smart contract implements a payable fallback function that needs less than 2300 gas units but is called through proxy, raising the call’s gas usage above 2300.

dup of #82

Lines of code

https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconMarket.sol#L361

Vulnerability details

Impact

    function cancel(uint256 id)
        public
        virtual
        can_cancel(id)
        synchronized
        returns (bool success)
    {
        OfferInfo memory _offer = offers[id];
        delete offers[id];

        require(_offer.pay_gem.transfer(_offer.owner, _offer.pay_amt)); // @audit non-standard compliant tokens like USDT

        emit LogItemUpdate(id);
        emit LogKill(
            bytes32(id),
            keccak256(abi.encodePacked(_offer.pay_gem, _offer.buy_gem)),
            _offer.owner,
            _offer.pay_gem,
            _offer.buy_gem,
            uint128(_offer.pay_amt),
            uint128(_offer.buy_amt),
            uint64(block.timestamp)
        );

        success = true;
    }

if _offer.pay_gem === <USDT_ADDRESS> this function will revert because transfer of usdt does not return anything. and ERC20.transfer want a boolean. so the cancel will never happen if _offer.pay_gem === <USDT_ADDRESS>.

Use OpenZeppelin’s SafeERC20 safeTransfer/safeTransferFrom instead of transfer/transferFrom that handles the return value check as well as non-standard-compliant tokens.

#0 - bghughes

2022-06-04T01:17:29Z

Duplicate of #316

Gas Optimizations

[G01] uint256 default value is 0 so we can remove = 0:

RubiconMarket.sol 990,25: uint256 old_top = 0; RubiconRouter.sol 82,25: uint256 lastBid = 0; 83,25: uint256 lastAsk = 0; 85,28: for (uint256 index = 0; index < topNOrders; index++) { 168,31: uint256 currentAmount = 0; 169,24: for (uint256 i = 0; i < route.length - 1; i++) { 226,31: uint256 currentAmount = 0; 227,24: for (uint256 i = 0; i < route.length - 1; i++) { rubiconPools/BathToken.sol 635,32: for (uint256 index = 0; index < bonusTokens.length; index++) {

[G02] ++i use less gas than i++:

++i costs less gas compared to i++. about 5 gas per iteration.

RubiconRouter.sol 169,51: for (uint256 i = 0; i < route.length - 1; i++) { 227,51: for (uint256 i = 0; i < route.length - 1; i++) {
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