// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.19; import "../src/Kraiken.sol"; import { IERC20 } from "@openzeppelin/token/ERC20/IERC20.sol"; import "forge-std/Test.sol"; import "forge-std/console.sol"; contract KraikenTest is Test { Kraiken internal kraiken; address internal stakingPool; address internal liquidityPool; address internal liquidityManager; function setUp() public { kraiken = new Kraiken("KRAIKEN", "KRK"); stakingPool = makeAddr("stakingPool"); kraiken.setStakingPool(stakingPool); liquidityManager = makeAddr("liquidityManager"); kraiken.setLiquidityManager(liquidityManager); } // Simulates staking by transferring tokens to the stakingPool address. function simulateStake(uint256 amount) internal { // the amount of token has to be available on the balance // of the test contract kraiken.transfer(stakingPool, amount); } // Simulates unstaking by transferring tokens from the stakingPool back to a given address. function simulateUnstake(uint256 amount) internal { // Direct transfer from the stakingPool to 'to' address to simulate unstaking vm.prank(stakingPool); // Assuming 'stake' contract would allow this in an actual scenario kraiken.transfer(address(this), amount); } function testKraikenConstructor() public view { // Check if the token details are set as expected assertEq(kraiken.name(), "KRAIKEN"); assertEq(kraiken.symbol(), "KRK"); // Confirm that the TwabController address is correctly set (address _lm, address _sp) = kraiken.peripheryContracts(); assertEq(_lm, liquidityManager); assertEq(_sp, stakingPool); } function testMintWithEmptyStakingPool() public { uint256 initialSupply = kraiken.totalSupply(); uint256 mintAmount = 1000 * 1e18; // 1000 HARB tokens vm.prank(address(liquidityManager)); kraiken.mint(mintAmount); // Check if the total supply has increased correctly assertEq(kraiken.totalSupply(), initialSupply + mintAmount); // Check if the staking pool balance is still 0, as before assertEq(kraiken.balanceOf(stakingPool), 0); } function testBurnWithEmptyStakingPool() public { uint256 initialSupply = kraiken.totalSupply(); uint256 burnAmount = 500 * 1e18; // 500 HARB tokens // First, mint some tokens to burn vm.prank(address(liquidityManager)); kraiken.mint(burnAmount); vm.prank(address(liquidityManager)); kraiken.burn(burnAmount); // Check if the total supply has decreased correctly assertEq(kraiken.totalSupply(), initialSupply); // Check if the staking pool balance has decreased correctly assertEq(kraiken.balanceOf(stakingPool), 0); } function testMintImpactOnSimulatedStaking() public { uint256 initialStakingPoolBalance = kraiken.balanceOf(stakingPool); uint256 mintAmount = 1000 * 1e18; // 1000 HARB tokens // Ensure the test contract has enough tokens to simulate staking vm.prank(address(liquidityManager)); kraiken.mint(mintAmount); vm.prank(address(liquidityManager)); kraiken.transfer(address(this), mintAmount); // Simulate staking of the minted amount simulateStake(mintAmount); // Check balances after simulated staking assertEq(kraiken.balanceOf(stakingPool), initialStakingPoolBalance + mintAmount); } function testUnstakeImpactOnTotalSupply() public { uint256 stakeAmount = 500 * 1e18; // 500 HARB tokens // Ensure the test contract has enough tokens to simulate staking vm.prank(address(liquidityManager)); kraiken.mint(stakeAmount); vm.prank(address(liquidityManager)); kraiken.transfer(address(this), stakeAmount); uint256 initialTotalSupply = kraiken.totalSupply(); // Simulate staking and then unstaking simulateStake(stakeAmount); simulateUnstake(stakeAmount); // Check total supply remains unchanged after unstake assertEq(kraiken.totalSupply(), initialTotalSupply); } // Fuzz test for mint function with varying stake amounts function testMintWithStake(uint8 _stakePercentage, uint256 mintAmount) public { uint256 initialAmount = 500 * 1e18; // Ensure the test contract has enough tokens to simulate staking vm.prank(address(liquidityManager)); kraiken.mint(initialAmount); vm.prank(address(liquidityManager)); kraiken.transfer(address(this), initialAmount); // Limit fuzzing input to 0% - 20% uint8 effectiveStakePercentage = _stakePercentage % 21; uint256 stakeAmount = (initialAmount * effectiveStakePercentage) / 100; simulateStake(stakeAmount); uint256 initialTotalSupply = kraiken.totalSupply(); uint256 initialStakingPoolBalance = kraiken.balanceOf(stakingPool); mintAmount = bound(mintAmount, 1, 500 * 1e18); uint256 expectedNewStake = initialStakingPoolBalance * mintAmount / (initialTotalSupply - initialStakingPoolBalance); // Expect Transfer events vm.expectEmit(true, true, true, true, address(kraiken)); emit IERC20.Transfer(address(0), address(liquidityManager), mintAmount); vm.prank(address(liquidityManager)); kraiken.mint(mintAmount); uint256 expectedStakingPoolBalance = initialStakingPoolBalance + expectedNewStake; uint256 expectedTotalSupply = initialTotalSupply + mintAmount + expectedNewStake; assertEq(kraiken.balanceOf(stakingPool), expectedStakingPoolBalance, "Staking pool balance did not adjust correctly after mint."); assertEq(kraiken.totalSupply(), expectedTotalSupply, "Total supply did not match expected after mint."); } // Fuzz test for burn function with varying stake amounts function testBurnWithStake(uint8 _stakePercentage, uint256 burnAmount) public { uint256 mintAmount = 500 * 1e18; // Ensure the test contract has enough tokens to simulate staking vm.prank(address(liquidityManager)); kraiken.mint(mintAmount); // Limit fuzzing input to 0% - 20% uint8 effectiveStakePercentage = _stakePercentage % 21; uint256 stakeAmount = (mintAmount * effectiveStakePercentage) / 100; vm.prank(address(liquidityManager)); kraiken.transfer(address(this), stakeAmount); simulateStake(stakeAmount); burnAmount = bound(burnAmount, 0, 200 * 1e18); uint256 initialTotalSupply = kraiken.totalSupply(); uint256 initialStakingPoolBalance = kraiken.balanceOf(stakingPool); uint256 expectedExcessStake = initialStakingPoolBalance * burnAmount / (initialTotalSupply - initialStakingPoolBalance); vm.prank(address(liquidityManager)); kraiken.burn(burnAmount); uint256 expectedStakingPoolBalance = initialStakingPoolBalance - expectedExcessStake; uint256 expectedTotalSupply = initialTotalSupply - burnAmount - expectedExcessStake; assertEq(kraiken.balanceOf(stakingPool), expectedStakingPoolBalance, "Staking pool balance did not adjust correctly after burn."); assertEq(kraiken.totalSupply(), expectedTotalSupply, "Total supply did not match expected after burn."); } }