Trader Joe v2 contest - KingNFT's results

One-stop-shop decentralized trading on Avalanche.

General Information

Platform: Code4rena

Start Date: 14/10/2022

Pot Size: $100,000 USDC

Total HM: 12

Participants: 75

Period: 9 days

Judge: GalloDaSballo

Total Solo HM: 1

Id: 171

League: ETH

Trader Joe

Findings Distribution

Researcher Performance

Rank: 7/75

Findings: 4

Award: $4,521.14

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: KIntern_NA

Also found by: KingNFT, Trust

Labels

bug
3 (High Risk)
edited-by-warden
satisfactory
duplicate-384

Awards

4170.8571 USDC - $4,170.86

External Links

Lines of code

https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBPair.sol#L915

Vulnerability details

Impact

The '_setFeesParameters' function of LBPair.sol is not properly implemented, the static and dynamic fee parameters are overlapped due to missing of 114 bits shift for dynamic parameters. It will messes up the parameters and make the LBPair contract unavailable。

Proof of Concept

https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBPair.sol#L915

Tools Used

VS Code

function _setFeesParameters(bytes32 _packedFeeParameters) internal { // ... assembly { sstore(_feeParameters.slot, or(_newFeeParameters, shl(_OFFSET_VARIABLE_FEE_PARAMETERS, _varParameters))) } }

#0 - trust1995

2022-10-23T21:41:06Z

Dup of #425

#1 - GalloDaSballo

2022-10-25T23:21:06Z

Definitely would have liked to see a quick coded POC here

#2 - GalloDaSballo

2022-10-26T16:42:10Z

#3 - c4-judge

2022-11-23T18:31:09Z

GalloDaSballo marked the issue as not a duplicate

#4 - c4-judge

2022-11-23T18:31:53Z

GalloDaSballo marked the issue as duplicate of #384

#5 - Simon-Busch

2022-12-05T06:46:52Z

Marked this issue as satisfactory as requested by @GalloDaSballo

Findings Information

Labels

bug
2 (Med Risk)
downgraded by judge
edited-by-warden
satisfactory
duplicate-108

Awards

0.9728 USDC - $0.97

External Links

Lines of code

https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBToken.sol#L237

Vulnerability details

Impact

The '_burn' function of LBToken.sol call internal virtual function '_beforeTokenTransfer' with wrong order for parameter 'from' and 'to'. It causes the implementation of '_beforeTokenTransfer' in LBPaire.sol to update user's debt incorrectly, cause the system corrupted.

Proof of Concept

https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBToken.sol#L237

https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBPair.sol#L808-L833

https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBPair.sol#L880-L901

Tools Used

function _burn( address _account, uint256 _id, uint256 _amount ) internal virtual { // ... _beforeTokenTransfer(_account, address(0), _id, _amount); // ... }

#0 - trust1995

2022-10-23T22:09:30Z

Dup of #179

#1 - GalloDaSballo

2022-10-26T18:18:29Z

#2 - c4-judge

2022-11-11T21:22:53Z

GalloDaSballo changed the severity to 2 (Med Risk)

#3 - c4-judge

2022-11-11T21:22:57Z

GalloDaSballo marked the issue as satisfactory

#4 - c4-judge

2022-11-16T21:55:53Z

GalloDaSballo marked the issue as not a duplicate

#5 - c4-judge

2022-11-16T21:56:16Z

GalloDaSballo marked the issue as duplicate of #108

Findings Information

🌟 Selected for report: shung

Also found by: 0x52, KingNFT, Trust, parashar, philogy, rvierdiiev

Labels

bug
2 (Med Risk)
edited-by-warden
satisfactory
duplicate-136

Awards

69.4984 USDC - $69.50

External Links

Lines of code

https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBPair.sol#L420-L456

Vulnerability details

Impact

The implementation of 'flashLoan' in LBPair.sol allow users to loan as much as up to all funds in pair, but loan fees are credited to the active bin only, there is a chance a little reserve in the active bin getting unreasonably high ROI. It's recommended to distribute fees to both active bin and these adjacent ones based on their reserves. This way we incentivize liquidity providers to actively manage liquidity while ensuring fairness.

Proof of Concept

https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBPair.sol#L420-L456

Tools Used

Manually review - VS code

Adding new internal function '_distributeLoanFee' and fix 'flashLoan' as follow:

function _distributeLoanFee( uint24 _id, FeeHelper.FeeParameters memory _fp, FeeHelper.FeesDistribution memory _fees, uint256 _amountOut, bool _loanForY ) internal { uint256 _left = _amountOut; while (_left != 0) { uint256 _reserve = _loanForY ? _bins[_id].reserveY : _bins[_id].reserveX; if (_reserve == 0) { _id = _tree.findFirstBin(_id, _loanForY); continue; } uint256 _amount; if (_left <= _reserve) { _amount = _left; _left = 0; } else { _amount = _reserve; unchecked { _left -= _reserve; } } FeeHelper.FeesDistribution memory _feesBin = _fp.getFeeAmountDistribution(_amount * _fees.total / _amountOut); if (_loanForY) { _bins[_id].accTokenYPerShare += _feesBin.getTokenPerShare(totalSupply(_id)); } else { _bins[_id].accTokenXPerShare += _feesBin.getTokenPerShare(totalSupply(_id)); } if (_left != 0) { _id = _tree.findFirstBin(_id, _loanForY); } } } function flashLoan( address _to, uint256 _amountXOut, uint256 _amountYOut, bytes calldata _data ) external override nonReentrant { (uint256 _reserveX, uint256 _reserveY, uint256 _id) = _getReservesAndId(); if (_amountXOut > _reserveX) revert LBPair__InsufficientReserveX(); if (_amountYOut > _reserveY) revert LBPair__InsufficientReserveY(); uint256 _fee = factory.flashLoanFee(); FeeHelper.FeeParameters memory _fp = _feeParameters; FeeHelper.FeesDistribution memory _feesX; FeeHelper.FeesDistribution memory _feesY; if (_amountXOut != 0) { // gas saving, since it's common to loan only one of the pair _feesX = _fp.getFeeAmountDistribution(_getFlashLoanFee(_amountXOut, _fee)); tokenX.safeTransfer(_to, _amountXOut); } if (_amountYOut != 0) { _feesY = _fp.getFeeAmountDistribution(_getFlashLoanFee(_amountYOut, _fee)); tokenY.safeTransfer(_to, _amountYOut); } ILBFlashLoanCallback(_to).LBFlashLoanCallback( msg.sender, _amountXOut, _amountYOut, _feesX.total, _feesY.total, _data ); if (_amountXOut != 0) { _feesX.flashLoanHelper(_pairInformation.feesX, tokenX, _reserveX); _distributeLoanFee(_id, _fp, _feesX, _amountXOut, false); } if (_amountYOut != 0) { _feesY.flashLoanHelper(_pairInformation.feesY, tokenY, _reserveY); _distributeLoanFee(_id, _fp, _feesY, _amountYOut, true); } emit FlashLoan(msg.sender, _to, _amountXOut, _amountYOut, _feesX.total, _feesY.total); }

#0 - trust1995

2022-10-23T22:03:19Z

Dup of #302

#1 - Shungy

2022-10-23T22:52:54Z

I believe this finding to be valid.

However, I think this report is of informational severity. Because the report have not identified an attack vector unlike the other reports mentioning the potential of value leak out of the protocol by way of stealing fees. Such as my report: https://github.com/code-423n4/2022-10-traderjoe-findings/issues/136. Additionally, the suggested fix is insufficient.

Disclaimer: Reduction of severity of this report would benefit me.

#2 - GalloDaSballo

2022-10-26T17:02:50Z

#3 - c4-judge

2022-11-13T17:19:55Z

GalloDaSballo marked the issue as satisfactory

#4 - c4-judge

2022-11-16T21:55:35Z

GalloDaSballo marked the issue as not a duplicate

#5 - c4-judge

2022-11-16T21:55:41Z

GalloDaSballo marked the issue as duplicate of #136

Findings Information

🌟 Selected for report: zzykxx

Also found by: 0x1f8b, 0xSmartContract, IllIllI, KingNFT, Rolezn, adriro, brgltd, hansfriese, pashov, rbserver

Labels

bug
QA (Quality Assurance)
grade-b
Q-03

Awards

279.8109 USDC - $279.81

External Links

  1. Missing check if the last bin in the bin tree level 0 The function 'findFirstBin' in TreeMath.sol checks if the last bin for level 2 and level 1, but missing check for level 0. Functionally there will be no problem,since coincidentally in this case an arithmetic overflow/underflow error will occur while calling function 'closestBit'. But it will revert with an unexpected reason rather than 'TreeMath__ErrorDepthSearch'.
function findFirstBin( mapping(uint256 => uint256)[3] storage _tree, uint24 _binId, bool _rightSide ) internal view returns (uint24) { unchecked { uint256 current; uint256 bit; (_binId, bit) = _getIdsFromAbove(_binId); // Search in depth 2 if ((_rightSide && bit != 0) || (!_rightSide && bit != 255)) { current = _tree[2][_binId]; bit = current.closestBit(uint8(bit), _rightSide); if (bit != type(uint256).max) { return _getBottomId(_binId, uint24(bit)); } } (_binId, bit) = _getIdsFromAbove(_binId); // Search in depth 1 if ((_rightSide && bit != 0) || (!_rightSide && bit != 255)) { current = _tree[1][_binId]; bit = current.closestBit(uint8(bit), _rightSide); if (bit != type(uint256).max) { _binId = _getBottomId(_binId, uint24(bit)); current = _tree[2][_binId]; return _getBottomId(_binId, current.significantBit(_rightSide)); } } // @audit missing check here // Search in depth 0 current = _tree[0][0]; bit = current.closestBit(uint8(_binId), _rightSide); if (bit == type(uint256).max) revert TreeMath__ErrorDepthSearch(); current = _tree[1][bit]; _binId = _getBottomId(uint24(bit), current.significantBit(_rightSide)); current = _tree[2][_binId]; return _getBottomId(_binId, current.significantBit(_rightSide)); } }

https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/libraries/TreeMath.sol#L56

#0 - GalloDaSballo

2022-11-09T20:08:09Z

Missing check if the last bin in the bin tree level 0

R

#1 - GalloDaSballo

2022-11-09T20:08:12Z

1R

#2 - c4-judge

2022-11-16T21:08:33Z

GalloDaSballo marked the issue as grade-b

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