diff --git a/contracts/BNBPartyFactory.sol b/contracts/BNBPartyFactory.sol index 2a13f0f..3f42560 100644 --- a/contracts/BNBPartyFactory.sol +++ b/contracts/BNBPartyFactory.sol @@ -18,15 +18,15 @@ contract BNBPartyFactory is BNBPartyInternal, ReentrancyGuard { function createParty( string calldata name, string calldata symbol - ) external payable override nonReentrant returns (IERC20 newToken) { - require( - msg.value >= party.createTokenFee, - "BNBPartyFactory: insufficient BNB" - ); - require( - address(BNBPositionManager) != address(0), - "BNBPartyFactory: BNBPositionManager not set" - ); + ) + 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 @@ -37,9 +37,9 @@ contract BNBPartyFactory is BNBPartyInternal, ReentrancyGuard { emit StartParty(address(newToken), msg.sender, liquidityPool); } - function handleSwap(address recipient) external override { - require(isParty[msg.sender], "LP is not at the party"); - + function handleSwap( + address recipient + ) external override onlyParty notZeroAddress(recipient) { uint256 WBNBBalance = WBNB.balanceOf(msg.sender); if (WBNBBalance < party.partyTarget) return; @@ -52,33 +52,29 @@ contract BNBPartyFactory is BNBPartyInternal, ReentrancyGuard { function joinParty( address tokenOut, - uint256 amountOutMinimum, - uint256 deadline - ) external payable { + uint256 amountOutMinimum + ) external payable notZeroAddress(tokenOut) notZeroValue { _executeSwap( address(WBNB), tokenOut, msg.sender, amountOutMinimum, - deadline, msg.value ); } function leaveParty( - IERC20 tokenIn, + address tokenIn, uint256 amountIn, - uint256 amountOutMinimum, - uint256 deadline - ) external { - tokenIn.safeTransferFrom(msg.sender, address(this), amountIn); - tokenIn.safeIncreaseAllowance(address(swapRouter), amountIn); + uint256 amountOutMinimum + ) external notZeroAddress(tokenIn) notZeroAmount(amountIn) { + IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn); + IERC20(tokenIn).safeIncreaseAllowance(address(swapRouter), amountIn); _executeSwap( - address(tokenIn), + tokenIn, address(WBNB), address(swapRouter), amountOutMinimum, - deadline, amountIn ); IPeripheryPayments(address(swapRouter)).unwrapWETH9( diff --git a/contracts/BNBPartyInternal.sol b/contracts/BNBPartyInternal.sol index 3abe212..bdd04cc 100644 --- a/contracts/BNBPartyInternal.sol +++ b/contracts/BNBPartyInternal.sol @@ -3,8 +3,9 @@ pragma solidity ^0.8.0; import "./token/ERC20Token.sol"; import "./interfaces/IUniswapV3Pool.sol"; -import "./BNBPartyState.sol"; -abstract contract BNBPartyInternal is BNBPartyState { +import "./BNBPartyModifiers.sol"; + +abstract contract BNBPartyInternal is BNBPartyModifiers { function _createFLP( address _token ) internal returns (address liquidityPool) { @@ -99,7 +100,7 @@ abstract contract BNBPartyInternal is BNBPartyState { function _executeSwap(address tokenOut) internal { uint256 amountIn = msg.value - party.createTokenFee; - _executeSwap(address(WBNB), tokenOut, msg.sender, 0, block.timestamp, amountIn); + _executeSwap(address(WBNB), tokenOut, msg.sender, 0, amountIn); } function _executeSwap( @@ -107,18 +108,13 @@ abstract contract BNBPartyInternal is BNBPartyState { address tokenOut, address recipient, uint256 amountOutMinimum, - uint256 deadline, uint256 amountIn - ) internal { - require( - address(swapRouter) != address(0), - "BNBPartyFactory: swapRouter not set" - ); + ) internal notZeroAddress(address(swapRouter)) { ISwapRouter.ExactInputParams memory params = ISwapRouter .ExactInputParams({ path: abi.encodePacked(tokenIn, party.partyLpFee, tokenOut), recipient: recipient, - deadline: deadline, + deadline: block.timestamp, amountIn: amountIn, amountOutMinimum: amountOutMinimum }); diff --git a/contracts/BNBPartyModifiers.sol b/contracts/BNBPartyModifiers.sol new file mode 100644 index 0000000..219aa18 --- /dev/null +++ b/contracts/BNBPartyModifiers.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./BNBPartyState.sol"; + +abstract contract BNBPartyModifiers is BNBPartyState { + modifier onlyParty() { + if (!isParty[msg.sender]) revert LPNotAtParty(); + _; + } + + modifier notZeroAddress(address _address) { + if (_address == address(0)) revert ZeroAddress(); + _; + } + + modifier insufficientBNB() { + if (msg.value < party.createTokenFee) revert InsufficientBNB(); + _; + } + + modifier notZeroAmount(uint256 _amount) { + if (_amount == 0) revert ZeroAmount(); + _; + } + + modifier notZeroValue() { + if (msg.value == 0) revert ZeroAmount(); + _; + } +} diff --git a/contracts/BNBPartyState.sol b/contracts/BNBPartyState.sol index 0c4f156..bb0921d 100644 --- a/contracts/BNBPartyState.sol +++ b/contracts/BNBPartyState.sol @@ -20,13 +20,21 @@ abstract contract BNBPartyState is IBNBPartyFactory, Ownable { IWBNB public immutable WBNB; constructor(Party memory _party, IWBNB _WBNB) Ownable(_msgSender()) { - require(_party.partyTarget > 0, "buyLimit is zero"); - require(_party.initialTokenAmount > 0, "initialTokenAmount is zero"); - require( - _party.partyTarget > _party.bonusPartyCreator, - "partyTarget is less than bonusParty" - ); - require(_party.sqrtPriceX96 > 0, "sqrtPriceX96 is zero"); + if (address(_WBNB) == address(0)) { + revert ZeroAddress(); + } + if (_party.partyTarget == 0) { + revert ZeroAmount(); + } + if (_party.initialTokenAmount == 0) { + revert ZeroAmount(); + } + if (_party.partyTarget <= _party.bonusPartyCreator) { + revert BonusGreaterThanTarget(); + } + if (_party.sqrtPriceX96 == 0) { + revert ZeroAmount(); + } party = _party; WBNB = _WBNB; } @@ -35,20 +43,17 @@ abstract contract BNBPartyState is IBNBPartyFactory, Ownable { INonfungiblePositionManager _BNBPositionManager, INonfungiblePositionManager _positionManager ) external onlyOwner { - require( - _BNBPositionManager != BNBPositionManager && - _positionManager != positionManager, - "BNBPartyFactory: positionManager already set" - ); + if (_BNBPositionManager == BNBPositionManager && _positionManager == positionManager) { + revert PositionManagerAlreadySet(); + } positionManager = _positionManager; BNBPositionManager = _BNBPositionManager; } function setSwapRouter(ISwapRouter _swapRouter) external onlyOwner { - require( - _swapRouter != swapRouter, - "BNBPartyFactory: swapRouter already set" - ); + if (_swapRouter == swapRouter) { + revert SwapRouterAlreadySet(); + } swapRouter = _swapRouter; } } diff --git a/contracts/interfaces/IBNBPartyFactory.sol b/contracts/interfaces/IBNBPartyFactory.sol index aaf5a8a..d6ddfb4 100644 --- a/contracts/interfaces/IBNBPartyFactory.sol +++ b/contracts/interfaces/IBNBPartyFactory.sol @@ -37,4 +37,13 @@ interface IBNBPartyFactory { address indexed owner, address indexed FLPAddress ); + + error InsufficientBNB(); + error ZeroAddress(); + error ZeroAmount(); + error BonusGreaterThanTarget(); + error PositionManagerNotSet(); + error PositionManagerAlreadySet(); + error SwapRouterAlreadySet(); + error LPNotAtParty(); } diff --git a/test/BNBPartyFactory.ts b/test/BNBPartyFactory.ts index a02249c..f951962 100644 --- a/test/BNBPartyFactory.ts +++ b/test/BNBPartyFactory.ts @@ -124,16 +124,16 @@ describe("BNBPartyFactory", function () { }) it("should revert if not enough BNB is sent", async function () { - await expect(bnbPartyFactory.createParty(name, symbol, { value: tokenCreationFee - 1n })).to.be.revertedWith( - "BNBPartyFactory: insufficient BNB" - ) + await expect( + bnbPartyFactory.createParty(name, symbol, { value: tokenCreationFee - 1n }) + ).to.be.revertedWithCustomError(bnbPartyFactory, "InsufficientBNB") }) it("should revert to Create Party if position manager is not set", async function () { await bnbPartyFactory.setNonfungiblePositionManager(ethers.ZeroAddress, ethers.ZeroAddress) - await expect(bnbPartyFactory.createParty(name, symbol, { value: tokenCreationFee })).to.be.revertedWith( - "BNBPartyFactory: BNBPositionManager not set" - ) + await expect( + bnbPartyFactory.createParty(name, symbol, { value: tokenCreationFee }) + ).to.be.revertedWithCustomError(bnbPartyFactory, "ZeroAddress") await bnbPartyFactory.setNonfungiblePositionManager( await positionManager.getAddress(), await positionManager.getAddress() @@ -143,8 +143,9 @@ describe("BNBPartyFactory", function () { it("should revert if swap router is not set", async function () { const amountIn = ethers.parseUnits("1", 18) await bnbPartyFactory.setSwapRouter(ethers.ZeroAddress) - await expect(bnbPartyFactory.createParty(name, symbol, { value: amountIn })).to.be.revertedWith( - "BNBPartyFactory: swapRouter not set" + await expect(bnbPartyFactory.createParty(name, symbol, { value: amountIn })).to.be.revertedWithCustomError( + bnbPartyFactory, + "ZeroAddress" ) await bnbPartyFactory.setSwapRouter(await swapRouter.getAddress()) }) @@ -168,7 +169,7 @@ describe("BNBPartyFactory", function () { const amountIn = ethers.parseUnits("5", 17) const lpBalanceBefore = await weth9.balanceOf(lpAddress) - await bnbPartyFactory.joinParty(MEME, 0, deadline, { value: amountIn }) + await bnbPartyFactory.joinParty(MEME, 0, { value: amountIn }) const lpBalanceAfter = await weth9.balanceOf(lpAddress) expect(lpBalanceAfter).to.be.equal(lpBalanceBefore + amountIn) @@ -179,7 +180,7 @@ describe("BNBPartyFactory", function () { const tokenOutContract = await ethers.getContractAt("ERC20", MEME) const balanceBefore = await tokenOutContract.balanceOf(await signers[0].getAddress()) - await bnbPartyFactory.joinParty(MEME, 0, deadline, { value: amountIn }) + await bnbPartyFactory.joinParty(MEME, 0, { value: amountIn }) const balanceAfter = await tokenOutContract.balanceOf(await signers[0].getAddress()) expect(balanceAfter).to.be.gt(balanceBefore) @@ -191,7 +192,7 @@ describe("BNBPartyFactory", function () { // approve token await tokenOutContract.approve(await bnbPartyFactory.getAddress(), amountIn) const bnbBalanceBefore = await ethers.provider.getBalance(await signers[0].getAddress()) - await bnbPartyFactory.leaveParty(MEME, amountIn, 0, deadline) + await bnbPartyFactory.leaveParty(MEME, amountIn, 0) const bnbBalanceAfter = await ethers.provider.getBalance(await signers[0].getAddress()) expect(bnbBalanceAfter).to.be.gt(bnbBalanceBefore) }) @@ -203,7 +204,7 @@ describe("BNBPartyFactory", function () { await tokenOutContract.approve(await bnbPartyFactory.getAddress(), amountIn) const lpBalanceBefore = await weth9.balanceOf(lpAddress) - await bnbPartyFactory.leaveParty(MEME, amountIn, 0, deadline) + await bnbPartyFactory.leaveParty(MEME, amountIn, 0) const lpBalanceAfter = await weth9.balanceOf(lpAddress) expect(lpBalanceBefore).to.be.gt(lpBalanceAfter) @@ -297,7 +298,7 @@ describe("BNBPartyFactory", function () { expect(liquidityPoolBalance).to.be.equal(amountIn - tokenCreationFee) }) - it("Should increase user tokens with excess party fee", async () => { + it("should increase user tokens with excess party fee", async () => { const amountIn = ethers.parseUnits("1", 17) const tx = await bnbPartyFactory.createParty(name, symbol, { value: amountIn }) await tx.wait() @@ -311,6 +312,32 @@ describe("BNBPartyFactory", function () { expect(balance).to.be.gt(0) }) + it("should revert tokenOut zero address on join party", async () => { + await expect( + bnbPartyFactory.joinParty(ethers.ZeroAddress, 0, { value: ethers.parseUnits("1", 17) }) + ).to.be.revertedWithCustomError(bnbPartyFactory, "ZeroAddress") + }) + + it("should revert zero msg.value on join party", async () => { + await expect(bnbPartyFactory.joinParty(MEME, 0)).to.be.revertedWithCustomError( + bnbPartyFactory, + "ZeroAmount" + ) + }) + + it('should revert if "amountIn" is zero on leave party', async () => { + await expect(bnbPartyFactory.leaveParty(MEME, 0, 0)).to.be.revertedWithCustomError( + bnbPartyFactory, + "ZeroAmount" + ) + }) + + it("should revert if tokenOut zero address on leave party", async () => { + await expect( + bnbPartyFactory.leaveParty(ethers.ZeroAddress, ethers.parseUnits("1", 16), 0) + ).to.be.revertedWithCustomError(bnbPartyFactory, "ZeroAddress") + }) + function getDataHexString(token0: string, token1: string) { return ethers.concat([ ethers.zeroPadValue(token0, 20),