Skip to content

Commit

Permalink
Add IDOMaster, Fix Stake by audit
Browse files Browse the repository at this point in the history
  • Loading branch information
Yaroslav committed Feb 25, 2021
1 parent 75ab2ef commit 2e4aad9
Show file tree
Hide file tree
Showing 17 changed files with 12,251 additions and 38 deletions.
1,193 changes: 1,193 additions & 0 deletions StakeMaster/build/contracts/ERC20Decimal.json

Large diffs are not rendered by default.

10,053 changes: 10,053 additions & 0 deletions StakeMaster/build/contracts/TokenVesting.json

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions StakeMaster/contracts/ERC20Decimal.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract ERC20Decimal is ERC20 {
constructor( uint256 totalSupply,
string memory name,
string memory symbol,
uint8 decimal) public ERC20(name, symbol) {
_setupDecimals(decimal);
_mint(msg.sender, totalSupply);
}
}
4 changes: 2 additions & 2 deletions StakeMaster/contracts/FeeToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ contract FeeToken is Context, AccessControl, ERC20Burnable {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

/**
* @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the
* @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` to the
* account that deploys the contract.
*
* See {ERC20-constructor}.
Expand All @@ -37,7 +37,7 @@ contract FeeToken is Context, AccessControl, ERC20Burnable {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());

_setupRole(MINTER_ROLE, _msgSender());
_mint(msg.sender, totalSupply);
_mint(_msgSender(), totalSupply);
}

/**
Expand Down
137 changes: 137 additions & 0 deletions StakeMaster/contracts/IDOMaster.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
pragma solidity 0.6.12;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
import "./IDOPool.sol";

contract IDOMaster is Ownable {
using SafeMath for uint256;
using SafeERC20 for ERC20Burnable;
using SafeERC20 for ERC20;

ERC20Burnable public feeToken;
address public feeWallet;
uint256 public feeAmount;
uint256 public burnPercent;
uint256 public divider;

event IDOCreated(address owner, address idoPool,
uint256 tokenPrice,
address rewardToken,
uint256 startTimestamp,
uint256 finishTimestamp,
uint256 startClaimTimestamp,
uint256 minEthPayment,
uint256 maxEthPayment,
uint256 maxDistributedTokenAmount);

event TokenFeeUpdated(address newFeeToken);
event FeeAmountUpdated(uint256 newFeeAmount);
event BurnPercentUpdated(uint256 newBurnPercent, uint256 divider);
event FeeWalletUpdated(address newFeeWallet);

constructor(
ERC20Burnable _feeToken,
address _feeWallet,
uint256 _feeAmount,
uint256 _burnPercent
) public {
feeToken = _feeToken;
feeAmount = _feeAmount;
feeWallet = _feeWallet;
burnPercent = _burnPercent;
divider = 100;
}

function setFeeToken(address _newFeeToken) external onlyOwner {
require(isContract(_newFeeToken), "New address is not a token");
feeToken = ERC20Burnable(_newFeeToken);

emit TokenFeeUpdated(_newFeeToken);
}

function setFeeAmount(uint256 _newFeeAmount) external onlyOwner {
feeAmount = _newFeeAmount;

emit FeeAmountUpdated(_newFeeAmount);
}

function setFeeWallet(address _newFeeWallet) external onlyOwner {
feeWallet = _newFeeWallet;

emit FeeWalletUpdated(_newFeeWallet);
}

function setBurnPercent(uint256 _newBurnPercent, uint256 _newDivider)
external
onlyOwner
{
require(_newBurnPercent <= _newDivider, "Burn percent must be less than divider");
burnPercent = _newBurnPercent;
divider = _newDivider;

emit BurnPercentUpdated(_newBurnPercent, _newDivider);
}

function createIDO(
uint256 _tokenPrice,
ERC20 _rewardToken,
uint256 _startTimestamp,
uint256 _finishTimestamp,
uint256 _startClaimTimestamp,
uint256 _minEthPayment,
uint256 _maxEthPayment,
uint256 _maxDistributedTokenAmount
) external {
if(feeAmount > 0){
uint256 burnAmount = feeAmount.mul(burnPercent).div(divider);

feeToken.safeTransferFrom(
msg.sender,
feeWallet,
feeAmount.sub(burnAmount)
);
feeToken.safeTransferFrom(msg.sender, address(this), burnAmount);
feeToken.burn(burnAmount);
}
IDOPool idoPool =
new IDOPool(
_tokenPrice,
_rewardToken,
_startTimestamp,
_finishTimestamp,
_startClaimTimestamp,
_minEthPayment,
_maxEthPayment,
_maxDistributedTokenAmount
);
idoPool.transferOwnership(msg.sender);

_rewardToken.safeTransferFrom(
msg.sender,
address(idoPool),
_maxDistributedTokenAmount
);

emit IDOCreated(msg.sender,
address(idoPool),
_tokenPrice,
address(_rewardToken),
_startTimestamp,
_finishTimestamp,
_startClaimTimestamp,
_minEthPayment,
_maxEthPayment,
_maxDistributedTokenAmount);
}

function isContract(address _addr) private view returns (bool) {
uint32 size;
assembly {
size := extcodesize(_addr)
}
return (size > 0);
}
}
143 changes: 143 additions & 0 deletions StakeMaster/contracts/IDOPool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
pragma solidity 0.6.12;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract IDOPool is Ownable, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for ERC20;

uint256 public tokenPrice;
ERC20 public rewardToken;
uint256 public decimals;
uint256 public startTimestamp;
uint256 public finishTimestamp;
uint256 public startClaimTimestamp;
uint256 public minEthPayment;
uint256 public maxEthPayment;
uint256 public maxDistributedTokenAmount;
uint256 public tokensForDistribution;
uint256 public distributedTokens;

struct UserInfo {
uint debt;
uint total;
uint totalInvestedETH;
}

mapping(address => UserInfo) public userInfo;

event TokensDebt(
address indexed holder,
uint256 ethAmount,
uint256 tokenAmount
);

event TokensWithdrawn(address indexed holder, uint256 amount);

constructor(
uint256 _tokenPrice,
ERC20 _rewardToken,
uint256 _startTimestamp,
uint256 _finishTimestamp,
uint256 _startClaimTimestamp,
uint256 _minEthPayment,
uint256 _maxEthPayment,
uint256 _maxDistributedTokenAmount
) public {
tokenPrice = _tokenPrice;
rewardToken = _rewardToken;
decimals = rewardToken.decimals();

require(
_startTimestamp < _finishTimestamp,
"Start timestamp must be less than finish timestamp"
);
require(
_finishTimestamp > now,
"Finish timestamp must be more than current block"
);
startTimestamp = _startTimestamp;
finishTimestamp = _finishTimestamp;
startClaimTimestamp = _startClaimTimestamp;
minEthPayment = _minEthPayment;
maxEthPayment = _maxEthPayment;
maxDistributedTokenAmount = _maxDistributedTokenAmount;
}

function pay() payable external {
require(msg.value >= minEthPayment, "Less then min amount");
require(msg.value <= maxEthPayment, "More then max amount");
require(now >= startTimestamp, "Not started");
require(now < finishTimestamp, "Ended");

uint256 tokenAmount = getTokenAmount(msg.value);
require(tokensForDistribution.add(tokenAmount) <= maxDistributedTokenAmount, "Overfilled");

UserInfo storage user = userInfo[msg.sender];
require(user.totalInvestedETH.add(msg.value) <= maxEthPayment, "More then max amount");

tokensForDistribution = tokensForDistribution.add(tokenAmount);
user.totalInvestedETH = user.totalInvestedETH.add(msg.value);
user.total = user.total.add(tokenAmount);
user.debt = user.debt.add(tokenAmount);

emit TokensDebt(msg.sender, msg.value, tokenAmount);
}

function getTokenAmount(uint256 ethAmount)
internal
view
returns (uint256)
{
return ethAmount.mul(10**decimals).div(tokenPrice);
}


/// @dev Allows to claim tokens for the specific user.
/// @param _user Token receiver.
function claimFor(address _user) external {
proccessClaim(_user);
}

/// @dev Allows to claim tokens for themselves.
function claim() external {
proccessClaim(msg.sender);
}

/// @dev Proccess the claim.
/// @param _receiver Token receiver.
function proccessClaim(
address _receiver
) internal nonReentrant{
require(now > startClaimTimestamp, "Distribution not started");
UserInfo storage user = userInfo[_receiver];
uint256 _amount = user.debt;
if (_amount > 0) {
user.debt = 0;
distributedTokens = distributedTokens.add(_amount);
rewardToken.safeTransfer(_receiver, _amount);
emit TokensWithdrawn(_receiver,_amount);
}
}

function withdrawETH(uint256 amount) external onlyOwner {
// This forwards all available gas. Be sure to check the return value!
(bool success, ) = msg.sender.call.value(amount)("");
require(success, "Transfer failed.");
}

//function safeTransferETH(address to, uint value) internal {
// (bool success,) = to.call{value:value}(new bytes(0));
// require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
//}

function withdrawNotSoldTokens() external onlyOwner {
require(now > finishTimestamp, "Withdraw allowed after stop accept ETH");
uint256 balance = rewardToken.balanceOf(address(this));
rewardToken.safeTransfer(msg.sender, balance.add(distributedTokens).sub(tokensForDistribution));
}
}
20 changes: 12 additions & 8 deletions StakeMaster/contracts/StakeMaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ contract StakeMaster is Ownable {
external
onlyOwner
{
require(_newBurnPercent <= _newDivider, "Burn percent must be less than divider");
burnPercent = _newBurnPercent;
divider = _newDivider;

Expand All @@ -72,15 +73,18 @@ contract StakeMaster is Ownable {
uint256 _finishBlock,
uint256 _poolTokenAmount
) external {
uint256 burnAmount = feeAmount.mul(burnPercent).div(divider);

feeToken.safeTransferFrom(
msg.sender,
feeWallet,
feeAmount.sub(burnAmount)
);
feeToken.safeTransferFrom(msg.sender, address(this), burnAmount);
feeToken.burn(burnAmount);
if(feeAmount > 0) {
uint256 burnAmount = feeAmount.mul(burnPercent).div(divider);

feeToken.safeTransferFrom(
msg.sender,
feeWallet,
feeAmount.sub(burnAmount)
);
feeToken.safeTransferFrom(msg.sender, address(this), burnAmount);
feeToken.burn(burnAmount);
}

StakingPool stakingPool =
new StakingPool(
Expand Down
5 changes: 4 additions & 1 deletion StakeMaster/contracts/StakingPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ contract StakingPool is Ownable, ReentrancyGuard {
view
returns (uint256)
{
if (_from >= _to) {
return 0;
}
if (_to <= finishBlock) {
return _to.sub(_from);
} else if (_from >= finishBlock) {
Expand Down Expand Up @@ -116,7 +119,7 @@ contract StakingPool is Ownable, ReentrancyGuard {
if (user.amount > 0) {
pending = transferPendingReward(user);
}
else{
else if (_amountToStake > 0){
participants +=1;
}

Expand Down
Loading

0 comments on commit 2e4aad9

Please sign in to comment.