Skip to content

Commit f0559ff

Browse files
committed
feat: test cases for invariant testing
1 parent 224cd2f commit f0559ff

File tree

9 files changed

+1359
-9
lines changed

9 files changed

+1359
-9
lines changed

src/FeeVault.sol

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,6 @@ contract FeeVault is IFeeVault {
2222
uint256 public ownerCount;
2323
uint256 public proposalCount;
2424

25-
// Withdrawal proposal structure
26-
struct WithdrawalProposal {
27-
address receiver;
28-
uint256 amount;
29-
uint256 signatureCount;
30-
mapping(address => bool) hasSignedWithdrawal;
31-
bool executed;
32-
}
33-
3425
/**
3526
* @notice Fallback function to receive WMON
3627
* @dev Only accepts WMON from the WMON contract

src/interfaces/IFeeVault.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ pragma solidity ^0.8.13;
66
* @dev Interface for the FeeVault contract that manages WNAD token withdrawals through multisig.
77
*/
88
interface IFeeVault {
9+
// Withdrawal proposal structure
10+
struct WithdrawalProposal {
11+
address receiver;
12+
uint256 amount;
13+
uint256 signatureCount;
14+
mapping(address => bool) hasSignedWithdrawal;
15+
bool executed;
16+
}
17+
918
/**
1019
* @dev Emitted when a new owner is added
1120
*/

test/BondingCurve.t.sol

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.13;
3+
4+
import {Test, console} from "forge-std/Test.sol";
5+
import {BondingCurve} from "../src/BondingCurve.sol";
6+
import {Token} from "../src/Token.sol";
7+
import {WMon} from "../src/WMon.sol";
8+
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
9+
import {IBondingCurve} from "../src/interfaces/IBondingCurve.sol";
10+
import "../src/errors/CustomErrors.sol" as CustomErrors;
11+
12+
contract BondingCurveTest is Test {
13+
BondingCurve public bondingCurve;
14+
Token public token;
15+
WMon public wMon;
16+
address public factory = address(0x123);
17+
address public gNad = address(0x456);
18+
19+
uint256 public constant VIRTUAL_NATIVE = 1 ether;
20+
uint256 public constant VIRTUAL_TOKEN = 1000 ether;
21+
uint256 public constant K = VIRTUAL_NATIVE * VIRTUAL_TOKEN;
22+
uint256 public constant LOCKED_TOKEN = 100 ether;
23+
uint8 public constant FEE_DENOMINATOR = 100;
24+
uint16 public constant FEE_NUMERATOR = 1;
25+
26+
function setUp() public {
27+
wMon = new WMon();
28+
vm.prank(factory);
29+
bondingCurve = new BondingCurve(gNad, address(wMon));
30+
31+
vm.prank(factory);
32+
token = new Token("Test Token", "TEST", "https://example.com", gNad);
33+
34+
// Mint tokens to bonding curve
35+
vm.prank(factory);
36+
token.mint(address(bondingCurve));
37+
38+
// Initialize bonding curve
39+
vm.prank(factory);
40+
bondingCurve.initialize(
41+
address(token),
42+
VIRTUAL_NATIVE,
43+
VIRTUAL_TOKEN,
44+
K,
45+
LOCKED_TOKEN,
46+
FEE_DENOMINATOR,
47+
FEE_NUMERATOR
48+
);
49+
}
50+
51+
function test_Initialize() public {
52+
assertEq(bondingCurve.token(), address(token));
53+
assertEq(bondingCurve.WMON(), address(wMon));
54+
assertEq(bondingCurve.getK(), K);
55+
assertEq(bondingCurve.getLockedToken(), LOCKED_TOKEN);
56+
assertEq(bondingCurve.getLock(), false);
57+
assertEq(bondingCurve.getIsListing(), false);
58+
59+
(uint256 vNative, uint256 vToken) = bondingCurve.getVirtualReserves();
60+
assertEq(vNative, VIRTUAL_NATIVE);
61+
assertEq(vToken, VIRTUAL_TOKEN);
62+
63+
(uint8 denom, uint16 num) = bondingCurve.getFeeConfig();
64+
assertEq(denom, FEE_DENOMINATOR);
65+
assertEq(num, FEE_NUMERATOR);
66+
}
67+
68+
function test_Initialize_Fails_NonFactory() public {
69+
vm.expectRevert(bytes(CustomErrors.INVALID_FACTORY_ADDRESS));
70+
bondingCurve.initialize(
71+
address(token),
72+
VIRTUAL_NATIVE,
73+
VIRTUAL_TOKEN,
74+
K,
75+
LOCKED_TOKEN,
76+
FEE_DENOMINATOR,
77+
FEE_NUMERATOR
78+
);
79+
}
80+
81+
function test_GetReserves() public {
82+
(uint256 nativeRes, uint256 tokenRes) = bondingCurve.getReserves();
83+
assertEq(nativeRes, 0);
84+
assertEq(tokenRes, 10 ** 27); // Initial mint amount
85+
}
86+
87+
function test_GetVirtualReserves() public {
88+
(uint256 vNative, uint256 vToken) = bondingCurve.getVirtualReserves();
89+
assertEq(vNative, VIRTUAL_NATIVE);
90+
assertEq(vToken, VIRTUAL_TOKEN);
91+
}
92+
93+
function test_GetK() public {
94+
assertEq(bondingCurve.getK(), K);
95+
}
96+
97+
function test_GetLockedToken() public {
98+
assertEq(bondingCurve.getLockedToken(), LOCKED_TOKEN);
99+
}
100+
101+
function test_GetLock() public {
102+
assertEq(bondingCurve.getLock(), false);
103+
}
104+
105+
function test_GetIsListing() public {
106+
assertEq(bondingCurve.getIsListing(), false);
107+
}
108+
109+
function test_Buy_Fails_NotGNad() public {
110+
address recipient = address(0x999);
111+
uint256 amountOut = 10 ether;
112+
113+
vm.expectRevert(bytes(CustomErrors.INVALID_GNAD_ADDRESS));
114+
bondingCurve.buy(recipient, amountOut);
115+
}
116+
117+
function test_Buy_Fails_InvalidAmountOut() public {
118+
vm.prank(gNad);
119+
vm.expectRevert(bytes(CustomErrors.INVALID_AMOUNT_OUT));
120+
bondingCurve.buy(address(0x999), 0);
121+
}
122+
123+
function test_Buy_Fails_InvalidRecipient() public {
124+
vm.prank(gNad);
125+
vm.expectRevert(bytes(CustomErrors.INVALID_RECIPIENT));
126+
bondingCurve.buy(address(wMon), 10 ether);
127+
}
128+
129+
function test_Sell_Fails_NotGNad() public {
130+
vm.expectRevert(bytes(CustomErrors.INVALID_GNAD_ADDRESS));
131+
bondingCurve.sell(address(0x999), 1 ether);
132+
}
133+
134+
function test_Sell_Fails_InvalidAmountOut() public {
135+
vm.prank(gNad);
136+
vm.expectRevert(bytes(CustomErrors.INVALID_AMOUNT_OUT));
137+
bondingCurve.sell(address(0x999), 0);
138+
}
139+
}
140+

test/BondingCurveFactory.t.sol

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
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

Comments
 (0)