Trader Joe v2 contest - brgltd'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: 24/75

Findings: 1

Award: $279.81

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

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-11

Awards

279.8109 USDC - $279.81

External Links

[01] Unhandled amountsId[0] == msg.value in LBRouter.swapAVAXForExactTokens

If msg.value equals amountsIn[0] in LBRouter, swapAVAXForExactTokens() will not revert and it will also not swap.

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBRouter.sol#L512

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBRouter.sol#L520

Recommendation

Since the transfer should not be executed if msg.value equals amountsId[0] (due to insufficient input funds), the correct behavior would be for the function to revert. E.g.

diff --git a/LBRouter.sol.orig b/LBRouter.sol --- a/LBRouter.sol.orig +++ b/LBRouter.sol - if (amountsIn[0] > msg.value) revert LBRouter__MaxAmountInExceeded(msg.value, amountsIn[0]); + if (amountsIn[0] >= msg.value) revert LBRouter__MaxAmountInExceeded(msg.value, amountsIn[0]);

[02] Missing address(0) checks for constructor

Consider adding checks for address(0) in LBQuoter.constructor().

If a variable gets configured with address zero, failure to immediately reset the value can result in unexpected behavior for the project.

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBQuoter.sol#L40-L44

Recommendation

diff --git a/LBQuoter.sol.orig b/LBQuoter.sol --- a/LBQuoter.sol.orig +++ b/LBQuoter.sol + if ( + _routerV2 == address(0) || + _factoryV1 == address(0) || + _factoryV2 == address(0) + ) { + // Example of a new custom error to revert on address(0) for LBQuoter + revert LBQuoter__AddressZero(); + } routerV2 = _routerV2; factoryV1 = _factoryV1; factoryV2 = _factoryV2;

[03] Critical changes should use two-step procedure

Lack of two-step procedure for critical operations leaves them error-prone. Consider adding two step procedure on the critical functions.

Recommendation

Consider adding a two-steps pattern on critical changes to avoid mistakenly transferring ownership of roles or critial functionalities to the wrong address.

function setFactoryLockedState(bool _locked) external override onlyOwner {

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBFactory.sol#L485

[04] Public functions not called by the contract should be declared external

function findBestPathFromAmountIn(address[] memory _route, uint256 _amountIn) public

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBQuoter.sol#L54-L55

function findBestPathFromAmountOut(address[] memory _route, uint256 _amountOut) public

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBQuoter.sol#L134-L135

[05] Replace memory with calldata

Read-only array arguments should use calldata instead of memory.

function pendingFees(address _account, uint256[] memory _ids)

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBPair.sol#L261

function mint( uint256[] memory _ids, uint256[] memory _distributionX, uint256[] memory _distributionY,

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBPair.sol#L466-L469

function burn( uint256[] memory _ids, uint256[] memory _amounts,

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBPair.sol#L616-L618

[06] Missing event for critical parameter changes

Adding an event for setFeeParameters() would facilitade offchain monitoring.

function setFeesParameters(bytes32 _packedFeeParameters) external override onlyFactory {

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBPair.sol#L788

function _setFeesParameters(bytes32 _packedFeeParameters) internal {

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBPair.sol#L905

[07] Missing NATSPEC/documentation

Consider adding NATSPEC on all functions to improve documentation.

function forceDecay() external override onlyFactory {

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBPair.sol#L792

[08] Mixing named variables and manually returning a value for the same function

For LBPair.mint(), consider manually returning all the values or using the named return variable feature for all variables to improve the explicitness and readability of the code.

returns ( uint256, uint256, uint256[] memory liquidityMinted )

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBPair.sol#L476-L478

[09] Replace magic numbers with constants to improve code readability

uint256 _amountOut = (_reserve1 * (_balance - _reserve1) * 997) / (_balance * 1_000);

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBRouter.sol#L891

uint256 _amountOut = (_reserve0 * (_balance - _reserve1) * 997) / (_balance * 1_000);

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBRouter.sol#L896

(quote.virtualAmountsWithoutSlippage[i] * 997) / 1000,

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBQuoter.sol#L85

quote.fees[i] = 0.003e18; // 0.3%

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBQuoter.sol#L89

(JoeLibrary.quote(quote.virtualAmountsWithoutSlippage[i], reserveOut, reserveIn) * 1000) / 997;

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBQuoter.sol#L163-L164

[10] Replace assert with custom error

As described on the solidity documentation.

"The assert function creates an error of type Panic(uint256). … Properly functioning code should never create a Panic, not even on invalid external input. If this happens, then there is a bug in your contract which you should fix."

Even if the code is expected to be unreacheable, consider using a custom error instead of assert.

assert(_binStep == _preset.decode(type(uint16).max, _shift));

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/LBFactory.sol#L141

#0 - GalloDaSballo

2022-11-09T18:58:13Z

[01] Unhandled amountsId[0] == msg.value in LBRouter.swapAVAXForExactTokens

Disputed, it reverts if value is greater

[02] Missing address(0) checks for constructor

L

[03] Critical changes should use two-step procedure

NC

[04] Public functions not called by the contract should be declared external

NC

## [05] Replace memory with calldata R

[06] Missing event for critical parameter changes

NC

## [07] Missing NATSPEC/documentation NC

[08] Mixing named variables and manually returning a value for the same function

R

[09] Replace magic numbers with constants to improve code readability

R

[10] Replace assert with custom error

R

Genuine report, not bad

1L 4R 4NC

#1 - c4-judge

2022-11-16T21:09:08Z

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