i receive an error upon trying to interact with buy function in my contract below
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract Market is Ownable {
using SafeMath for uint256;
using SafeERC20 for IERC20;
AggregatorV3Interface internal priceFeed;
struct Item {
bytes32 id; // unique id of the item
string name; // name of item
uint256 price; // price of item
bool isSold; //
address payable seller; // seller / owner of item
address payable buyer; // buyer of the item
}
mapping(bytes32 => Item) internal items; // mapping of items
bytes32[] internal itemIds; // mapping of the unique ids of the items
uint256 internal itemIndex; // counter
uint256 internal feePercentage = 10; // default fee precentage
IERC20 internal usdt;
IERC20 internal teToken;
/// events
event ItemListed(bytes32 id, string name, uint256 price, address seller);
event ItemSold(
bytes32 id,
string name,
uint256 price,
address seller,
address buyer
);
constructor(IERC20 _usdt, IERC20 _teToken) {
usdt = _usdt;
teToken = _teToken;
priceFeed = AggregatorV3Interface(
0x0d79df66BE487753B02D015Fb622DED7f0E9798d
);
}
/**
* @notice unique id genrator function
* @param to address of the item owner
* @param count counter
*/
function generateId(
address to,
uint256 count
) internal view returns (bytes32) {
return keccak256(abi.encode(address(this), to, count));
}
/**
* @notice function that lists an item
* @param _name name of item
* @param _price price of item
*/
function listItem(string memory _name, uint256 _price) external {
require(bytes(_name).length > 0, "Item name cannot be empty");
require(_price > 0, "Item price must be greater than 0");
bytes32 itemId = generateId(msg.sender, itemIndex); // generate unique id
require(items[itemId].id == 0, "Item already exists");
items[itemId] = Item({
id: itemId,
name: _name,
price: _price,
isSold: false,
seller: payable(msg.sender),
buyer: payable(address(0))
});
itemIds.push(itemId); //creating item
emit ItemListed(
generateId(msg.sender, itemIndex),
_name,
_price,
payable(msg.sender)
);
itemIndex++; // incrementing itemIndex
}
/**
* @notice function that converts price of item to usdt
* @dev use chainlink Price feeds
* @param usdPrice price of item
* @return converted price in usdt
*/
function getUsdtPrice(uint256 usdPrice) internal view returns (uint256) {
// ERC20 usdtNew = ERC20(0x55d398326f99059fF775485246999027B3197955); // contract for usdt
(, int256 price, , , ) = priceFeed.latestRoundData(); // latest price of usdt
require(price > 0, "Invalid price feed");
uint256 usdtPrice = uint256(price).div(1e8).mul(10 ** 18);
uint256 priceUsd = usdPrice.mul(10 ** 18);
uint256 priceInUsdt = priceUsd.div(usdtPrice);
return priceInUsdt;
}
/**
* @notice function that converts price of item to $TeToken
* @dev use API call to coinmarketcap to get price
* @param usdPrice price of item
* @return converted price in $TeToken
*/
function getTePrice(uint256 usdPrice) internal pure returns (uint256) {
uint256 tePrice = 20000000000000000;
uint256 priceUsd = usdPrice.mul(10 ** 18);
uint256 newPrice = priceUsd.div(tePrice);
return newPrice;
}
/**
* @notice function to buy an item
* @param id unique id for the item
*/
function buyItem(bytes32 id) external {
Item storage item = items[id];
require(item.id != 0, "Item does not exist");
require(!item.isSold, "Item is already Purchased");
item.buyer = payable(msg.sender);
uint256 price= item.price.mul(10**18);
if (usdt.balanceOf(msg.sender) >= price) {
uint256 usdtTokens = getUsdtPrice(item.price);
uint256 feeAmount = usdtTokens.mul(feePercentage).div(100);
usdt.safeTransferFrom(
msg.sender,
item.seller,
usdtTokens.sub(feeAmount)
); // transfer funds to seller account
usdt.safeTransferFrom(msg.sender, owner(), feeAmount); // transfer funds to contract owner
} else if (teToken.balanceOf(msg.sender) >= price) {
uint256 teTokens = getTePrice(item.price);
uint256 feeAmount = teTokens.mul(feePercentage).div(100);
teToken.safeTransferFrom(
msg.sender,
item.seller,
teTokens.sub(feeAmount)
); // transfer funds to seller account
teToken.safeTransferFrom(msg.sender, owner(), feeAmount); // transfer funds to contract owner
} else {
revert("Insufficient funds or wrong payment method");
}
emit ItemSold(id, item.name, item.price, item.seller, item.buyer);
item.isSold = true;
item.seller = item.buyer;
}
/**
* @dev : return all unique ids for the items
*/
function getAllItemIds() external view returns (bytes32[] memory) {
return itemIds;
}
/**
* @dev returning an item based on the unique id
* @param itemId unique id for the item
*/
function getItem(
bytes32 itemId
) external view returns (string memory name, uint256 price, bool sold, address seller, address buyer) {
Item storage item = items[itemId];
require(item.id != 0, "Item does not exist");
return (item.name, item.price, item.isSold, item.seller, item.buyer);
}
/**
* @dev Sets Fee Percentage
*/
function setFeePercent(uint256 _feePercent) external onlyOwner {
require(
_feePercent >= 0 && _feePercent <= 100,
"Invalid fee percentage: fee percentage should be between 1 and 99"
);
feePercentage = _feePercent;
}
function getFeePercentage() external view returns (uint256) {
return feePercentage;
}
}
i get an error while using remix idle
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
VM Exception while processing transaction: revert
teToken is a custom token i created for testing purposes. below is the contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract TE is ERC20 {
uint256 public constant INITIAL_SUPPLY = 1000000 * 10 ** 18; // Total supply of 1 million tokens
constructor() ERC20("TE", "TE") {
_mint(msg.sender, INITIAL_SUPPLY);
}
}