// 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/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 tekToken;
/// 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 _tekToken) {
tekToken = _teToken;
}
/**
* @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 $TE
* @dev use API call to coinmarketcap to get price
* @param usdPrice price of item
* @return converted price in $TE
*/
function getTeTokenPrice(uint256 usdPrice) internal pure returns (uint256) {
uint256 teTokenPrice = 20000000000000000;
uint256 priceUsd = usdPrice.mul(10 ** 18);
uint256 newPrice = priceUsd.div(teTokenPrice);
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 (tekToken.balanceOf(msg.sender) >= price) {
uint256 teTokens = getTeTokenPrice(item.price);
uint256 feeAmount = teTokens.mul(feePercentage).div(100);
tekToken.safeTransferFrom(
msg.sender,
item.seller,
teTokens.sub(feeAmount)
); // transfer funds to seller account
tekToken.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);
}
}
I have the contract above . am facing an error of insufficient allowance when I try to buy the item using the tek token. How would I add the approval of TEK tokens to my contract to allow the contract to spend a given number of tek tokens on behalf of the TEKToken contract?
NB: tek token is a test token so it can be any token