|
| 1 | +// SPDX-License-Identifier: UNLICENSED |
| 2 | +pragma solidity ^0.8.13; |
| 3 | + |
| 4 | +import {Test, console} from "forge-std/Test.sol"; |
| 5 | +import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; |
| 6 | +import {BondingCurveFactory} from "../src/BondingCurveFactory.sol"; |
| 7 | +import {BondingCurve} from "../src/BondingCurve.sol"; |
| 8 | +import {Token} from "../src/Token.sol"; |
| 9 | +import {WMon} from "../src/WMon.sol"; |
| 10 | +import {IBondingCurveFactory} from "../src/interfaces/IBondingCurveFactory.sol"; |
| 11 | +import "../src/errors/CustomErrors.sol" as CustomErrors; |
| 12 | + |
| 13 | +contract BondingCurveFactoryTest is Test { |
| 14 | + BondingCurveFactory public factory; |
| 15 | + WMon public wMon; |
| 16 | + address public owner = address(0x123); |
| 17 | + address public gNad = address(0x456); |
| 18 | + address public dexFactory = address(0x789); |
| 19 | + |
| 20 | + uint256 public constant DEPLOY_FEE = 0.1 ether; |
| 21 | + uint256 public constant LISTING_FEE = 0.05 ether; |
| 22 | + uint256 public constant TOKEN_TOTAL_SUPPLY = 10 ** 27; |
| 23 | + uint256 public constant VIRTUAL_NATIVE = 1 ether; |
| 24 | + uint256 public constant VIRTUAL_TOKEN = 1000 ether; |
| 25 | + uint256 public constant TARGET_TOKEN = 100 ether; |
| 26 | + uint8 public constant FEE_DENOMINATOR = 100; |
| 27 | + uint16 public constant FEE_NUMERATOR = 1; |
| 28 | + |
| 29 | + function setUp() public { |
| 30 | + wMon = new WMon(); |
| 31 | + factory = new BondingCurveFactory(owner, gNad, address(wMon)); |
| 32 | + |
| 33 | + // Initialize factory |
| 34 | + IBondingCurveFactory.InitializeParams memory params = IBondingCurveFactory.InitializeParams({ |
| 35 | + deployFee: DEPLOY_FEE, |
| 36 | + listingFee: LISTING_FEE, |
| 37 | + tokenTotalSupply: TOKEN_TOTAL_SUPPLY, |
| 38 | + virtualNative: VIRTUAL_NATIVE, |
| 39 | + virtualToken: VIRTUAL_TOKEN, |
| 40 | + targetToken: TARGET_TOKEN, |
| 41 | + feeNumerator: FEE_NUMERATOR, |
| 42 | + feeDenominator: FEE_DENOMINATOR, |
| 43 | + dexFactory: dexFactory |
| 44 | + }); |
| 45 | + |
| 46 | + vm.prank(owner); |
| 47 | + factory.initialize(params); |
| 48 | + } |
| 49 | + |
| 50 | + function test_InitialState() public { |
| 51 | + assertEq(factory.WMON(), address(wMon)); |
| 52 | + assertEq(factory.getOwner(), owner); |
| 53 | + assertEq(factory.getGNad(), gNad); |
| 54 | + assertEq(factory.getDexFactory(), dexFactory); |
| 55 | + } |
| 56 | + |
| 57 | + function test_Initialize() public { |
| 58 | + IBondingCurveFactory.Config memory config = factory.getConfig(); |
| 59 | + assertEq(config.deployFee, DEPLOY_FEE); |
| 60 | + assertEq(config.listingFee, LISTING_FEE); |
| 61 | + assertEq(config.tokenTotalSupply, TOKEN_TOTAL_SUPPLY); |
| 62 | + assertEq(config.virtualNative, VIRTUAL_NATIVE); |
| 63 | + assertEq(config.virtualToken, VIRTUAL_TOKEN); |
| 64 | + assertEq(config.k, VIRTUAL_NATIVE * VIRTUAL_TOKEN); |
| 65 | + assertEq(config.targetToken, TARGET_TOKEN); |
| 66 | + assertEq(config.feeDenominator, FEE_DENOMINATOR); |
| 67 | + assertEq(config.feeNumerator, FEE_NUMERATOR); |
| 68 | + } |
| 69 | + |
| 70 | + function test_Initialize_Fails_NonOwner() public { |
| 71 | + IBondingCurveFactory.InitializeParams memory params = IBondingCurveFactory.InitializeParams({ |
| 72 | + deployFee: DEPLOY_FEE, |
| 73 | + listingFee: LISTING_FEE, |
| 74 | + tokenTotalSupply: TOKEN_TOTAL_SUPPLY, |
| 75 | + virtualNative: VIRTUAL_NATIVE, |
| 76 | + virtualToken: VIRTUAL_TOKEN, |
| 77 | + targetToken: TARGET_TOKEN, |
| 78 | + feeNumerator: FEE_NUMERATOR, |
| 79 | + feeDenominator: FEE_DENOMINATOR, |
| 80 | + dexFactory: dexFactory |
| 81 | + }); |
| 82 | + |
| 83 | + vm.expectRevert(bytes(CustomErrors.INVALID_BC_FACTORY_OWNER)); |
| 84 | + factory.initialize(params); |
| 85 | + } |
| 86 | + |
| 87 | + function test_Create() public { |
| 88 | + address creator = address(0xABC); |
| 89 | + string memory name = "Test Token"; |
| 90 | + string memory symbol = "TEST"; |
| 91 | + string memory tokenURI = "https://example.com"; |
| 92 | + |
| 93 | + vm.expectEmit(true, true, true, true); |
| 94 | + emit IBondingCurveFactory.Create( |
| 95 | + creator, address(0), address(0), tokenURI, name, symbol, VIRTUAL_NATIVE, VIRTUAL_TOKEN |
| 96 | + ); |
| 97 | + |
| 98 | + vm.prank(gNad); |
| 99 | + (address bc, address token, uint256 vNative, uint256 vToken) = |
| 100 | + factory.create(creator, name, symbol, tokenURI); |
| 101 | + |
| 102 | + assertTrue(bc != address(0)); |
| 103 | + assertTrue(token != address(0)); |
| 104 | + assertEq(vNative, VIRTUAL_NATIVE); |
| 105 | + assertEq(vToken, VIRTUAL_TOKEN); |
| 106 | + |
| 107 | + // Verify bonding curve exists for token |
| 108 | + assertEq(factory.getBc(token), bc); |
| 109 | + |
| 110 | + // Verify token was minted to bonding curve |
| 111 | + assertEq(IERC20(token).balanceOf(bc), TOKEN_TOTAL_SUPPLY); |
| 112 | + } |
| 113 | + |
| 114 | + function test_Create_Fails_NonGNad() public { |
| 115 | + vm.expectRevert(bytes(CustomErrors.INVALID_GNAD)); |
| 116 | + factory.create(address(0xABC), "Test", "TEST", "https://example.com"); |
| 117 | + } |
| 118 | + |
| 119 | + function test_GetConfig() public { |
| 120 | + IBondingCurveFactory.Config memory config = factory.getConfig(); |
| 121 | + assertEq(config.deployFee, DEPLOY_FEE); |
| 122 | + assertEq(config.listingFee, LISTING_FEE); |
| 123 | + } |
| 124 | + |
| 125 | + function test_GetK() public { |
| 126 | + assertEq(factory.getK(), VIRTUAL_NATIVE * VIRTUAL_TOKEN); |
| 127 | + } |
| 128 | + |
| 129 | + function test_GetDelpyFee() public { |
| 130 | + assertEq(factory.getDelpyFee(), DEPLOY_FEE); |
| 131 | + } |
| 132 | + |
| 133 | + function test_GetListingFee() public { |
| 134 | + assertEq(factory.getListingFee(), LISTING_FEE); |
| 135 | + } |
| 136 | + |
| 137 | + function test_GetFeeConfig() public { |
| 138 | + (uint8 denominator, uint16 numerator) = factory.getFeeConfig(); |
| 139 | + assertEq(denominator, FEE_DENOMINATOR); |
| 140 | + assertEq(numerator, FEE_NUMERATOR); |
| 141 | + } |
| 142 | + |
| 143 | + function test_SetOwner() public { |
| 144 | + address newOwner = address(0x999); |
| 145 | + |
| 146 | + vm.prank(owner); |
| 147 | + factory.setOwner(newOwner); |
| 148 | + |
| 149 | + assertEq(factory.getOwner(), newOwner); |
| 150 | + } |
| 151 | + |
| 152 | + function test_SetOwner_Fails_NonOwner() public { |
| 153 | + vm.expectRevert(bytes(CustomErrors.INVALID_BC_FACTORY_OWNER)); |
| 154 | + factory.setOwner(address(0x999)); |
| 155 | + } |
| 156 | + |
| 157 | + function test_SetGNad() public { |
| 158 | + address newGNad = address(0x888); |
| 159 | + |
| 160 | + vm.expectEmit(true, false, false, true); |
| 161 | + emit IBondingCurveFactory.SetGNad(newGNad); |
| 162 | + |
| 163 | + vm.prank(owner); |
| 164 | + factory.setGNad(newGNad); |
| 165 | + |
| 166 | + assertEq(factory.getGNad(), newGNad); |
| 167 | + } |
| 168 | + |
| 169 | + function test_SetDexFactory() public { |
| 170 | + address newDexFactory = address(0x777); |
| 171 | + |
| 172 | + vm.expectEmit(true, false, false, true); |
| 173 | + emit IBondingCurveFactory.SetDexFactory(newDexFactory); |
| 174 | + |
| 175 | + vm.prank(owner); |
| 176 | + factory.setDexFactory(newDexFactory); |
| 177 | + |
| 178 | + assertEq(factory.getDexFactory(), newDexFactory); |
| 179 | + } |
| 180 | + |
| 181 | + function test_MultipleCreates() public { |
| 182 | + vm.startPrank(gNad); |
| 183 | + |
| 184 | + (address bc1, address token1,,) = factory.create(address(0x1), "Token1", "T1", "uri1"); |
| 185 | + (address bc2, address token2,,) = factory.create(address(0x2), "Token2", "T2", "uri2"); |
| 186 | + |
| 187 | + vm.stopPrank(); |
| 188 | + |
| 189 | + assertTrue(bc1 != bc2); |
| 190 | + assertTrue(token1 != token2); |
| 191 | + assertEq(factory.getBc(token1), bc1); |
| 192 | + assertEq(factory.getBc(token2), bc2); |
| 193 | + } |
| 194 | +} |
| 195 | + |
0 commit comments