From 3223b677f165c6d47afe326dea906f4ec12286a6 Mon Sep 17 00:00:00 2001 From: Kai Kang Date: Thu, 11 Apr 2024 13:28:18 +0800 Subject: [PATCH] ADD: aime power fair launch v2 --- contracts/aime/AIMePowerFairLaunchV2.sol | 236 ++++++++++++++++++ contracts/aime/MathUtil.sol | 17 ++ contracts/aime/PowerSwapTest.sol | 75 ++++-- package.json | 1 + scripts/aime/deploy_aime.ts | 8 +- scripts/test-script.ts | 5 +- {test => test-archived}/AIMeFactoryV3.spec.ts | 2 +- test/PowerSwapTest.spec.ts | 124 ++++++--- 8 files changed, 402 insertions(+), 66 deletions(-) create mode 100644 contracts/aime/AIMePowerFairLaunchV2.sol create mode 100644 contracts/aime/MathUtil.sol rename {test => test-archived}/AIMeFactoryV3.spec.ts (99%) diff --git a/contracts/aime/AIMePowerFairLaunchV2.sol b/contracts/aime/AIMePowerFairLaunchV2.sol new file mode 100644 index 0000000..c56791b --- /dev/null +++ b/contracts/aime/AIMePowerFairLaunchV2.sol @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; +import "@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol"; +import "@uniswap/v3-periphery/contracts/interfaces/IPeripheryImmutableState.sol"; +import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; +import "@uniswap/v3-periphery/contracts/interfaces/external/IWETH9.sol"; +import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "../utils/ReentrancyGuard.sol"; +import "./MathUtil.sol"; + +contract AIMePowerFairLaunchV2 is ERC20, ReentrancyGuard, IERC721Receiver { + uint256 public price; + uint256 public amountPerUnits; + uint256 public reservedAmount; + uint256 public deadline; + uint24 public poolFee; + address public pool; + + uint256 public mintLimit; + uint256 public minted; + + bool public started; + address public launcher; + + address public immutable WETH; + ISwapRouter public immutable swapRouter; + INonfungiblePositionManager public immutable nonfungiblePositionManager; + + uint256 public positionTokenId; + + event AIMePowerFairMinted(address indexed to, uint256 amount, uint256 ethAmount); + event AIMePowerFairRefund(address indexed to, uint256 amount, uint256 ethAmount); + + constructor( + uint256 _price, + uint256 _amountPerUnits, + uint256 _totalSupply, + uint256 _reservedAmount, + address _launcher, + uint256 _deadline, + uint24 _poolFee, + INonfungiblePositionManager _nonfungiblePositionManager, + ISwapRouter _swapRouter, + string memory _name, + string memory _symbol + ) ERC20(_name, _symbol) { + price = _price; + amountPerUnits = _amountPerUnits; + deadline = _deadline; + launcher = _launcher; + reservedAmount = _reservedAmount; + poolFee = _poolFee; + started = false; + + _mint(address(this), _totalSupply); + + // 50% for mint + mintLimit = (_totalSupply - reservedAmount) / 2; + + // uniswap + nonfungiblePositionManager = _nonfungiblePositionManager; + swapRouter = _swapRouter; + WETH = IPeripheryImmutableState(address(_swapRouter)).WETH9(); + } + + /// @notice Collects the fees associated with provided liquidity + function collectFees() external { + // set amount0Max and amount1Max to uint256.max to collect all fees + INonfungiblePositionManager.CollectParams memory params = + INonfungiblePositionManager.CollectParams({ + tokenId: positionTokenId, + recipient: address(this), + amount0Max: type(uint128).max, + amount1Max: type(uint128).max + }); + + (uint256 amount0, uint256 amount1) = nonfungiblePositionManager.collect(params); + + // todo: send collected fee to receiver or just buy token + } + + receive() external payable { + // todo: require value != 0? + if (msg.sender != launcher) { + if (block.timestamp > deadline || minted == mintLimit) { + start(); + } else { + mint(); + } + } else { + start(); + } + } + + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) external override returns (bytes4) { + return this.onERC721Received.selector; + } + + function mint() internal virtual nonReentrant { + require(!started, "AIMEPowerFairLaunch: already started"); + require(msg.value >= price, "AIMEPowerFairLaunch: value not match"); + require(!_isContract(msg.sender), "AIMEPowerFairLaunch: can not mint to contract"); + require(msg.sender == tx.origin, "AIMEPowerFairLaunch: can not mint to contract."); + + uint256 units = msg.value / price; + uint256 amountDesired = units * amountPerUnits; + uint256 amount = amountDesired; + if (minted + amountDesired > mintLimit) { + amount = mintLimit - minted; + units = amount / amountPerUnits + 1; + } + + uint256 realCost = units * price; + uint256 refund = msg.value - realCost; + + minted += amount; + _transfer(address(this), msg.sender, amount); + + emit AIMePowerFairMinted(msg.sender, amount, realCost); + + if (refund > 0) { + (bool success, ) = payable(msg.sender).call{value: refund}(""); + require(success, "Failed to refund"); + } + } + + function start() internal { + require(!started, "AIMEPowerFairLaunch: already started"); + started = true; + + // eth -> weth + IWETH9(WETH).deposit{value: address(this).balance}(); + + if (address(this) < WETH) { + _createPool(address(this), WETH, minted, IWETH9(WETH).balanceOf(address(this))); + } else { + _createPool(WETH, address(this), IWETH9(WETH).balanceOf(address(this)), minted); + } + // todo: launch event + } + + function _createPool(address token0, address token1, uint256 token0Amount, uint256 token1Amount) internal { + uint160 sqrtPriceX96 = uint160((2 ** 96) * MathUtil.SquareRoot(token0Amount) / MathUtil.SquareRoot(token1Amount)); + + // init pool + pool = nonfungiblePositionManager + .createAndInitializePoolIfNecessary( + token0, + token1, + poolFee, + sqrtPriceX96 + ); + + // Approve the position manager + TransferHelper.safeApprove( + token0, + address(nonfungiblePositionManager), + token0Amount + ); + TransferHelper.safeApprove( + token1, + address(nonfungiblePositionManager), + token1Amount + ); + + int24 tickSpacing = IUniswapV3Pool(pool).tickSpacing(); + (, int24 tick, , , , , ) = IUniswapV3Pool(pool).slot0(); + + // todo: calculate tick lower and upper + INonfungiblePositionManager.MintParams + memory params = INonfungiblePositionManager.MintParams({ + token0: token0, + token1: token1, + fee: poolFee, + tickLower: tick - 2 * tickSpacing, + tickUpper: tick - 2 * tickSpacing, + amount0Desired: token0Amount, + amount1Desired: token1Amount, + amount0Min: token0Amount, + amount1Min: token1Amount, + recipient: address(this), + deadline: block.timestamp + }); + + (uint256 tokenId, uint256 liquidity, uint256 amount0, uint256 amount1) = nonfungiblePositionManager + .mint(params); + + positionTokenId = tokenId; + + // todo: refund tokens + } + + function _afterTokenTransfer( + address from, + address to, + uint256 amount + ) internal override { + if (!started && to == address(this) && from != address(0)) { + _refund(from, amount); + } + } + + function _refund(address from, uint256 value) internal nonReentrant { + require(!started, "AIMEPowerFairLaunch: already started"); + require(!_isContract(from), "AIMEPowerFairLaunch: can not refund to contract"); + require(from == tx.origin, "AIMEPowerFairLaunch: can not refund to contract."); + require(value >= amountPerUnits, "AIMEPowerFairLaunch: value not match"); + require(value % amountPerUnits == 0, "AIMEPowerFairLaunch: value not match"); + + uint256 ethAmount = (value / amountPerUnits) * price; + require(ethAmount > 0, "AIMEPowerFairLaunch: no refund"); + + minted -= value; + (bool success, ) = payable(from).call{value: ethAmount}(""); + require(success, "Failed to refund"); + + emit AIMePowerFairRefund(from, value, ethAmount); + } + + function _isContract(address _addr) internal view returns (bool) { + uint32 size; + assembly { + size := extcodesize(_addr) + } + return (size > 0); + } +} diff --git a/contracts/aime/MathUtil.sol b/contracts/aime/MathUtil.sol new file mode 100644 index 0000000..ed36baf --- /dev/null +++ b/contracts/aime/MathUtil.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +library MathUtil { + function SquareRoot(uint y) internal pure returns (uint z) { + if (y > 3) { + z = y; + uint x = y / 2 + 1; + while (x < z) { + z = x; + x = (y / x + x) / 2; + } + } else if (y != 0) { + z = 1; + } + } +} diff --git a/contracts/aime/PowerSwapTest.sol b/contracts/aime/PowerSwapTest.sol index 0745c7d..934334d 100644 --- a/contracts/aime/PowerSwapTest.sol +++ b/contracts/aime/PowerSwapTest.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import "@uniswap/v3-core/contracts/libraries/TickMath.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; import "@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol"; import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; @@ -12,9 +13,11 @@ import "@uniswap/v3-periphery/contracts/interfaces/external/IWETH9.sol"; import "./AIMePower.sol"; contract PowerSwapTest is IERC721Receiver { - address public constant WETH = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1; // arbitrum + address public constant WETH = 0x4200000000000000000000000000000000000006; // base uint24 public constant poolFee = 3000; - uint160 public constant sqrtPriceX96 = 79228162514264337593543950336000; + uint160 public constant sqrtPriceX96 = 10 * 2 ** 96; + address public token0; + address public token1; AIMePower public immutable aimePower; ISwapRouter public immutable swapRouter; @@ -22,6 +25,8 @@ contract PowerSwapTest is IERC721Receiver { address public pool; + event MintPosition(uint256 tokenId); + struct Deposit { address owner; uint128 liquidity; @@ -43,6 +48,19 @@ contract PowerSwapTest is IERC721Receiver { aimePower.mint(address(this), 10000 * 10 ** 18); } + function calSqrt(uint y) public pure returns (uint z) { + if (y > 3) { + z = y; + uint x = y / 2 + 1; + while (x < z) { + z = x; + x = (y / x + x) / 2; + } + } else if (y != 0) { + z = 1; + } + } + function _createDeposit(address owner, uint256 tokenId) internal { ( , @@ -80,15 +98,19 @@ contract PowerSwapTest is IERC721Receiver { return this.onERC721Received.selector; } - function createPowerSwap() external returns (address) { + function createPowerSwap() external payable returns (address) { // eth -> weth - // IWETH9(WETH).deposit{value: msg.value}(); + IWETH9(WETH).deposit{value: msg.value}(); + + (token0, token1) = address(aimePower) < WETH + ? (address(aimePower), WETH) + : (WETH, address(aimePower)); // init pool address poolAddress = nonfungiblePositionManager .createAndInitializePoolIfNecessary( - address(aimePower), - WETH, + token0, + token1, poolFee, sqrtPriceX96 ); @@ -97,11 +119,6 @@ contract PowerSwapTest is IERC721Receiver { return poolAddress; } - /// @notice Calls the mint function defined in periphery, mints the same amount of each token. For this example we are providing 1000 DAI and 1000 USDC in liquidity - /// @return tokenId The id of the newly minted ERC721 - /// @return liquidity The amount of liquidity for the position - /// @return amount0 The amount of token0 - /// @return amount1 The amount of token1 function mintNewPosition() external payable @@ -112,37 +129,36 @@ contract PowerSwapTest is IERC721Receiver { uint256 amount1 ) { - // eth -> weth - IWETH9(WETH).deposit{value: msg.value}(); - // For this example, we will provide equal amounts of liquidity in both assets. // Providing liquidity in both assets means liquidity will be earning fees and is considered in-range. - uint256 amount0ToMint = aimePower.balanceOf(address(this)); - uint256 amount1ToMint = IWETH9(WETH).balanceOf(address(this)); + uint256 amount0ToMint = IWETH9(WETH).balanceOf(address(this)); + uint256 amount1ToMint = amount0ToMint; // Approve the position manager TransferHelper.safeApprove( - address(aimePower), + token0, address(nonfungiblePositionManager), amount0ToMint ); TransferHelper.safeApprove( - WETH, + token1, address(nonfungiblePositionManager), amount1ToMint ); + int24 tickSpacing = IUniswapV3Pool(pool).tickSpacing(); + INonfungiblePositionManager.MintParams memory params = INonfungiblePositionManager.MintParams({ - token0: address(aimePower), - token1: WETH, - fee: poolFee, - tickLower: TickMath.MIN_TICK, - tickUpper: TickMath.MAX_TICK, + token0: token0, + token1: token1, + fee: 3000, + tickLower: -120, + tickUpper: 120, amount0Desired: amount0ToMint, amount1Desired: amount1ToMint, - amount0Min: 0, - amount1Min: 0, + amount0Min: amount0ToMint, + amount1Min: amount1ToMint, recipient: msg.sender, deadline: block.timestamp + 1 days }); @@ -151,8 +167,11 @@ contract PowerSwapTest is IERC721Receiver { (tokenId, liquidity, amount0, amount1) = nonfungiblePositionManager .mint(params); - // // Create a deposit - // _createDeposit(msg.sender, tokenId); + // todo: do we need this? + emit MintPosition(tokenId); + + // Create a deposit + _createDeposit(msg.sender, tokenId); // todo: refund tokens?? @@ -210,4 +229,6 @@ contract PowerSwapTest is IERC721Receiver { amountOut = swapRouter.exactInputSingle(params); return amountOut; } + + receive() external payable {} } diff --git a/package.json b/package.json index baa53ab..f19bddd 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "fork": "npx hardhat node --fork https://eth-mainnet.g.alchemy.com/v2/lJ62g_9sSAubdOyUnR0nWMijzbvO6411", "fork-arb": "npx hardhat node --fork https://arb-mainnet.g.alchemy.com/v2/jyfs77cEyexJUKOFqLCoWavP4sLpd4Y_", "fork-base-sepolia": "npx hardhat node --fork https://base-sepolia.g.alchemy.com/v2/9eXiLRTSOxWAQBV5eNj19NJCfIzQF28U", + "fork-base": "npx hardhat node --fork https://base-mainnet.g.alchemy.com/v2/n6zbgny3-Jdmwwrfi9b2HtGBVQQLaFCn", "clear-cache": "rm -rf artifacts/ cache/ typechain/", "deploy-sepolia": "npx hardhat run --network sepolia ./scripts/gptminer/deploy_gptminer.ts", "deploy-aime": "npx hardhat run --network sepolia ./scripts/aime/deploy_aime.ts", diff --git a/scripts/aime/deploy_aime.ts b/scripts/aime/deploy_aime.ts index b309977..c629905 100644 --- a/scripts/aime/deploy_aime.ts +++ b/scripts/aime/deploy_aime.ts @@ -1,12 +1,12 @@ import { ethers } from "hardhat"; -import { AIMeFactoryV3 } from "../../typechain"; +import { AIMeFactoryV4 } from "../../typechain"; -async function deployAIMeForTest(): Promise { - const contractFactory = await ethers.getContractFactory("AIMeFactoryV3"); +async function deployAIMeForTest(): Promise { + const contractFactory = await ethers.getContractFactory("AIMeFactoryV4"); const instance = await contractFactory.deploy(); await instance.deployed(); - console.log("AIMeFactory V3 contract deployed to", instance.address); + console.log("AIMeFactory V4 contract deployed to", instance.address); return instance; } diff --git a/scripts/test-script.ts b/scripts/test-script.ts index eb78cdf..6dd2c09 100644 --- a/scripts/test-script.ts +++ b/scripts/test-script.ts @@ -2,4 +2,7 @@ const yourToken_amount = 10000; // Token0 amount with 0 decimals const WETH_amount = 0.01; // Token1 amount with 0 decimals const SqrtPriceX96 = BigInt(Math.sqrt(yourToken_amount / WETH_amount) * 2 ** 96); -console.log("SqrtPriceX96: ", SqrtPriceX96.toString()); \ No newline at end of file +console.log("SqrtPriceX96: ", SqrtPriceX96.toString()); + +// SqrtPriceX96: +// sqrt(token0Amount / token1Amount) * 2^96 diff --git a/test/AIMeFactoryV3.spec.ts b/test-archived/AIMeFactoryV3.spec.ts similarity index 99% rename from test/AIMeFactoryV3.spec.ts rename to test-archived/AIMeFactoryV3.spec.ts index cd99cca..f4e59ec 100644 --- a/test/AIMeFactoryV3.spec.ts +++ b/test-archived/AIMeFactoryV3.spec.ts @@ -574,7 +574,7 @@ describe("AIMe Factory and NFT Contract", () => { const nftOnwer = await aimeNFTContract.ownerOf(1); expect(nftOnwer).eq(signer3.address); const tokenData = await aimeNFTContract.tokenContents(1); - console.log('tokenData', tokenData) + // console.log('tokenData', tokenData) // console.log("receipt", receipt) diff --git a/test/PowerSwapTest.spec.ts b/test/PowerSwapTest.spec.ts index 234a907..7dd8088 100644 --- a/test/PowerSwapTest.spec.ts +++ b/test/PowerSwapTest.spec.ts @@ -1,13 +1,16 @@ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { ethers } from "hardhat"; -import { AIMePower, PowerSwapTest } from "../typechain"; +import { AIMePower, PowerSwapTest, IUniswapV3Pool, IUniswapV3Pool__factory } from "../typechain"; const { expect } = require("chai"); -const WETH_ADDRESS = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; -const DAI_ADDRESS = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; -const DAI_DECIMALS = 18; -const SwapRouterAddress = "0xE592427A0AEce92De3Edee1F18E0157C05861564"; -const NonfungiblePositionManager = "0xC36442b4a4522E871399CD717aBDD847Ab11FE88"; +// const WETH_ADDRESS = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; +const WETH_ADDRESS = "0x4200000000000000000000000000000000000006"; // base weth +// const DAI_ADDRESS = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; +// const DAI_DECIMALS = 18; +// const SwapRouterAddress = "0xE592427A0AEce92De3Edee1F18E0157C05861564"; +const SwapRouterAddress = "0x2626664c2603336E57B271c5C0b26F421741e481"; // swap router2 on base +// const NonfungiblePositionManager = "0xC36442b4a4522E871399CD717aBDD847Ab11FE88"; +const NonfungiblePositionManager = "0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1"; // on base // alchemy key lJ62g_9sSAubdOyUnR0nWMijzbvO6411 @@ -17,6 +20,8 @@ describe("PowerSwapTest", () => { let signer3: SignerWithAddress; let powerSwapTestContract: PowerSwapTest; let powerContract: AIMePower; + let wethContract: AIMePower; + let poolContract: IUniswapV3Pool; beforeEach("init", async () => { [owner, signer2, signer3] = await ethers.getSigners(); @@ -26,14 +31,20 @@ describe("PowerSwapTest", () => { const powerSwapTestContractFactory = await ethers.getContractFactory( "PowerSwapTest" ); - powerSwapTestContract = await powerSwapTestContractFactory.deploy(NonfungiblePositionManager, SwapRouterAddress); + powerSwapTestContract = await powerSwapTestContractFactory.deploy( + NonfungiblePositionManager, + SwapRouterAddress + ); await powerSwapTestContract.deployed(); const aimePowerAddress = await powerSwapTestContract.aimePower(); - const aimePowerContractFactory = await ethers.getContractFactory("AIMePower"); - powerContract = await aimePowerContractFactory.attach( - aimePowerAddress + const aimePowerContractFactory = await ethers.getContractFactory( + "AIMePower" ); + powerContract = await aimePowerContractFactory.attach(aimePowerAddress); + + const wethContractFactory = await ethers.getContractFactory("AIMePower"); + wethContract = await wethContractFactory.attach(WETH_ADDRESS); // const permit2VaultContractFactory = await ethers.getContractFactory( // "Permit2Vault" @@ -54,31 +65,78 @@ describe("PowerSwapTest", () => { const aimePowerAddress = await powerSwapTestContract.aimePower(); expect(aimePowerAddress).to.be.eq(powerContract.address); - const powerBalance = await powerContract.balanceOf(powerSwapTestContract.address); + const powerBalance = await powerContract.balanceOf( + powerSwapTestContract.address + ); expect(powerBalance).to.be.eq(ethers.utils.parseEther("10000")); - }) + }); + + it("compute sqrt", async () => { + const value1 = await powerSwapTestContract.calSqrt(100); + expect(value1).to.be.eq(10); + + const value2 = await powerSwapTestContract.calSqrt(4); + expect(value2).to.be.eq(2); + }); + + it("create pool and swap", async () => { + const tx = await powerSwapTestContract.createPowerSwap(); + await tx.wait(); + + const pool = await powerSwapTestContract.pool(); + console.log("pool address:", pool); - // it("create pool and swap", async () => { - // const tx = await powerSwapTestContract.createPowerSwap(); - // await tx.wait(); - - // const pool = await powerSwapTestContract.pool(); - // console.log('pool address:', pool); - - // // const ethValue = ethers.utils.parseEther("0.01"); - // // console.log('eth value:', ethValue.toString()); - // // const tx2 = await powerSwapTestContract.connect(owner).mintNewPosition({value: ethValue}); - // // await tx2.wait(); - - // // const powerBalanceBeforeSwap = await powerContract.balanceOf(owner.address); - // // console.log('power balance before swap:', powerBalanceBeforeSwap.toString()); - // // const tx3 = await powerSwapTestContract.swapETHForPower({value: ethers.utils.parseEther("0.01")}); - // // await tx3.wait(); - // // const powerBalanceAfterSwap = await powerContract.balanceOf(owner.address); - // // console.log('power balance after swap:', powerBalanceAfterSwap.toString()); - // // expect(powerBalanceAfterSwap).to.be.gt(powerBalanceBeforeSwap); - // }) -}) + // const poolContractFactory = (await ethers.getContractFactory( + // "IUniswapV3Pool" + // )).connect(); + poolContract = IUniswapV3Pool__factory.connect(pool, owner); + + const tickSpacing = await poolContract.tickSpacing(); + console.log("tickSpacing:", tickSpacing.toString()); + + const slot0 = await poolContract.slot0(); + console.log("slot0:", slot0); + + const ethValue = ethers.utils.parseEther("0.01"); + await owner.sendTransaction({ + to: powerSwapTestContract.address, + value: ethValue, + }); + + const wethBalance = await wethContract.balanceOf( + powerSwapTestContract.address + ); + expect(wethBalance).to.be.eq(ethValue); + + const token0 = await powerSwapTestContract.token0(); + const token1 = await powerSwapTestContract.token1(); + console.log("token0:", token0); + console.log("token1:", token1); + + const tx2 = await powerSwapTestContract + .connect(owner) + .mintNewPosition({ value: ethValue }); + const receipt = await tx2.wait(); + + // console.log("mint rec", receipt); + const newPositionMintedEvent = receipt.events?.find( + (event) => event.event === "MintPosition" + ); + if (newPositionMintedEvent) { + const tokenId = newPositionMintedEvent.args?.tokenId; + const deposit = await powerSwapTestContract.deposits(tokenId); + console.log("deposit:", deposit); + } + + // const powerBalanceBeforeSwap = await powerContract.balanceOf(owner.address); + // console.log('power balance before swap:', powerBalanceBeforeSwap.toString()); + // const tx3 = await powerSwapTestContract.swapETHForPower({value: ethers.utils.parseEther("0.01")}); + // await tx3.wait(); + // const powerBalanceAfterSwap = await powerContract.balanceOf(owner.address); + // console.log('power balance after swap:', powerBalanceAfterSwap.toString()); + // expect(powerBalanceAfterSwap).to.be.gt(powerBalanceBeforeSwap); + }) +}); // describe("SimpleSwap", function () { // it("Should provide a caller with more DAI than they started with after a swap", async function () {