Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor party #56

Merged
merged 5 commits into from
Aug 26, 2024
Merged

refactor party #56

merged 5 commits into from
Aug 26, 2024

Conversation

YouStillAlive
Copy link
Member

No description provided.

@YouStillAlive YouStillAlive changed the title split liquidity file refactor party Aug 23, 2024
Copy link

github-actions bot commented Aug 23, 2024

Methods

Symbol Meaning
Execution gas for this method does not include intrinsic gas overhead
Cost was non-zero but below the precision setting for the currency display (see options)
Min Max Avg Calls usd avg
BNBPartyFactory
       createParty(string,string) 5,725,654 5,902,694 5,763,634 32 3.33
       joinParty(address,uint256) 155,749 5,662,942 2,082,111 23 1.20
       leaveParty(address,uint256,uint256) 176,059 200,199 181,366 5 0.10
       setBNBPartySwapRouter(address) 24,180 46,320 44,843 15 0.03
       setNonfungiblePositionManager(address,address) 27,399 68,928 66,159 15 0.04
       setSwapRouter(address) - - 46,298 13 0.03
       withdrawFee() - - 31,770 2 0.02
       withdrawPartyLPFee(address[]) - - 173,792 2 0.10
NonfungiblePositionManager
       approve(address,uint256) 46,052 46,395 46,277 3 0.03
SwapRouter
       exactInput((bytes,address,uint256,uint256,uint256)) 133,979 143,537 140,351 3 0.08
       multicall(bytes[]) - - 160,560 2 0.09

Deployments

Min Max Avg Block % usd avg
BNBPartyFactory 3,728,094 3,728,118 3,728,114 2.9 % 2.15
MockContract - - 107,817 0.1 % 0.06
MockNonfungibleTokenPositionDescriptor - - 111,537 0.1 % 0.06
NonfungiblePositionManager 5,171,512 5,171,524 5,171,518 4 % 2.99
SqrtPriceCalculator - - 278,712 0.2 % 0.16
SwapRouter 2,201,078 2,201,090 2,201,086 1.7 % 1.27
UniswapV3Factory - - 5,437,109 4.2 % 3.14

Solidity and Network Config

Settings Value
Solidity: version 0.8.24
Solidity: optimized true
Solidity: runs 200
Solidity: viaIR false
Block Limit 130,000,000
L1 Gas Price 1 gwei
Token Price 577.76 usd/bnb
Network BINANCE
Toolchain hardhat

@codecov-commenter
Copy link

codecov-commenter commented Aug 23, 2024

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

Attention: Patch coverage is 95.23810% with 2 lines in your changes missing coverage. Please review.

Files Patch % Lines
contracts/BNBPartyFee.sol 83.33% 2 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Files Coverage Δ
contracts/BNBPartyCreation.sol 100.00% <100.00%> (ø)
contracts/BNBPartyFactory.sol 100.00% <100.00%> (ø)
contracts/BNBPartyLiquidity.sol 100.00% <100.00%> (ø)
contracts/BNBPartyLiquidityHelper.sol 100.00% <100.00%> (ø)
contracts/BNBPartyState.sol 62.50% <ø> (ø)
contracts/BNBPartyView.sol 90.90% <100.00%> (+8.55%) ⬆️
contracts/BNBPartyFee.sol 83.33% <83.33%> (ø)

Copy link

github-actions bot commented Aug 23, 2024

Slither report

THIS CHECKLIST IS NOT COMPLETE. Use --show-ignored-findings to show all the results.
Summary

incorrect-equality

Impact: Medium
Confidence: High

function _calculateAmounts(address tokenA) internal view returns (uint256 amount0, uint256 amount1) {
uint256 balanceA = IERC20(tokenA).balanceOf(address(this));
if (balanceA == party.initialTokenAmount) {
amount0 = party.initialTokenAmount; // Set amount0 if tokenA balance matches the initial amount
} else {
amount1 = party.initialTokenAmount; // Otherwise, set amount1
}
}

function withdrawFee() external onlyOwner {
if (address(this).balance == 0) {
revert ZeroAmount();
}
payable(msg.sender).transfer(address(this).balance); // Transfers the entire BNB balance to the owner
emit TransferOutBNB(msg.sender, address(this).balance); // Emits an event indicating the transfer of BNB
}

reentrancy-no-eth

Impact: Medium
Confidence: Medium

function _handleLiquidity(address recipient) internal {
IUniswapV3Pool pool = IUniswapV3Pool(msg.sender);
(uint160 sqrtPriceX96, , , , , , ) = pool.slot0();
address token0 = pool.token0();
address token1 = pool.token1();
uint128 liquidity = pool.liquidity();
// Decrease liquidity and collect tokens
(uint256 amount0, uint256 amount1) = _decreaseAndCollect(lpToTokenId[msg.sender], liquidity);
uint256 unwrapAmount = party.bonusTargetReach + party.bonusPartyCreator + party.targetReachFee;
uint160 newSqrtPriceX96;
if (token0 == address(WBNB)) {
amount0 -= unwrapAmount; // Deduct unwrap amount from token0 if it is WBNB
isTokenOnPartyLP[token1] = false;
newSqrtPriceX96 = sqrtPriceCalculator.getNextSqrtPriceFromAmount0RoundingUp(
sqrtPriceX96,
liquidity,
unwrapAmount,
false
);
} else {
amount1 -= unwrapAmount; // Deduct unwrap amount from token1 if it is WBNB
isTokenOnPartyLP[token0] = false;
newSqrtPriceX96 = sqrtPriceCalculator.getNextSqrtPriceFromAmount1RoundingDown(
sqrtPriceX96,
liquidity,
unwrapAmount / 2,
false
);
}
// Approve tokens for the new liquidity pool creation
_approveTokens(token0, token1, amount0, amount1);
// Create new Liquidity Pool
_createLP(positionManager, token0, token1, amount0, amount1, newSqrtPriceX96, party.lpFee, party.lpTicks);
// Send bonuses
_unwrapAndSendBNB(recipient, unwrapAmount);
// burn meme tokens
_burnMemeToken(token0 == address(WBNB) ? token1 : token0);
}

unused-return

Impact: Medium
Confidence: Medium

function _createLP(
INonfungiblePositionManager liquidityManager,
address token0,
address token1,
uint256 amount0,
uint256 amount1,
uint160 sqrtPriceX96,
uint24 fee,
Ticks memory ticks
) internal returns (address liquidityPool) {
// Create LP
liquidityPool = liquidityManager.createAndInitializePoolIfNecessary(
token0,
token1,
fee,
sqrtPriceX96
);
// Mint LP
(lpToTokenId[liquidityPool], , , ) = liquidityManager.mint(
INonfungiblePositionManager.MintParams({
token0: token0,
token1: token1,
fee: fee,
tickLower: ticks.tickLower,
tickUpper: ticks.tickUpper,
amount0Desired: amount0,
amount1Desired: amount1,
amount0Min: 0,
amount1Min: 0,
recipient: address(this),
deadline: block.timestamp
})
);
}

function _decreaseAndCollect(
uint256 tokenId,
uint128 liquidity
) internal returns (uint256 amount0, uint256 amount1) {
// Decrease liquidity from the position and receive the amount of token0 and token1
(amount0, amount1) = BNBPositionManager.decreaseLiquidity(
INonfungiblePositionManager.DecreaseLiquidityParams({
tokenId: tokenId,
liquidity: liquidity,
amount0Min: 0, // Minimum amount of token0 to collect, set to 0 for flexibility
amount1Min: 0, // Minimum amount of token1 to collect, set to 0 for flexibility
deadline: block.timestamp // Deadline for the transaction to be completed
})
);
// Collect the tokens from the position after liquidity decrease
BNBPositionManager.collect(
INonfungiblePositionManager.CollectParams({
tokenId: tokenId,
recipient: address(this), // Collect tokens to this contract address
amount0Max: uint128(amount0), // Maximum amount of token0 to collect
amount1Max: uint128(amount1) // Maximum amount of token1 to collect
})
);
}

function _approveTokens(
address token0,
address token1,
uint256 amount0,
uint256 amount1
) internal {
IERC20(token0).approve(address(positionManager), amount0);
IERC20(token1).approve(address(positionManager), amount1);
}

function _approveTokens(
address token0,
address token1,
uint256 amount0,
uint256 amount1
) internal {
IERC20(token0).approve(address(positionManager), amount0);
IERC20(token1).approve(address(positionManager), amount1);
}

function _collectFee(
address liquidityPool,
INonfungiblePositionManager manager
) internal notZeroAddress(liquidityPool) {
manager.collect(
INonfungiblePositionManager.CollectParams({
tokenId: lpToTokenId[liquidityPool],
recipient: msg.sender,
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
})
); // Collects fees from the specified liquidity pool
}

function _executeSwap(
ISwapRouter router,
ISwapRouter.ExactInputParams memory params
) internal notZeroAddress(address(router)) {
uint256 value = msg.value > 0 ? params.amountIn : 0; // Set value if msg.value is greater than zero
ISwapRouter(router).exactInput{value: value}(params); // Executes the swap
}

function _createFLP(address _token) internal returns (address liquidityPool) {
(address tokenA, address tokenB, uint160 sqrtPrice) = _getTokenPairAndPrice(_token);
// Determine the token amounts
(uint256 amount0, uint256 amount1) = _calculateAmounts(tokenA);
IERC20(_token).approve(address(BNBPositionManager), party.initialTokenAmount);
liquidityPool = _createLP(
BNBPositionManager,
tokenA,
tokenB,
amount0,
amount1,
sqrtPrice,
party.partyLpFee,
party.partyTicks
);
isParty[liquidityPool] = true; // Mark the liquidity pool as a party pool
isTokenOnPartyLP[_token] = true; // Mark the token as part of the party LP
}

function _getFeeGrowthInsideLastX128(
IUniswapV3Pool pool,
bytes32 key
)
internal
view
returns (
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128
)
{
(, feeGrowthInside0LastX128, feeGrowthInside1LastX128, , ) = pool.positions(key);
}

function _handleLiquidity(address recipient) internal {
IUniswapV3Pool pool = IUniswapV3Pool(msg.sender);
(uint160 sqrtPriceX96, , , , , , ) = pool.slot0();
address token0 = pool.token0();
address token1 = pool.token1();
uint128 liquidity = pool.liquidity();
// Decrease liquidity and collect tokens
(uint256 amount0, uint256 amount1) = _decreaseAndCollect(lpToTokenId[msg.sender], liquidity);
uint256 unwrapAmount = party.bonusTargetReach + party.bonusPartyCreator + party.targetReachFee;
uint160 newSqrtPriceX96;
if (token0 == address(WBNB)) {
amount0 -= unwrapAmount; // Deduct unwrap amount from token0 if it is WBNB
isTokenOnPartyLP[token1] = false;
newSqrtPriceX96 = sqrtPriceCalculator.getNextSqrtPriceFromAmount0RoundingUp(
sqrtPriceX96,
liquidity,
unwrapAmount,
false
);
} else {
amount1 -= unwrapAmount; // Deduct unwrap amount from token1 if it is WBNB
isTokenOnPartyLP[token0] = false;
newSqrtPriceX96 = sqrtPriceCalculator.getNextSqrtPriceFromAmount1RoundingDown(
sqrtPriceX96,
liquidity,
unwrapAmount / 2,
false
);
}
// Approve tokens for the new liquidity pool creation
_approveTokens(token0, token1, amount0, amount1);
// Create new Liquidity Pool
_createLP(positionManager, token0, token1, amount0, amount1, newSqrtPriceX96, party.lpFee, party.lpTicks);
// Send bonuses
_unwrapAndSendBNB(recipient, unwrapAmount);
// burn meme tokens
_burnMemeToken(token0 == address(WBNB) ? token1 : token0);
}

shadowing-local

Impact: Low
Confidence: High

string memory symbol,

reentrancy-benign

Impact: Low
Confidence: Medium

function createParty(
string calldata name,
string calldata symbol
)
external
payable
override
nonReentrant
insufficientBNB
notZeroAddress(address(BNBPositionManager))
returns (IERC20 newToken)
{
// Create new token
newToken = new ERC20Token(name, symbol, party.initialTokenAmount);
// Create First Liquidity Pool
address liquidityPool = _createFLP(address(newToken));
lpToCreator[liquidityPool] = msg.sender;
if (msg.value > party.createTokenFee) {
_executeSwap(address(newToken));
}
emit StartParty(address(newToken), msg.sender, liquidityPool);
}

function _createLP(
INonfungiblePositionManager liquidityManager,
address token0,
address token1,
uint256 amount0,
uint256 amount1,
uint160 sqrtPriceX96,
uint24 fee,
Ticks memory ticks
) internal returns (address liquidityPool) {
// Create LP
liquidityPool = liquidityManager.createAndInitializePoolIfNecessary(
token0,
token1,
fee,
sqrtPriceX96
);
// Mint LP
(lpToTokenId[liquidityPool], , , ) = liquidityManager.mint(
INonfungiblePositionManager.MintParams({
token0: token0,
token1: token1,
fee: fee,
tickLower: ticks.tickLower,
tickUpper: ticks.tickUpper,
amount0Desired: amount0,
amount1Desired: amount1,
amount0Min: 0,
amount1Min: 0,
recipient: address(this),
deadline: block.timestamp
})
);
}

function _handleLiquidity(address recipient) internal {
IUniswapV3Pool pool = IUniswapV3Pool(msg.sender);
(uint160 sqrtPriceX96, , , , , , ) = pool.slot0();
address token0 = pool.token0();
address token1 = pool.token1();
uint128 liquidity = pool.liquidity();
// Decrease liquidity and collect tokens
(uint256 amount0, uint256 amount1) = _decreaseAndCollect(lpToTokenId[msg.sender], liquidity);
uint256 unwrapAmount = party.bonusTargetReach + party.bonusPartyCreator + party.targetReachFee;
uint160 newSqrtPriceX96;
if (token0 == address(WBNB)) {
amount0 -= unwrapAmount; // Deduct unwrap amount from token0 if it is WBNB
isTokenOnPartyLP[token1] = false;
newSqrtPriceX96 = sqrtPriceCalculator.getNextSqrtPriceFromAmount0RoundingUp(
sqrtPriceX96,
liquidity,
unwrapAmount,
false
);
} else {
amount1 -= unwrapAmount; // Deduct unwrap amount from token1 if it is WBNB
isTokenOnPartyLP[token0] = false;
newSqrtPriceX96 = sqrtPriceCalculator.getNextSqrtPriceFromAmount1RoundingDown(
sqrtPriceX96,
liquidity,
unwrapAmount / 2,
false
);
}
// Approve tokens for the new liquidity pool creation
_approveTokens(token0, token1, amount0, amount1);
// Create new Liquidity Pool
_createLP(positionManager, token0, token1, amount0, amount1, newSqrtPriceX96, party.lpFee, party.lpTicks);
// Send bonuses
_unwrapAndSendBNB(recipient, unwrapAmount);
// burn meme tokens
_burnMemeToken(token0 == address(WBNB) ? token1 : token0);
}

function _createFLP(address _token) internal returns (address liquidityPool) {
(address tokenA, address tokenB, uint160 sqrtPrice) = _getTokenPairAndPrice(_token);
// Determine the token amounts
(uint256 amount0, uint256 amount1) = _calculateAmounts(tokenA);
IERC20(_token).approve(address(BNBPositionManager), party.initialTokenAmount);
liquidityPool = _createLP(
BNBPositionManager,
tokenA,
tokenB,
amount0,
amount1,
sqrtPrice,
party.partyLpFee,
party.partyTicks
);
isParty[liquidityPool] = true; // Mark the liquidity pool as a party pool
isTokenOnPartyLP[_token] = true; // Mark the token as part of the party LP
}

reentrancy-events

Impact: Low
Confidence: Medium

function _unwrapAndSendBNB(address recipient, uint256 unwrapAmount) internal {
address creator = lpToCreator[msg.sender];
WBNB.withdraw(unwrapAmount); // Unwrap WBNB to BNB
if (recipient == creator) {
_transferBNB(recipient, party.bonusTargetReach + party.bonusPartyCreator); // Send total bonus to creator
} else {
_transferBNB(recipient, party.bonusTargetReach); // Send bonus to recipient
_transferBNB(creator, party.bonusPartyCreator); // Send bonus to creator
}
}

function _transferBNB(address recipient, uint256 amount) private {
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert BonusAmountTransferFailed();
}
emit TransferOutBNB(recipient, amount);
}

function _unwrapAndSendBNB(address recipient, uint256 unwrapAmount) internal {
address creator = lpToCreator[msg.sender];
WBNB.withdraw(unwrapAmount); // Unwrap WBNB to BNB
if (recipient == creator) {
_transferBNB(recipient, party.bonusTargetReach + party.bonusPartyCreator); // Send total bonus to creator
} else {
_transferBNB(recipient, party.bonusTargetReach); // Send bonus to recipient
_transferBNB(creator, party.bonusPartyCreator); // Send bonus to creator
}
}

function _handleLiquidity(address recipient) internal {
IUniswapV3Pool pool = IUniswapV3Pool(msg.sender);
(uint160 sqrtPriceX96, , , , , , ) = pool.slot0();
address token0 = pool.token0();
address token1 = pool.token1();
uint128 liquidity = pool.liquidity();
// Decrease liquidity and collect tokens
(uint256 amount0, uint256 amount1) = _decreaseAndCollect(lpToTokenId[msg.sender], liquidity);
uint256 unwrapAmount = party.bonusTargetReach + party.bonusPartyCreator + party.targetReachFee;
uint160 newSqrtPriceX96;
if (token0 == address(WBNB)) {
amount0 -= unwrapAmount; // Deduct unwrap amount from token0 if it is WBNB
isTokenOnPartyLP[token1] = false;
newSqrtPriceX96 = sqrtPriceCalculator.getNextSqrtPriceFromAmount0RoundingUp(
sqrtPriceX96,
liquidity,
unwrapAmount,
false
);
} else {
amount1 -= unwrapAmount; // Deduct unwrap amount from token1 if it is WBNB
isTokenOnPartyLP[token0] = false;
newSqrtPriceX96 = sqrtPriceCalculator.getNextSqrtPriceFromAmount1RoundingDown(
sqrtPriceX96,
liquidity,
unwrapAmount / 2,
false
);
}
// Approve tokens for the new liquidity pool creation
_approveTokens(token0, token1, amount0, amount1);
// Create new Liquidity Pool
_createLP(positionManager, token0, token1, amount0, amount1, newSqrtPriceX96, party.lpFee, party.lpTicks);
// Send bonuses
_unwrapAndSendBNB(recipient, unwrapAmount);
// burn meme tokens
_burnMemeToken(token0 == address(WBNB) ? token1 : token0);
}

function _unwrapAndSendBNB(address recipient, uint256 unwrapAmount) internal {
address creator = lpToCreator[msg.sender];
WBNB.withdraw(unwrapAmount); // Unwrap WBNB to BNB
if (recipient == creator) {
_transferBNB(recipient, party.bonusTargetReach + party.bonusPartyCreator); // Send total bonus to creator
} else {
_transferBNB(recipient, party.bonusTargetReach); // Send bonus to recipient
_transferBNB(creator, party.bonusPartyCreator); // Send bonus to creator
}
}

assembly

Impact: Informational
Confidence: High

https://github.com/bnb-party/BNBParty.Factory/blob/bd6f33ecf2629d17c385f8420d11fc83c36c0aaa/node_modules/@openzeppelin/contracts/utils/Address.sol#L146-L158

low-level-calls

Impact: Informational
Confidence: High

https://github.com/bnb-party/BNBParty.Factory/blob/bd6f33ecf2629d17c385f8420d11fc83c36c0aaa/node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#L110-L117

https://github.com/bnb-party/BNBParty.Factory/blob/bd6f33ecf2629d17c385f8420d11fc83c36c0aaa/node_modules/@openzeppelin/contracts/utils/Address.sol#L95-L98

https://github.com/bnb-party/BNBParty.Factory/blob/bd6f33ecf2629d17c385f8420d11fc83c36c0aaa/node_modules/@openzeppelin/contracts/utils/Address.sol#L104-L107

function _transferBNB(address recipient, uint256 amount) private {
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert BonusAmountTransferFailed();
}
emit TransferOutBNB(recipient, amount);
}

https://github.com/bnb-party/BNBParty.Factory/blob/bd6f33ecf2629d17c385f8420d11fc83c36c0aaa/node_modules/@openzeppelin/contracts/utils/Address.sol#L41-L50

https://github.com/bnb-party/BNBParty.Factory/blob/bd6f33ecf2629d17c385f8420d11fc83c36c0aaa/node_modules/@openzeppelin/contracts/utils/Address.sol#L83-L89

naming-convention

Impact: Informational
Confidence: High

IWBNB public immutable WBNB; // Wrapped BNB token contract

INonfungiblePositionManager public BNBPositionManager; // BNB Party position manager

ISwapRouter _swapRouter

INonfungiblePositionManager _BNBPositionManager,

function WETH9() external view returns (address);

INonfungiblePositionManager _positionManager

https://github.com/bnb-party/BNBParty.Factory/blob/bd6f33ecf2629d17c385f8420d11fc83c36c0aaa/node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol#L89

ISwapRouter _swapRouter

modifier SwapRouterAlreadySet(
ISwapRouter _swapRouter,
ISwapRouter _newSwapRouter
) {
if (_swapRouter == _newSwapRouter) {
revert AlreadySet();
}
_;
}

ISwapRouter public BNBSwapRouter; // V3 swap router

reentrancy-unlimited-gas

Impact: Informational
Confidence: Medium

function withdrawFee() external onlyOwner {
if (address(this).balance == 0) {
revert ZeroAmount();
}
payable(msg.sender).transfer(address(this).balance); // Transfers the entire BNB balance to the owner
emit TransferOutBNB(msg.sender, address(this).balance); // Emits an event indicating the transfer of BNB
}

unused-import

Impact: Informational
Confidence: High

  • ID-41
    The following unused import(s) in contracts/BNBPartyState.sol should be removed:
    -import "./interfaces/IUniswapV3Pool.sol"; (contracts/BNBPartyState.sol#9)

  • ID-42
    The following unused import(s) in contracts/BNBPartyLiquidity.sol should be removed:
    -import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; (contracts/BNBPartyLiquidity.sol#5)

  • ID-43
    The following unused import(s) in contracts/BNBPartyCreation.sol should be removed:
    -import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; (contracts/BNBPartyCreation.sol#5)

immutable-states

Impact: Optimization
Confidence: High

ISqrtPriceCalculator public sqrtPriceCalculator;

@YouStillAlive YouStillAlive marked this pull request as ready for review August 23, 2024 11:10
@YouStillAlive YouStillAlive merged commit 9acbdbd into master Aug 26, 2024
4 checks passed
@YouStillAlive YouStillAlive deleted the refactor branch August 26, 2024 09:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants