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
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions contracts/BNBPartyCreation.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./BNBPartySwaps.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

/// @title BNBPartyCreation
/// @notice This abstract contract manages the creation pools within the BNB Party system.
abstract contract BNBPartyCreation is BNBPartySwaps {
/// @notice Creates the first liquidity pool (FLP) for a given token.
/// @param _token Address of the token to be used in the liquidity pool
/// @return liquidityPool Address of the newly created liquidity pool
/// @dev Sets the token amounts based on the balance and initializes the pool
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
}

/// @notice Creates a new liquidity pool and mints liquidity positions.
/// @param liquidityManager Address of the liquidity manager contract
/// @param token0 Address of the first token in the pool
/// @param token1 Address of the second token in the pool
/// @param amount0 Amount of token0 to add to the pool
/// @param amount1 Amount of token1 to add to the pool
/// @param sqrtPriceX96 The initial sqrt price of the pool
/// @param fee Fee tier for the pool
/// @return liquidityPool Address of the created liquidity pool
/// @dev Creates and initializes the pool, then mints liquidity for the position
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
})
);
}

/// @notice Calculates the amounts of token0 and token1 based on the balance of tokenA and tokenB.
/// @param tokenA Address of the first token.
/// @return amount0 The amount of token0.
/// @return amount1 The amount of token1.
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
}
}
}
15 changes: 3 additions & 12 deletions contracts/BNBPartyFactory.sol
Original file line number Diff line number Diff line change
@@ -54,23 +54,14 @@ contract BNBPartyFactory is BNBPartyLiquidity, ReentrancyGuard, BNBPartyManageab

/// @notice Handles token swaps for the liquidity pool
/// @param recipient The address of the entity making the exchange
function handleSwap(
address recipient
) external override onlyParty notZeroAddress(recipient) {
function handleSwap(address recipient) external override onlyParty notZeroAddress(recipient) {
IUniswapV3Pool pool = IUniswapV3Pool(msg.sender);

uint256 WBNBBalance = WBNB.balanceOf(msg.sender);
uint256 feeGrowthGlobal = 0;
if (pool.token0() == address(WBNB)) {
(uint256 feeGrowthInside0LastX128, ) = _getPartyFeeGrowthInsideLastX128(pool);
feeGrowthGlobal = pool.feeGrowthGlobal0X128() - feeGrowthInside0LastX128;
} else {
(, uint256 feeGrowthInside1LastX128) = _getPartyFeeGrowthInsideLastX128(pool);
feeGrowthGlobal = pool.feeGrowthGlobal1X128() - feeGrowthInside1LastX128;
}

uint256 feeGrowthGlobal = _calculateFeeGrowthGlobal(pool);
uint256 liquidity = pool.liquidity();
uint256 feesEarned = calculateFees(liquidity, feeGrowthGlobal);

if (WBNBBalance - feesEarned < party.partyTarget) return;
// Handle liquidity
_handleLiquidity(recipient);
92 changes: 92 additions & 0 deletions contracts/BNBPartyFee.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./BNBPartyModifiers.sol";

/// @title BNBPartyFee
/// @notice This abstract contract provides internal functions for calculating fees in the BNB Party system.
abstract contract BNBPartyFee is BNBPartyModifiers {
/// @notice Internal function to retrieve the fee growth inside the position from the last observation
/// @param pool Address of the Uniswap V3 pool
/// @return feeGrowthInside0LastX128 Fee growth inside for token0 from the last observation
/// @return feeGrowthInside1LastX128 Fee growth inside for token1 from the last observation
function _getFeeGrowthInsideLastX128(
IUniswapV3Pool pool
)
internal
view
returns (
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128
)
{
(
feeGrowthInside0LastX128,
feeGrowthInside1LastX128
) = _getFeeGrowthInsideLastX128(
pool,
keccak256(
abi.encodePacked(
address(positionManager),
party.lpTicks.tickLower,
party.lpTicks.tickUpper
)
)
);
}

/// @notice Internal function to retrieve the fee growth inside the position from the last observation
/// @param pool Address of the Uniswap V3 pool
function _getPartyFeeGrowthInsideLastX128(
IUniswapV3Pool pool
)
internal
view
returns (
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128
)
{
(
feeGrowthInside0LastX128,
feeGrowthInside1LastX128
) = _getFeeGrowthInsideLastX128(
pool,
keccak256(
abi.encodePacked(
address(BNBPositionManager),
party.partyTicks.tickLower,
party.partyTicks.tickUpper
)
)
);
}

/// @notice Internal function to retrieve the fee growth inside the position from the last observation
/// @param pool Address of the Uniswap V3 pool
function _getFeeGrowthInsideLastX128(
IUniswapV3Pool pool,
bytes32 key
)
internal
view
returns (
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128
)
{
(, feeGrowthInside0LastX128, feeGrowthInside1LastX128, , ) = pool.positions(key);
}

/// @notice Internal function to calculate the global fee growth
/// @param pool Address of the Uniswap V3 pool
function _calculateFeeGrowthGlobal(IUniswapV3Pool pool) internal view returns (uint256 feeGrowthGlobal) {
if (pool.token0() == address(WBNB)) {
(uint256 feeGrowthInside0LastX128,) = _getPartyFeeGrowthInsideLastX128(pool);
feeGrowthGlobal = pool.feeGrowthGlobal0X128() - feeGrowthInside0LastX128;
} else {
(,uint256 feeGrowthInside1LastX128) = _getPartyFeeGrowthInsideLastX128(pool);
feeGrowthGlobal = pool.feeGrowthGlobal1X128() - feeGrowthInside1LastX128;
}
}
}
116 changes: 6 additions & 110 deletions contracts/BNBPartyLiquidity.sol
Original file line number Diff line number Diff line change
@@ -1,89 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./BNBPartySwaps.sol";
import "./BNBPartyLiquidityHelper.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

/// @title BNBPartyLiquidity
/// @notice This abstract contract manages the creation and handling of liquidity pools within the BNB Party system.
abstract contract BNBPartyLiquidity is BNBPartySwaps {
/// @notice Creates the first liquidity pool (FLP) for a given token.
/// @param _token Address of the token to be used in the liquidity pool
/// @return liquidityPool Address of the newly created liquidity pool
/// @dev Sets the token amounts based on the balance and initializes the pool
function _createFLP(address _token) internal returns (address liquidityPool) {
(address tokenA, address tokenB, uint160 sqrtPrice) = _getTokenPairAndPrice(_token);
uint256 amount0;
uint256 amount1;
if (IERC20(tokenA).balanceOf(address(this)) == party.initialTokenAmount) {
amount0 = party.initialTokenAmount; // Set amount0 if tokenA balance matches the initial amount
} else {
amount1 = party.initialTokenAmount; // Otherwise, set amount1
}
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
}

/// @notice Creates a new liquidity pool and mints liquidity positions.
/// @param liquidityManager Address of the liquidity manager contract
/// @param token0 Address of the first token in the pool
/// @param token1 Address of the second token in the pool
/// @param amount0 Amount of token0 to add to the pool
/// @param amount1 Amount of token1 to add to the pool
/// @param sqrtPriceX96 The initial sqrt price of the pool
/// @param fee Fee tier for the pool
/// @return liquidityPool Address of the created liquidity pool
/// @dev Creates and initializes the pool, then mints liquidity for the position
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
})
);
}

abstract contract BNBPartyLiquidity is BNBPartyLiquidityHelper {
/// @notice Handles liquidity by decreasing the liquidity, collecting tokens, and creating a new liquidity pool.
/// @param recipient Address receiving the bonus BNB
/// @dev Decreases liquidity, collects tokens, creates a new pool, and sends bonuses
@@ -95,24 +18,7 @@ abstract contract BNBPartyLiquidity is BNBPartySwaps {
uint128 liquidity = pool.liquidity();

// Decrease liquidity and collect tokens
(uint256 amount0, uint256 amount1) = BNBPositionManager.decreaseLiquidity(
INonfungiblePositionManager.DecreaseLiquidityParams({
tokenId: lpToTokenId[msg.sender],
liquidity: liquidity,
amount0Min: 0,
amount1Min: 0,
deadline: block.timestamp
})
);

BNBPositionManager.collect(
INonfungiblePositionManager.CollectParams({
tokenId: lpToTokenId[msg.sender],
recipient: address(this),
amount0Max: uint128(amount0),
amount1Max: uint128(amount1)
})
);
(uint256 amount0, uint256 amount1) = _decreaseAndCollect(lpToTokenId[msg.sender], liquidity);

uint256 unwrapAmount = party.bonusTargetReach + party.bonusPartyCreator + party.targetReachFee;
uint160 newSqrtPriceX96;
@@ -136,24 +42,14 @@ abstract contract BNBPartyLiquidity is BNBPartySwaps {
);
}

IERC20(token0).approve(address(positionManager), amount0);
IERC20(token1).approve(address(positionManager), amount1);
// 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
if(token0 == address(WBNB)) {
_burnMemeToken(token1);
}
else {
_burnMemeToken(token0);
}
}

function _burnMemeToken(address token) internal {
uint256 balance = IERC20(token).balanceOf(address(this));
ERC20Burnable(token).burn(balance);
_burnMemeToken(token0 == address(WBNB) ? token1 : token0);
}
}
Loading