Skip to content

Commit

Permalink
tests done
Browse files Browse the repository at this point in the history
  • Loading branch information
gab0071 committed Aug 21, 2024
1 parent 68cbd65 commit 5c27a4a
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 76 deletions.
10 changes: 10 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,13 @@ remappings = [
]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options

[fmt]
bracket_spacing = true
int_types = "long"
line_length = 132
multiline_func_header = "all"
number_underscore = "preserve"
quote_style = "double"
tab_width = 4
wrap_comments = true
47 changes: 29 additions & 18 deletions src/Main.sol
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
// SPDX-LINCENSE-Identifier: MIT
pragma solidity ^0.8.20;
pragma experimental ABIEncoderV2;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {StakingToken} from "./StakingToken.sol";
import {RewardToken} from "./RewardToken.sol";

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { StakingToken } from "./StakingToken.sol";
import { RewardToken } from "./RewardToken.sol";

/// @title Main Contract
/// @author Gabi Maverick from catellatech
/// @notice This is the main contract that manages the staking and unstaking also the rewardTokensDistribution logic
/// @dev This contract extends the Ownable contract from OpenZeppelin
/// @dev This contract is used just as a educational purpose dont use it in production

contract Main is Ownable {
// custom errors
error Main_amountMustBeGreaterThanZero();
error Main_stakingBalanceMustBeGreaterThanZero();

event SuccessfulStaked(address indexed user, uint256 amount);
event SuccessfulUnstake(address indexed user, uint256 amount);

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////
Variables
/////////////////////////////////////////////////////////////////////////////////////////////////////////*/
StakingToken public immutable i_stakingToken;
RewardToken public immutable i_rewardToken;

address[] public stakers;

struct StakeInfo {
uint256 StakedBalance;
bool hasStaked;
Expand All @@ -34,11 +25,30 @@ contract Main is Ownable {

mapping(address user => StakeInfo) public Stakes;

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////
Events
/////////////////////////////////////////////////////////////////////////////////////////////////////////*/
event SuccessfulStaked(address indexed user, uint256 amount);
event SuccessfulUnstake(address indexed user, uint256 amount);

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////
Custom Errors
/////////////////////////////////////////////////////////////////////////////////////////////////////////*/
error Main_amountMustBeGreaterThanZero();
error Main_stakingBalanceMustBeGreaterThanZero();

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////
Constructor
/////////////////////////////////////////////////////////////////////////////////////////////////////////*/
constructor(StakingToken _stakingToken, RewardToken _rewardToken) Ownable(msg.sender) {
i_stakingToken = _stakingToken;
i_rewardToken = _rewardToken;
}

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////
Public Functions
/////////////////////////////////////////////////////////////////////////////////////////////////////////*/

/// @notice This function is used to stake (STK) tokens
/// @param _amountToStake amount of STK tokens to stake
/// @dev If the amount to stake is good lets transfer StakingToken (STK) to the contract
Expand Down Expand Up @@ -87,8 +97,9 @@ contract Main is Ownable {

/// @notice This function is used to distribute the reward token (RWT) to the users who currently staking in the platform
/// @dev We iterate through the stakers array and transfer the reward token (RWT) to each user
/// 🚨 this function is for educational purpuse but it can be better tbh, this can maybe in production can cause DoS
/// if a lot of users stake and the array is big enough to cause DoS, if u want to apply this in production consider Consider limiting the number of iterations in for-loops that make external calls
//**🚨 this function is for educational purpuse but it can be better tbh, this can maybe in production can cause DoSif a lot
// of users stake and the array is big enough to cause DoS, if u want to apply this in production consider Consider limiting the
// number of iterations in for-loops that make external calls*/
function rewardTokensDistribution() public onlyOwner {
uint256 length = stakers.length;
for (uint256 i; i < length; i++) {
Expand Down
2 changes: 1 addition & 1 deletion src/RewardToken.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-Lincese-Identifier: MIT
pragma solidity ^0.8.20;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/// @title RewardToken
/// @author Gabi Maverick from catellatech
Expand Down
2 changes: 1 addition & 1 deletion src/StakingToken.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-Lincese-Identifier: MIT
pragma solidity ^0.8.20;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/// @title StakingToken
/// @author Gabi Maverick from catellatech
Expand Down
96 changes: 47 additions & 49 deletions test/MainTest.t.sol
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
// SPDX-Lincese-Identifier: MIT
pragma solidity ^0.8.20;

import {StakingToken} from "../src/StakingToken.sol";
import {RewardToken} from "../src/RewardToken.sol";
import {Main} from "../src/Main.sol";
import {Test, console} from "forge-std/Test.sol";

/**
1. So i need to deploy the staking contract and fund with some STK tokens to 2 users
2. So the main token deploy reward token to use the rewardTokensDistribution function
*/
import { StakingToken } from "../src/StakingToken.sol";
import { RewardToken } from "../src/RewardToken.sol";
import { Main } from "../src/Main.sol";
import { Test } from "forge-std/Test.sol";

contract MainTest is Test {
// custom errors
error Main_amountMustBeGreaterThanZero();
error Main_stakingBalanceMustBeGreaterThanZero();

event SuccessfulStaked(address indexed user, uint256 amount);
event SuccessfulUnstake(address indexed user, uint256 amount);

// call it all the contract that i need
StakingToken public stakingToken;
RewardToken public rewardToken;
Main public main;
Main public mainContract;

address public user1 = makeAddr("user1");
address public user2 = makeAddr("user2");
address public user3 = makeAddr("user3");
Expand All @@ -34,33 +28,37 @@ contract MainTest is Test {
function setUp() public {
stakingToken = new StakingToken(stakingTokenInitialSupply);
rewardToken = new RewardToken(rewardTokenInitialSupply);
main = new Main(stakingToken, rewardToken);
mainContract = new Main(stakingToken, rewardToken);

vm.prank(address(this));
stakingToken.transfer(user1, 1_000);
stakingToken.transfer(user2, 5_000);
}

function testMainContractOwner() public view {
assertEq(main.owner(), address(this));
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////
CHECK OWNER TEST
/////////////////////////////////////////////////////////////////////////////////////////////////////////*/
function testmainContractContractOwner() public view {
assertEq(mainContract.owner(), address(this));
}

// Test the staking function of the Main contract
// user1 and user2 stake some STK tokens correctly
function testStakingToken() public {
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////
STAKING TOKEN TEST
/////////////////////////////////////////////////////////////////////////////////////////////////////////*/
function testStakingToken() public {
vm.startPrank(user1);
uint256 amountToStakeUser1 = 555;
// Let's approve the Main contract to stake the STK tokens
stakingToken.approve(address(main), amountToStakeUser1);
// Let's approve the mainContract contract to stake the STK tokens
stakingToken.approve(address(mainContract), amountToStakeUser1);
// Let's stake the STK tokens
main.stake(amountToStakeUser1);
mainContract.stake(amountToStakeUser1);
vm.stopPrank();
// Test that the Main contract receives the STK tokens
assertEq(stakingToken.balanceOf(address(main)), amountToStakeUser1);

// Test that the mainContract contract receives the STK tokens
assertEq(stakingToken.balanceOf(address(mainContract)), amountToStakeUser1);

// Destructure the returned struct into individual variables for user1
(uint256 stakedBalance, bool hasStaked, bool isStaking) = main.Stakes(user1);
(uint256 stakedBalance, bool hasStaked, bool isStaking) = mainContract.Stakes(user1);
// Test that the values of the Stakes struct are updated correctly user1
assertEq(stakedBalance, amountToStakeUser1);
assertEq(hasStaked, true);
Expand All @@ -69,32 +67,34 @@ contract MainTest is Test {
// Let's make user2 stake some STK tokens
vm.startPrank(user2);
uint256 amountToStakeUser2 = 4_000;
stakingToken.approve(address(main), amountToStakeUser2);
main.stake(amountToStakeUser2);
stakingToken.approve(address(mainContract), amountToStakeUser2);
mainContract.stake(amountToStakeUser2);
vm.stopPrank();


// check the new balance of STK tokens in the mainContract
uint256 newStakedBalance = amountToStakeUser1 + amountToStakeUser2;
assertEq(stakingToken.balanceOf(address(main)), newStakedBalance);
assertEq(stakingToken.balanceOf(address(mainContract)), newStakedBalance);

// verify that user2 was succefully added into the stakers array
address staker = main.stakers(1);
address staker = mainContract.stakers(1);
assertEq(staker, user2, "Staker number 2 was not added to the array.");

}

function testStakingFailure() public {
// check that user3 can not stake with 0 amount
vm.startPrank(user3);
uint256 amountToStakeUser3 = 0;
stakingToken.approve(address(main), amountToStakeUser3);
stakingToken.approve(address(mainContract), amountToStakeUser3);
vm.expectRevert(Main_amountMustBeGreaterThanZero.selector);
main.stake(amountToStakeUser3);
mainContract.stake(amountToStakeUser3);
vm.stopPrank();
}

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////
UNSTAKING TEST
/////////////////////////////////////////////////////////////////////////////////////////////////////////*/

function testUnstake() public {
uint256 amountToUnstake = 555;
// Let's call the function where users stake tokens
// Let's call the function where users stake tokens
testStakingToken();

// Let's emit the event where the user unstakes
Expand All @@ -103,16 +103,19 @@ contract MainTest is Test {

// User1 unstake the tokens
vm.startPrank(user1);
main.unstake();
mainContract.unstake();
vm.stopPrank();

// Let's see if the user3 can unstake
vm.startPrank(user3);
vm.expectRevert(Main_stakingBalanceMustBeGreaterThanZero.selector);
main.unstake();
mainContract.unstake();
vm.stopPrank();
}

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////
DISTRIBUTION REWARD TOKENS TEST
/////////////////////////////////////////////////////////////////////////////////////////////////////////*/
function testRewardTokensDistribution() public {
// Let's create the enviroment where exist stakers
testStakingToken();
Expand All @@ -123,18 +126,13 @@ contract MainTest is Test {
// Now lets make the distribution of the reward tokens to the stakers (In this case 1:1)
// So if user1 staked 555 STK tokens he is going to receive 555 RWT tokens
vm.startPrank(address(this));
// We are going to send full supply to the Main contract to distribute the reward tokens to the stakers
rewardToken.transfer(address(main), rewardTokenInitialSupply);
main.rewardTokensDistribution();
// We are going to send full supply to the mainContract contract to distribute the reward tokens to the stakers
rewardToken.transfer(address(mainContract), rewardTokenInitialSupply);
mainContract.rewardTokensDistribution();
vm.stopPrank();

// Let's check if the reward token balance is correct
assertEq(rewardToken.balanceOf(user1), amountUser1Staked);
assertEq(rewardToken.balanceOf(user2), amountUser2Staked);

}




}
}
7 changes: 3 additions & 4 deletions test/RewardTokenTest.t.sol
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
// SPDX-Lincese-Identifier: MIT
pragma solidity ^0.8.20;

import {RewardToken} from "../src/RewardToken.sol";
import {Test} from "forge-std/Test.sol";
import { RewardToken } from "../src/RewardToken.sol";
import { Test } from "forge-std/Test.sol";

contract RewardTokenTest is Test {
RewardToken rewardToken;
uint256 initialSupply = 8_000_000;


function setUp() public {
rewardToken = new RewardToken(initialSupply);
}

function testRewardTokenSupply() public view {
assertEq(rewardToken.totalSupply(), initialSupply);
}
}
}
6 changes: 3 additions & 3 deletions test/StakingTokenTest.t.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-Lincese-Identifier: MIT
pragma solidity ^0.8.20;

import {StakingToken} from "../src/StakingToken.sol";
import {Test} from "forge-std/Test.sol";
import { StakingToken } from "../src/StakingToken.sol";
import { Test } from "forge-std/Test.sol";

contract StakingTokenTest is Test {
StakingToken stakingToken;
Expand All @@ -15,4 +15,4 @@ contract StakingTokenTest is Test {
function testSupply() public view {
assertEq(stakingToken.totalSupply(), initialStakingSupply);
}
}
}

0 comments on commit 5c27a4a

Please sign in to comment.