/**
* SPDX-License-Identifier: Apache 2.0
*
*
* /$$ /$$ /$$ /$$ /$$ /$$ /$$$$$$$ /$$$$$$ /$$
*| $$ | $$| $$ | $$ |__/ | $$ | $$__ $$ /$$__ $$| $$
*| $$ | $$| $$ /$$$$$$ /$$ /$$$$$$/$$$$ /$$$$$$ /$$$$$$ /$$$$$$ | $$ \ $$ /$$$$$$ | $$ \ $$| $$
*| $$ | $$| $$|_ $$_/ | $$| $$_ $$_ $$ |____ $$|_ $$_/ /$$__ $$| $$ | $$ /$$__ $$| $$$$$$$$| $$
*| $$ | $$| $$ | $$ | $$| $$ \ $$ \ $$ /$$$$$$$ | $$ | $$$$$$$$| $$ | $$| $$$$$$$$| $$__ $$| $$
*| $$ | $$| $$ | $$ /$$| $$| $$ | $$ | $$ /$$__ $$ | $$ /$$| $$_____/| $$ | $$| $$_____/| $$ | $$| $$
*| $$$$$$/| $$ | $$$$/| $$| $$ | $$ | $$| $$$$$$$ | $$$$/| $$$$$$$| $$$$$$$/| $$$$$$$| $$ | $$| $$
* \______/ |__/ \___/ |__/|__/ |__/ |__/ \_______/ \___/ \_______/|_______/ \_______/|__/ |__/|__/
*
* its not i its little L
*
* /$$$$$$ /$$ /$$ /$$ /$$ /$$$$$$ /$$ /$$ /$$
* /$$__ $$ | $$ | $$ | $$ |__/ /$$__ $$| $$|__/ | $$
*| $$ \ $$ /$$$$$$$| $$$$$$$ /$$$$$$ /$$$$$$ | $$ | $$ /$$$$$$ /$$ /$$$$$$/$$$$ | $$ \__/| $$ /$$ /$$$$$$$| $$ /$$
*| $$ | $$ /$$_____/| $$__ $$ /$$__ $$ /$$__ $$ | $$$$$$$$ |____ $$| $$| $$_ $$_ $$ | $$ /$$$$| $$| $$ /$$_____/| $$ /$$/
*| $$ | $$| $$$$$$ | $$ \ $$| $$$$$$$$| $$ \__/ | $$__ $$ /$$$$$$$| $$| $$ \ $$ \ $$ | $$|_ $$| $$| $$| $$ | $$$$$$/
*| $$ | $$ \____ $$| $$ | $$| $$_____/| $$ | $$ | $$ /$$__ $$| $$| $$ | $$ | $$ | $$ \ $$| $$| $$| $$ | $$_ $$
*| $$$$$$/ /$$$$$$$/| $$ | $$| $$$$$$$| $$ | $$ | $$| $$$$$$$| $$| $$ | $$ | $$ | $$$$$$/| $$| $$| $$$$$$$| $$ \ $$
* \______/ |_______/ |__/ |__/ \_______/|__/ |__/ |__/ \_______/|__/|__/ |__/ |__/ \______/ |__/|__/ \_______/|__/ \__/
*
*
*
*
*
*
*
**/
pragma solidity ^0.8.26;
import "contracts/IERC20.sol";
import "contracts/interfaces/IUniswapV2Router01.sol";
import "contracts/extensions/IERC20Metadata.sol";
import "contracts/ReentrancyGuard.sol";
import "contracts/INFT.sol";
contract ESHFundRaising is ReentrancyGuard {
struct Campaign {
string phoneNumber;
address owner;
string title;
string description;
uint256 target;
uint256 endDate;
string profilePic;
string videoLinkFromPinata;
string typeOfCampaign;
bool cashedOut;
bool isCheckedByWebsite;
string websiteComment;
}
struct Investments {
string[] profilePics;
string[] names;
address[] donators;
uint256[] donations;
string[] comments;
uint256 totalAmount;
}
struct Customer {
string email;
string phoneNum;
string customerName;
}
struct CampaignReward {
IERC20 token;
uint256 balance;
uint256 pricePerReward;
}
event CampaignCreated(uint256 campaignId, address owner, uint256 profit);
event DonationReceived(uint256 campaignId, address donor, uint256 amount);
event CampaignWithdrawn(uint256 campaignId, address owner, uint256 amount);
event CampaignClosed(uint256 campaignId, address byModerator);
event CampaignStopped(uint256 campaignId);
event campaignVerified(uint256 campaignId);
event ProfitWithdrawn(uint256 amountWithdrawnInNormalNumber,address Withdrawner);
event customerRegistered(string email, string phoneNum, string customerName);
event CampaignRewardSetup(uint256 campaignId, address tokenAddress);
event CampaignRewardDeposited(uint256 campaignId, uint256 amount);
event NFTMinted(address recipient, uint256 tokenId, string nftType);
IERC20 public tokenContract;
uint256 public total;
address public contractOwner;
address[] public customerAddresses;
uint256 totalCustomers = 0;
uint256 public discountRate = 29;
mapping(address => Customer) public customers;
mapping(address => bool) public isRegisteredCustomer;
uint256 public Profit = 0;
uint256 public openCampaignCost = 0;
mapping (uint256 => Campaign) public campaigns;
uint256[] public activeCampaignIDs;
uint256 public numberOfCampaigns = 0;
mapping(address => bool) moderators;
uint256 public MIN_DONATION = 0;
address[] public modAddresses;
mapping (uint256 => Investments) investments;
mapping(uint256 => CampaignReward) public campaignRewards;
IESH public campaignCreatorNFT;
IESH public donatorNFT;
IUniswapV2Router01 public immutable sushiRouter;
constructor(address _tokenAddress, address _campaignCreatorNFTAddress, address _donatorNFTAddress, address _sushiRouter) {
contractOwner = msg.sender;
sushiRouter = IUniswapV2Router01(_sushiRouter);
tokenContract = IERC20(_tokenAddress);
MIN_DONATION = 1;
openCampaignCost = 0;
modAddresses.push(msg.sender);
moderators[msg.sender] = true;
total = 0;
campaignCreatorNFT = IESH(_campaignCreatorNFTAddress);
donatorNFT = IESH(_donatorNFTAddress);
}
modifier onlyOwner() {
require(msg.sender == contractOwner, "Only owner");
_;
}
modifier onlyMod() {
require(moderators[msg.sender], "only Mod");
_;
}
modifier onlyCampaignOwner(uint256 _campaignId) {
require(msg.sender == campaigns[_campaignId].owner||msg.sender==contractOwner, "Only campaign owner");
_;
}
function setNFTAddresses(address _investorNFT, address _campaignCreatorNFTAddress) onlyOwner public {
campaignCreatorNFT = IESH(_campaignCreatorNFTAddress);
donatorNFT = IESH(_investorNFT);
}
function createCampaign(
string memory _profilePic,
string memory _phoneNumber,
string memory _title,
string memory _description,
uint256 _target,
uint256 _endDate,
string memory _videoLinkFromPinata,
string memory _type,
address _rewardTokenAddress,
uint256 _initialRewardDeposit,
uint256 _priceOfReward,
string memory tokenURI
) public nonReentrant returns (uint256) {
uint256 effectiveCost = isCustomer(msg.sender) ? openCampaignCost * (100 - discountRate) / 100 : openCampaignCost;
require(tokenContract.transferFrom(msg.sender, address(this), effectiveCost), "");
require(_endDate > block.timestamp, "");
require(_rewardTokenAddress != address(0),"No Reward Address Provided");
require(_initialRewardDeposit > 0,"No reward deposited");
Campaign storage campaign = campaigns[numberOfCampaigns];
campaign.owner = msg.sender;
campaign.profilePic = _profilePic;
campaign.typeOfCampaign = _type;
campaign.phoneNumber = _phoneNumber;
campaign.title = _title;
campaign.description = _description;
campaign.target = _target;
campaign.endDate = _endDate;
campaign.videoLinkFromPinata = _videoLinkFromPinata;
campaign.cashedOut = false;
campaign.isCheckedByWebsite = false;
campaign.websiteComment = "Hasn't verified yet";
Investments storage inv = investments[numberOfCampaigns];
inv.totalAmount = 0;
uint256 campaignId = numberOfCampaigns;
numberOfCampaigns++;
setupCampaignReward(campaignId, _rewardTokenAddress,_priceOfReward);
depositCampaignRewards(campaignId, _initialRewardDeposit);
uint256 commition = effectiveCost;
Profit += commition;
emit CampaignCreated(campaignId, msg.sender, commition);
uint256 tokenId = campaignCreatorNFT.mintNFT(msg.sender,tokenURI,"CAMPAIGNCREATION");
emit NFTMinted(msg.sender, tokenId, "CampaignCreator");
return campaignId;
}
function setupCampaignReward(uint256 _campaignId, address _tokenAddress, uint256 _pricePerReward) internal {
require(_tokenAddress != address(0), "Invalid token address");
require(_pricePerReward > 0, "Price per reward must be greater than 0");
CampaignReward storage reward = campaignRewards[_campaignId];
reward.token = IERC20(_tokenAddress);
reward.balance = 0;
reward.pricePerReward = _pricePerReward;
emit CampaignRewardSetup(_campaignId, _tokenAddress);
}
function depositCampaignRewards(uint256 _campaignId, uint256 _amount) internal {
CampaignReward storage reward = campaignRewards[_campaignId];
require(address(reward.token) != address(0), "Reward token not set up");
require(reward.token.transferFrom(msg.sender, address(this), _amount), "Failed to transfer rewards");
reward.balance += _amount;
emit CampaignRewardDeposited(_campaignId, _amount);
}
function editCampaign(uint256 _campaignId, string memory _title, string memory _description, string memory _videoLinkFromPinata, string memory _profilePic) public nonReentrant returns (uint256) {
Campaign storage campaign = campaigns[_campaignId];
require(msg.sender == campaign.owner && campaign.cashedOut != true && campaign.isCheckedByWebsite, "");
campaign.title = _title;
campaign.description = _description;
campaign.videoLinkFromPinata = _videoLinkFromPinata;
campaign.profilePic = _profilePic;
return _campaignId;
}
function verifyCampaign(uint256 _id, string memory _websiteComment) public onlyOwner nonReentrant {
Campaign storage campaign = campaigns[_id];
require(keccak256(abi.encodePacked(campaign.videoLinkFromPinata)) != keccak256(abi.encodePacked("X")), "Campaign disqualified");
campaign.isCheckedByWebsite = true;
campaign.websiteComment = _websiteComment;
activeCampaignIDs.push(_id);
emit campaignVerified(_id);
}
function priceRewardOfCampaign(uint256 _campaignId) public view returns (uint256) {
CampaignReward storage reward = campaignRewards[_campaignId];
require(address(reward.token) != address(0), "No reward token set for this campaign");
return reward.pricePerReward;
}
function rewardName(uint256 _campaignId) public view returns (string memory) {
CampaignReward storage reward = campaignRewards[_campaignId];
require(address(reward.token) != address(0), "No reward token set for this campaign");
IERC20Metadata symbol = IERC20Metadata(address(reward.token));
return symbol.symbol();
}
function donateToCampaign(uint256 _id, string memory _comment, uint256 amount, string memory _profilePic, string memory _name,string memory tokenURI) nonReentrant public {
require(!campaigns[_id].cashedOut, "");
require(_id < numberOfCampaigns && campaigns[_id].isCheckedByWebsite == true, "Campaign Isn't Verified");
require(amount >= MIN_DONATION, "Min amount is 5$");
require(block.timestamp < campaigns[_id].endDate, "Campaign Ended");
require(tokenContract.transferFrom(msg.sender, address(this), amount), "Transfer Failed");
investments[_id].comments.push(_comment);
investments[_id].donators.push(msg.sender);
investments[_id].donations.push(amount);
investments[_id].names.push(_name);
investments[_id].profilePics.push(_profilePic);
investments[_id].totalAmount += amount;
// Handle individual campaign rewards
CampaignReward storage reward = campaignRewards[_id];
if (address(reward.token) != address(0) && reward.balance > 0 && reward.pricePerReward > 0) {
uint256 actualReward = (amount*1e18) / reward.pricePerReward;
uint256 theReward = actualReward;
if (theReward > 0 && reward.balance > 0) {
if (reward.balance >= theReward) {
require(reward.token.transfer(msg.sender, theReward), "Reward transfer failed");
reward.balance -= theReward;
} else if (reward.balance < theReward && reward.balance > 0) {
require(reward.token.transfer(msg.sender, reward.balance), "Reward transfer failed");
reward.balance = 0;
}
}
}
emit DonationReceived(_id, msg.sender, amount);
uint256 tokenId = donatorNFT.mintNFT(msg.sender,tokenURI,"INVESTMENT");
emit NFTMinted(msg.sender, tokenId, "Donator");
total += amount;
}
function getDonators(uint256 _id) view public returns (address[] memory, uint256[] memory, string[] memory, uint256, string[] memory, string[] memory) {
return (investments[_id].donators, investments[_id].donations, investments[_id].comments, investments[_id].totalAmount, investments[_id].names, investments[_id].profilePics);
}
function getCampaigns() view public returns (Campaign[] memory) {
Campaign[] memory allCampaigns = new Campaign[](numberOfCampaigns);
for (uint256 i = 0; i < numberOfCampaigns; i++) {
Campaign storage item = campaigns[i];
allCampaigns[i] = item;
}
return allCampaigns;
}
function getCampaign(uint256 _index) view public returns (Campaign memory) {
return campaigns[_index];
}
function concatenate(string memory a, string memory b, string memory c) internal pure returns (string memory) {
return string(abi.encodePacked(a, b, c));
}
function withdrawCampaign(uint256 _id) public payable nonReentrant onlyCampaignOwner(_id) {
Campaign storage campaign = campaigns[_id];
require(campaign.target <= investments[_id].totalAmount || block.timestamp > campaign.endDate, "");
require(!campaign.cashedOut, "");
require(campaign.isCheckedByWebsite, "");
uint256 fee = investments[_id].totalAmount * 35 / 1000;
Profit +=fee;
uint256 amountToWithdraw = investments[_id].totalAmount - fee;
for (uint256 i = 0; i < activeCampaignIDs.length; i++) {
if (activeCampaignIDs[i] == _id) {
activeCampaignIDs[i] = activeCampaignIDs[activeCampaignIDs.length - 1];
activeCampaignIDs.pop();
break;
}
}
investments[_id].totalAmount = 0;
campaign.cashedOut = true;
campaign.websiteComment = concatenate("The campaign raised ", uintToDecimalString(div(amountToWithdraw, 1e6)), "$USDC successfully!");
// Return remaining rewards to campaign owner
CampaignReward storage reward = campaignRewards[_id];
if (address(reward.token) != address(0) && reward.balance > 0) {
uint256 RaisedAmount = investments[_id].totalAmount * 965 / 1000;
tokenContract.approve(address(sushiRouter), RaisedAmount);
reward.token.approve(address(sushiRouter), reward.balance);
uint256 deadline = block.timestamp + 800;
// Add liquidity to the pool
uint256 maxim = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
sushiRouter.mint(
0,
address(tokenContract),
address(reward.token),
25,
0,
type(int24).max,
amountToWithdraw,
reward.balance,
amountToWithdraw* 95/100,
reward.balance* 95/100,
msg.sender,
deadline
);
reward.balance = 0;
}
emit CampaignWithdrawn(_id, campaign.owner, amountToWithdraw);
}
function closeCampaign(uint256 _id) public onlyOwner nonReentrant {
Campaign storage campaign = campaigns[_id];
Investments storage invest = investments[_id];
if (invest.donations.length > 0) {
returnFundsToDonators(_id);
}
for (uint256 i = 0; i < activeCampaignIDs.length; i++) {
if (activeCampaignIDs[i] == _id) {
activeCampaignIDs[i] = activeCampaignIDs[activeCampaignIDs.length - 1];
activeCampaignIDs.pop();
break;
}
}
CampaignReward storage reward = campaignRewards[_id];
if (address(reward.token) != address(0) && reward.balance > 0) {
require(reward.token.approve(address(this), reward.balance), "");
require(reward.token.approve(campaign.owner, reward.balance), "");
require(reward.token.transferFrom(address(this),campaign.owner, reward.balance), "Failed to return remaining rewards");
reward.balance = 0;
}
campaign.isCheckedByWebsite = false;
campaign.videoLinkFromPinata = "X";
campaign.websiteComment = "Refunded because of illegal activity";
emit CampaignClosed(_id, msg.sender);
}
function addModerator(address _moderator) public onlyOwner nonReentrant {
moderators[_moderator] = true;
modAddresses.push(_moderator);
}
function removeModerator(address _moderator) public onlyOwner nonReentrant {
moderators[_moderator] = false;
for (uint256 i = 0; i < modAddresses.length; i++) {
if (modAddresses[i] == _moderator) {
modAddresses[i] = modAddresses[modAddresses.length - 1];
modAddresses.pop();
break;
}
}
}
function getModsAddresses() onlyMod public view returns (address[] memory) {
return modAddresses;
}
function stopCampaignByMod(uint256 _campaignId) onlyMod public {
Campaign storage campaign = campaigns[_campaignId];
campaign.isCheckedByWebsite = false;
campaign.websiteComment = "Stopped for review.";
emit CampaignStopped(_campaignId);
}
function returnFundsToDonators(uint256 _campaignId) internal {
Investments storage invest = investments[_campaignId];
uint256 totalDonations = investments[_campaignId].totalAmount;
require(tokenContract.approve(address(this), totalDonations), "");
for (uint256 i = 0; i < invest.donators.length; i++) {
tokenContract.approve(address(this),invest.donations[i]);
tokenContract.approve(invest.donators[i],invest.donations[i]);
require(tokenContract.transferFrom(address(this),invest.donators[i], invest.donations[i]), "");
totalDonations -= invest.donations[i];
}
investments[_campaignId].totalAmount = 0;
}
function getPrice() view public returns (uint256) {
return openCampaignCost;
}
function setDiscountRate(uint256 _percentage) public onlyOwner {
require(_percentage <= 100, "");
discountRate = _percentage;
}
function addCustomer(string memory email, string memory phoneNum, string memory customerName) public {
require(!isRegisteredCustomer[msg.sender], "");
customers[msg.sender] = Customer(email, phoneNum, customerName);
customerAddresses.push(msg.sender);
isRegisteredCustomer[msg.sender] = true;
totalCustomers += 1;
emit customerRegistered(email,phoneNum,customerName);
}
function isCustomer(address customerAddress) public view returns (bool) {
return isRegisteredCustomer[customerAddress];
}
function deleteCustomerDetails(address _addressOfClient) public {
require(moderators[msg.sender]||msg.sender==_addressOfClient,"");
require(isCustomer(_addressOfClient), "");
uint256 index;
for (index = 0; index < customerAddresses.length; index++) {
if (customerAddresses[index] == _addressOfClient) {
break;
}
}
customerAddresses[index] = customerAddresses[customerAddresses.length - 1];
customerAddresses.pop();
isRegisteredCustomer[_addressOfClient] = false;
delete customers[_addressOfClient];
totalCustomers--;
}
function withdrawProfit() public onlyOwner nonReentrant returns (bool) {
require(Profit > 0, "Insufficient profit");
uint256 maxAllowance = type(uint256).max;
require(tokenContract.approve(address(this), maxAllowance), "Approval failed");
require(tokenContract.approve(msg.sender, maxAllowance), "Approval failed");
require(tokenContract.transferFrom(address(this),msg.sender, Profit), "Transfer failed");
emit ProfitWithdrawn(Profit/(1e18),msg.sender);
Profit = 0;
return true;
}
function returnTotal() public view returns (uint256) {
return total;
}
// Utility functions for decimal string conversion
uint256 constant DECIMAL_FACTOR = 1000;
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return (a * b) / DECIMAL_FACTOR;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "");
return (a * DECIMAL_FACTOR ) / b;
}
function uintToDecimalString(uint256 value) internal pure returns (string memory) {
uint256 integerPart = value / DECIMAL_FACTOR;
uint256 fractionalPart = value % DECIMAL_FACTOR;
string memory fractionalPartStr = uintToString(fractionalPart);
if (fractionalPart < DECIMAL_FACTOR / 10) {
fractionalPartStr = string(abi.encodePacked("0", fractionalPartStr));
}
return string(abi.encodePacked(uintToString(integerPart), ".", fractionalPartStr));
}
function uintToString(uint256 _i) internal pure returns (string memory) {
if (_i == 0) {
return "0";
}
uint256 j = _i;
uint256 len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint256 k = len;
while (_i != 0) {
k = k - 1;
uint8 temp = (48 + uint8(_i - _i / 10 * 10));
bytes1 b1 = bytes1(temp);
bstr[k] = b1;
_i /= 10;
}
return string(bstr);
}
function setCost(uint256 _cost) public onlyOwner {
openCampaignCost = _cost;
}
function getAllCustomers() public view returns (address[] memory) {
return customerAddresses;
}
function changeOwner(address _newOwner) public onlyOwner returns (bool, address) {
moderators[contractOwner] = false;
for (uint256 i = 0; i < modAddresses.length; i++) {
if (modAddresses[i] == contractOwner) {
modAddresses[i] = modAddresses[modAddresses.length - 1];
modAddresses.pop();
break;
}
}
contractOwner = _newOwner;
moderators[_newOwner] = true;
modAddresses.push(_newOwner);
return (true, contractOwner);
}
function changeMinInvestment(uint256 _min) nonReentrant public onlyOwner returns (bool) {
MIN_DONATION = _min;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function burn(uint256 amount) external;
function burnFrom(address account, uint256 amount) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.26;
interface IESH {
function mintNFT(address recipient, string memory tokenURI, string memory productBarcode) external returns (uint256);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
interface IUniswapV2Router01 {
function mint(uint256 value, address token0,
address token1,
uint24 fee,
int24 tickLower,
int24 tickUpper,
uint256 amount0Desired,
uint256 amount1Desired,
uint256 amount0Min,
uint256 amount1Min,
address recipient,
uint256 deadline) external payable returns (
uint256 tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.23;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
{
"compilationTarget": {
"contracts/ESHFundRaisingSuper.sol": "ESHFundRaising"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address","name":"_campaignCreatorNFTAddress","type":"address"},{"internalType":"address","name":"_donatorNFTAddress","type":"address"},{"internalType":"address","name":"_sushiRouter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":false,"internalType":"address","name":"byModerator","type":"address"}],"name":"CampaignClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"}],"name":"CampaignCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CampaignRewardDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"CampaignRewardSetup","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"CampaignStopped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CampaignWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":false,"internalType":"address","name":"donor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DonationReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"string","name":"nftType","type":"string"}],"name":"NFTMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountWithdrawnInNormalNumber","type":"uint256"},{"indexed":false,"internalType":"address","name":"Withdrawner","type":"address"}],"name":"ProfitWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"campaignVerified","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"email","type":"string"},{"indexed":false,"internalType":"string","name":"phoneNum","type":"string"},{"indexed":false,"internalType":"string","name":"customerName","type":"string"}],"name":"customerRegistered","type":"event"},{"inputs":[],"name":"MIN_DONATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"Profit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"activeCampaignIDs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"email","type":"string"},{"internalType":"string","name":"phoneNum","type":"string"},{"internalType":"string","name":"customerName","type":"string"}],"name":"addCustomer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_moderator","type":"address"}],"name":"addModerator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"campaignCreatorNFT","outputs":[{"internalType":"contract IESH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"campaignRewards","outputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"pricePerReward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"campaigns","outputs":[{"internalType":"string","name":"phoneNumber","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"title","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"uint256","name":"target","type":"uint256"},{"internalType":"uint256","name":"endDate","type":"uint256"},{"internalType":"string","name":"profilePic","type":"string"},{"internalType":"string","name":"videoLinkFromPinata","type":"string"},{"internalType":"string","name":"typeOfCampaign","type":"string"},{"internalType":"bool","name":"cashedOut","type":"bool"},{"internalType":"bool","name":"isCheckedByWebsite","type":"bool"},{"internalType":"string","name":"websiteComment","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_min","type":"uint256"}],"name":"changeMinInvestment","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"closeCampaign","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_profilePic","type":"string"},{"internalType":"string","name":"_phoneNumber","type":"string"},{"internalType":"string","name":"_title","type":"string"},{"internalType":"string","name":"_description","type":"string"},{"internalType":"uint256","name":"_target","type":"uint256"},{"internalType":"uint256","name":"_endDate","type":"uint256"},{"internalType":"string","name":"_videoLinkFromPinata","type":"string"},{"internalType":"string","name":"_type","type":"string"},{"internalType":"address","name":"_rewardTokenAddress","type":"address"},{"internalType":"uint256","name":"_initialRewardDeposit","type":"uint256"},{"internalType":"uint256","name":"_priceOfReward","type":"uint256"},{"internalType":"string","name":"tokenURI","type":"string"}],"name":"createCampaign","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"customerAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"customers","outputs":[{"internalType":"string","name":"email","type":"string"},{"internalType":"string","name":"phoneNum","type":"string"},{"internalType":"string","name":"customerName","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addressOfClient","type":"address"}],"name":"deleteCustomerDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"discountRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"string","name":"_comment","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"_profilePic","type":"string"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"tokenURI","type":"string"}],"name":"donateToCampaign","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"donatorNFT","outputs":[{"internalType":"contract IESH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_campaignId","type":"uint256"},{"internalType":"string","name":"_title","type":"string"},{"internalType":"string","name":"_description","type":"string"},{"internalType":"string","name":"_videoLinkFromPinata","type":"string"},{"internalType":"string","name":"_profilePic","type":"string"}],"name":"editCampaign","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllCustomers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getCampaign","outputs":[{"components":[{"internalType":"string","name":"phoneNumber","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"title","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"uint256","name":"target","type":"uint256"},{"internalType":"uint256","name":"endDate","type":"uint256"},{"internalType":"string","name":"profilePic","type":"string"},{"internalType":"string","name":"videoLinkFromPinata","type":"string"},{"internalType":"string","name":"typeOfCampaign","type":"string"},{"internalType":"bool","name":"cashedOut","type":"bool"},{"internalType":"bool","name":"isCheckedByWebsite","type":"bool"},{"internalType":"string","name":"websiteComment","type":"string"}],"internalType":"struct ESHFundRaising.Campaign","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCampaigns","outputs":[{"components":[{"internalType":"string","name":"phoneNumber","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"title","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"uint256","name":"target","type":"uint256"},{"internalType":"uint256","name":"endDate","type":"uint256"},{"internalType":"string","name":"profilePic","type":"string"},{"internalType":"string","name":"videoLinkFromPinata","type":"string"},{"internalType":"string","name":"typeOfCampaign","type":"string"},{"internalType":"bool","name":"cashedOut","type":"bool"},{"internalType":"bool","name":"isCheckedByWebsite","type":"bool"},{"internalType":"string","name":"websiteComment","type":"string"}],"internalType":"struct ESHFundRaising.Campaign[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getDonators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"string[]","name":"","type":"string[]"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"string[]","name":"","type":"string[]"},{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getModsAddresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"customerAddress","type":"address"}],"name":"isCustomer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isRegisteredCustomer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"modAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numberOfCampaigns","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openCampaignCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_campaignId","type":"uint256"}],"name":"priceRewardOfCampaign","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_moderator","type":"address"}],"name":"removeModerator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"returnTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_campaignId","type":"uint256"}],"name":"rewardName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cost","type":"uint256"}],"name":"setCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_percentage","type":"uint256"}],"name":"setDiscountRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_investorNFT","type":"address"},{"internalType":"address","name":"_campaignCreatorNFTAddress","type":"address"}],"name":"setNFTAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_campaignId","type":"uint256"}],"name":"stopCampaignByMod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sushiRouter","outputs":[{"internalType":"contract IUniswapV2Router01","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenContract","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"total","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"string","name":"_websiteComment","type":"string"}],"name":"verifyCampaign","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"withdrawCampaign","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdrawProfit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]