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
Rank: 5/36
Findings: 2
Award: $2,258.68
๐ Selected for report: 1
๐ Solo Findings: 1
๐ Selected for report: Bauchibred
2068.8771 USDC - $2,068.88
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.
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
.
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
#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
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
- Blast is an optimistic rollup, just like Arbritrum, Base, Optimism, etc.
- 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
๐ Selected for report: ether_sky
Also found by: 0x11singh99, 0xE1, 0xJaeger, Bauchibred, Bigsam, Bozho, Breeje, DarkTower, HChang26, SpicyMeatball, Trust, ZanyBonzy, albahaca, bareli, blutorque, grearlake, hals, hassan-truscova, hihen, oualidpro, pfapostol, ravikiranweb3, slvDev, zhaojie
189.8 USDC - $189.80
Issue ID | Description |
---|---|
QA-01 | Protocol hardcodes acceptable tokens to 18 decimals |
QA-02 | Unhandled Chainlink revert would halt core functionalities |
QA-03 | Unused local variables should be removed |
QA-04 | Always implement CEI patterns where possible |
QA-05 | Unnamed return variable can remain unassigned |
uint256 public constant WAD = 18;
//@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
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.
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.
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.
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(); | ^^^^^^^^^^^^^^^^^^^^
Low, bad code structuring, makes it harder for bith users and developers to understnad code
Either use the valriables or remove them from code
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
Low, code is not following the best practise.
It's always great practise to follow the check effects interaction pattern
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) {
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