Abracadabra Mimswap - Bauchibred's results

General Information

Platform: Code4rena

Start Date: 07/03/2024

Pot Size: $63,000 USDC

Total HM: 20

Participants: 36

Period: 5 days

Judge: cccz

Total Solo HM: 11

Id: 349

League: BLAST

Abracadabra Money

Findings Distribution

Researcher Performance

Rank: 5/36

Findings: 2

Award: $2,258.68

๐ŸŒŸ Selected for report: 1

๐Ÿš€ Solo Findings: 1

Findings Information

๐ŸŒŸ Selected for report: Bauchibred

Labels

bug
2 (Med Risk)
primary issue
satisfactory
selected for report
sponsor acknowledged
sufficient quality report
M-08

Awards

2068.8771 USDC - $2,068.88

External Links

Lines of code

https://github.com/code-423n4/2024-03-abracadabra-money/blob/1f4693fdbf33e9ad28132643e2d6f7635834c6c6/src/mimswap/periphery/Factory.sol#L81-L90

Vulnerability details

Proof of Concept

Take a look at https://github.com/code-423n4/2024-03-abracadabra-money/blob/1f4693fdbf33e9ad28132643e2d6f7635834c6c6/src/mimswap/periphery/Factory.sol#L81-L90

    function create(address baseToken_, address quoteToken_, uint256 lpFeeRate_, uint256 i_, uint256 k_) external returns (address clone) {
        address creator = tx.origin;

        bytes32 salt = _computeSalt(creator, baseToken_, quoteToken_, lpFeeRate_, i_, k_);
        clone = LibClone.cloneDeterministic(address(implementation), salt);
        IMagicLP(clone).init(address(baseToken_), address(quoteToken_), lpFeeRate_, address(maintainerFeeRateModel), i_, k_);

        emit LogCreated(clone, baseToken_, quoteToken_, creator, lpFeeRate_, maintainerFeeRateModel, i_, k_);
        _addPool(creator, baseToken_, quoteToken_, clone);
    }

We can see that this function uses the create() logic and depends on the tx.origin, now Blast is suspicious of a reorg attack and protocol would be deployed on here.

Where as one can assume that the tx.origin should be different for different calls this is not really the case as going to the Blast Explorer for transactions that are currently enqueued we can see that only two addresses are rampant as the tx.origin, i.e 0x4b16E5d33D7ab3864d53aAec93c8301C1FA4a226 and 0x6e5572f31bd9385709ec61305Afc749F0fa8fae1 what this leads is the fact that another user can just wait and due to a re-org take control of the magic lp deployment, since the tx.origin in this case would be the same with original deployer's own.

Impact

Now, if users rely on the address derivation in advance or try to deploy the magiclp with the same address, any funds/tokens sent to it could potentially be withdrawn by anyone else. All in all, it could lead to the theft of user funds.

Try the deployment using create2 with salt that includes real msg.sender.

Assessed type

Context

#0 - 0xm3rlin

2024-03-15T00:42:56Z

informational, no factor

#1 - c4-pre-sort

2024-03-15T13:40:45Z

141345 marked the issue as sufficient quality report

#2 - 141345

2024-03-15T13:40:47Z

seems invalid, reorg won't cause addr change

#3 - c4-sponsor

2024-03-15T17:40:02Z

0xCalibur (sponsor) acknowledged

#4 - 0xCalibur

2024-03-15T17:40:40Z

That was fixed meanwhile this contest happen. We now use the creator address as part of the salt

see here https://github.com/Abracadabra-money/abracadabra-money-contracts/blob/main/src/mimswap/periphery/Factory.sol

#5 - c4-judge

2024-03-29T09:23:56Z

thereksfour marked the issue as satisfactory

#6 - thereksfour

2024-03-29T12:31:01Z

https://docs.code4rena.com/roles/judges/how-to-judge-a-contest#notes-on-judging

Unless there is something uniquely novel created by combining vectors, most submissions regarding vulnerabilities that are inherent to a particular system or the Ethereum network as a whole should be considered QA. Examples of such vulnerabilities include front running, sandwich attacks, and MEV. In such events, leave a comment on the issue:

As per the c4 docs, will downgrade to QA

#7 - c4-judge

2024-03-29T12:31:07Z

thereksfour changed the severity to QA (Quality Assurance)

#8 - lanrebayode

2024-04-02T17:50:27Z

Thanks for judging @c4-judge,

I wanted to bring to your attention an issue regarding the grading process. I've noticed that several downgraded issues, specifically #225, #211, #208, and #18, have been acknowledged by the sponsor but have not yet been graded. This seems to be the case for other downgraded issues as well.

#9 - Bauchibred

2024-04-03T10:39:30Z

Hi @thereksfour, thanks for judging, in regards to this:

https://docs.code4rena.com/roles/judges/how-to-judge-a-contest#notes-on-judging

Unless there is something uniquely novel created by combining vectors, most submissions regarding vulnerabilities that are inherent to a particular system or the Ethereum network as a whole should be considered QA. Examples of such vulnerabilities include front running, sandwich attacks, and MEV. In such events, leave a comment on the issue:

As per the c4 docs, will downgrade to QA

The idea of using this rule as the grounds for downgrading this issue seems to be flawed, cause considering this rule, do we now say all front running, MEV bug ideas are invalid on Code4rena? We beg to differ as context really matters for bug cases like this.

In fact a similar discussion around this bug case (very similar instance) was held a short while ago, can be seen here, and the deciding lines of the validity of the report not being a medium severity was the fact that in that instance the protocol was to be deployed on Canto, and Canto is a fork of Evmos/Ethermint, so it uses Tendermint Core BFT consensus, which provides a 1-block finality and not probabilisitic finality like other chains: https://docs.ethermint.zone/core/pending_state.html

But thatโ€™s not the case we have here, in this case protocol is to be deployed on Blast

  1. Blast is an optimistic rollup, just like Arbritrum, Base, Optimism, etc.
  2. Optimistic rollups are known for having re-org issues.
  3. Not all current satisfactory H/M issues have been fixed by the protocol, but this was not only confirmed by the protocol but also addressed in this commit, proving that this issue is of great value to them and accepted by them to be worthy a fix.

Considering all the above arguments, weโ€™d request a reassessment of this finding being validated as medium severity, thank you.

#10 - thereksfour

2024-04-04T15:38:17Z

These facts raise the likelihood of this issue, will reconsider it as M

  1. Blast is an optimistic rollup, just like Arbritrum, Base, Optimism, etc.
  2. Optimistic rollups are known for having re-org issues.

#11 - c4-judge

2024-04-05T07:30:41Z

This previously downgraded issue has been upgraded by thereksfour

#12 - c4-judge

2024-04-05T07:30:41Z

This previously downgraded issue has been upgraded by thereksfour

#13 - c4-judge

2024-04-05T07:30:47Z

thereksfour marked the issue as selected for report

#14 - c4-judge

2024-04-05T07:30:52Z

thereksfour marked the issue as primary issue

Awards

189.8 USDC - $189.80

Labels

bug
grade-a
QA (Quality Assurance)
sufficient quality report
Q-06

External Links

QA Report for Abracadabra

Table of Contents

Issue IDDescription
QA-01Protocol hardcodes acceptable tokens to 18 decimals
QA-02Unhandled Chainlink revert would halt core functionalities
QA-03Unused local variables should be removed
QA-04Always implement CEI patterns where possible
QA-05Unnamed return variable can remain unassigned

QA-01 Protocol hardcodes acceptable tokens to 18 decimals

Proof of Concept

Take a look at https://github.com/code-423n4/2024-03-abracadabra-money/blob/1f4693fdbf33e9ad28132643e2d6f7635834c6c6/src/oracles/aggregators/MagicLpAggregator.sol#L16

    uint256 public constant WAD = 18;

See this https://github.com/code-423n4/2024-03-abracadabra-money/blob/1f4693fdbf33e9ad28132643e2d6f7635834c6c6/src/oracles/aggregators/MagicLpAggregator.sol#L37-L48

    //@audit chainlink issues
    function latestAnswer() public view override returns (int256) {
       //@audit
        uint256 baseAnswerNomalized = uint256(baseOracle.latestAnswer()) * (10 ** (WAD - baseOracle.decimals()));
        uint256 quoteAnswerNormalized = uint256(quoteOracle.latestAnswer()) * (10 ** (WAD - quoteOracle.decimals()));
        uint256 minAnswer = baseAnswerNomalized < quoteAnswerNormalized ? baseAnswerNomalized : quoteAnswerNormalized;

        (uint256 baseReserve, uint256 quoteReserve) = _getReserves();
       //@audit
        baseReserve = baseReserve * (10 ** (WAD - baseDecimals));
        quoteReserve = quoteReserve * (10 ** (WAD - quoteDecimals));
        return int256(minAnswer * (baseReserve + quoteReserve) / pair.totalSupply());
    }

Evidently protocol assumes in four instances that the decimals would always be < 18, i.e in a case where the decimals are above 18 for either of tokens or oracles then this attempt to query the price always reverts

Impact

Medium to low depending on if plans on supporting tokens whose decimals or their price feed decimals would be more than 18, cause currently protocol is incompatible with some popular tokens out there, limiting adoption.

Consider reimplementing the logic and accept tokens that have more than 18 decimals.

QA-02 Unhandled Chainlink revert would halt core functionalities

Proof of Concept

Take a look at https://github.com/code-423n4/2024-03-abracadabra-money/blob/1f4693fdbf33e9ad28132643e2d6f7635834c6c6/src/oracles/aggregators/MagicLpAggregator.sol#L38-L51

    function latestAnswer() public view override returns (int256) {
        uint256 baseAnswerNomalized = uint256(baseOracle.latestAnswer()) * (10 ** (WAD - baseOracle.decimals()));
        uint256 quoteAnswerNormalized = uint256(quoteOracle.latestAnswer()) * (10 ** (WAD - quoteOracle.decimals()));
        uint256 minAnswer = baseAnswerNomalized < quoteAnswerNormalized ? baseAnswerNomalized : quoteAnswerNormalized;

        (uint256 baseReserve, uint256 quoteReserve) = _getReserves();
        baseReserve = baseReserve * (10 ** (WAD - baseDecimals));
        quoteReserve = quoteReserve * (10 ** (WAD - quoteDecimals));
        return int256(minAnswer * (baseReserve + quoteReserve) / pair.totalSupply());
    }

    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {
        return (0, latestAnswer(), 0, 0, 0);
    }

Evidently we can see that this is the logic for getting prices that's implemented in the protocol, note that a call to latestRoundData() actually just queries latestAnswer()

But also we can see that this call lacks error handling for the potential failure of feedConfig.feed.latestRoundData(), note that Chainlink pricefeeds could revert due to whatever reason, i.e say maintenance or maybe the Chainlink team decide to change the underlying address. Now this omission of not considering this call failing would lead to systemic issues, since calls to this would now revert halting any action that requires this call to succeed.

Here is a minimalistic POC proving the issue:

TokenA has a minPrice of $1. The price of TokenA drops to $0.10. The aggregator still returns $1 allowing the user to interact with TokenA as if it is $1 which is 10x it's actual value.

Impact

A revert of the entire operation that requires querying the Chainlink pricing logic, This limitation poses a significant risk, since all three pricing modes that use the Chainlink mode either as a primary or secondary source would now revert.

Wrap the feedConfig.feed.latestRoundData() call in a try-catch block, and consider introducing a fallback oracle incase the call to chainlink reverts.

QA-03 Unused local variables should be removed

Proof of Concept

Take a look at some of the instances from code

  --> script/BlastOnboarding.s.sol:17:9:
   |
17 |         address blastGovernor = toolkit.getAddress(block.chainid, "blastGovernor");
   |         ^^^^^^^^^^^^^^^^^^^^^

  --> src/oracles/aggregators/MagicLpAggregator.sol:34:10:
   |
34 |         (uint256 baseReserve, uint256 quoteReserve) = pair.getReserves();
   |          ^^^^^^^^^^^^^^^^^^^

  --> src/oracles/aggregators/MagicLpAggregator.sol:34:31:
   |
34 |         (uint256 baseReserve, uint256 quoteReserve) = pair.getReserves();
   |                               ^^^^^^^^^^^^^^^^^^^^

Impact

Low, bad code structuring, makes it harder for bith users and developers to understnad code

Either use the valriables or remove them from code

QA-04 Always implement CEI patterns where possible

Proof of Concept

Take a look athttps://github.com/code-423n4/2024-03-abracadabra-money/blob/1f4693fdbf33e9ad28132643e2d6f7635834c6c6/src/staking/LockingMultiRewards.sol#L458-L478

    function _stakeFor(address account, uint256 amount, bool lock_) internal {
        if (amount == 0) {
            revert ErrZeroAmount();
        }

        // This staking contract isn't using balanceOf, so it's safe to transfer immediately
        stakingToken.safeTransferFrom(msg.sender, address(this), amount);
        stakingTokenBalance += amount;

        _updateRewardsForUser(account);

        if (lock_) {
            _createLock(account, amount);
        } else {
            _balances[account].unlocked += amount;
            unlockedSupply += amount;

            emit LogStaked(account, amount);
        }
    }

We can see that the CEI pattern is not followed

Impact

Low, code is not following the best practise.

It's always great practise to follow the check effects interaction pattern

QA-05 Unnamed return variable can remain unassigned

Take a look at some of the instances from code

  --> src/oracles/aggregators/MagicLpAggregator.sol:33:60:
   |
33 |     function _getReserves() internal view virtual returns (uint256, uint256) {
   |                                                            ^^^^^^^
  --> src/oracles/aggregators/MagicLpAggregator.sol:33:69:
   |
33 |     function _getReserves() internal view virtual returns (uint256, uint256) {

Impact

It'ss known that unnamed return variables can remain unassigned leading to bad code structure.

Add an explicit return with value to all non-reverting code paths or name the variable.

#0 - c4-pre-sort

2024-03-15T15:00:46Z

141345 marked the issue as sufficient quality report

#1 - 141345

2024-03-16T01:07:22Z

210 Bauchibred l r nc 2 0 2

L 1 d dup of https://github.com/code-423n4/2024-03-abracadabra-money-findings/issues/88 L 2 l L 3 n L 4 l L 5 n

#2 - c4-judge

2024-03-29T16:47:56Z

thereksfour marked the issue as grade-b

#3 - Bauchibred

2024-04-03T10:43:25Z

Hi @c4-judge, considering both #140 and #95 have been finalised as QAs, shouldn't the grade of the overall report bump to A?

Edit: Noticed #97 & #139 have also been downgraded during PJQA, kindly take them into account as this make the overall report have 7 Ls and 2Ncs.

#4 - c4-judge

2024-04-06T06:44:53Z

thereksfour marked the issue as grade-a

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