becrypto/contracts/market/BETokenMall.sol

110 lines
3.2 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../utils/UInt.sol";
import "./MallBase.sol";
interface ICurrency is IERC20 {
function decimals() external view returns (uint256);
}
contract BETokenMall is MallBase, ReentrancyGuard {
using SafeERC20 for IERC20;
using UInt for uint256;
uint256 constant ROUND = 1000000;
address public tokenAddress;
address public seller;
// currency => price
mapping(address => uint256) public prices;
// Events
event BuyTransaction(
address indexed buyer,
address tokenAddress,
address currency,
uint256 amount,
uint256 tokenAmount
);
event TokenAddressUpdated(address tokenAddress);
event SellerUpdated(address seller);
event UpdateTokenPrice(address currency, uint256 price, uint256 pricePre);
/**
* @dev Constructor
*/
constructor(address _tokenAddress, address _seller) {
tokenAddress = _tokenAddress;
seller = _seller;
}
/**
* @dev Update token address
*/
function updateTokenAddress(address _tokenAddress) external onlyOwner {
tokenAddress = _tokenAddress;
emit TokenAddressUpdated(_tokenAddress);
}
/**
* @dev Update seller address
*/
function updateSeller(address _seller) external onlyOwner {
seller = _seller;
emit SellerUpdated(_seller);
}
/**
* @dev Update token price
*/
function updateTokenPrice(
address currency,
uint256 price
) external onlyOwner {
uint256 pricePre = prices[currency];
prices[currency] = price;
emit UpdateTokenPrice(currency, price, pricePre);
}
/**
* @dev Buy token
*/
function buyToken(address currency, uint256 amount) external nonReentrant {
require(amount > 0, "BETokenMall: invalid amount");
require(erc20Supported[currency], "BETokenMall: invalid payment method");
require(prices[currency] > 0, "BETokenMall: invalid token price");
// calc currency amount
uint256 currencyDecimal = ICurrency(currency).decimals();
uint256 tokenAmount = (prices[currency] *
amount *
(10 ** (18 - currencyDecimal))) / ROUND;
address buyer = _msgSender();
require(
IERC20(tokenAddress).balanceOf(seller) >= tokenAmount,
"BETokenMall: seller doesn't have enough token to sell this item"
);
require(
IERC20(tokenAddress).allowance(seller, address(this)) >= tokenAmount,
"BETokenMall: seller doesn't approve enough token to sell this item"
);
// Check payment approval and buyer balance
require(
IERC20(currency).balanceOf(buyer) >= amount,
"BETokenMall: buyer doesn't have enough token to buy this item"
);
require(
IERC20(currency).allowance(buyer, address(this)) >= amount,
"BETokenMall: buyer doesn't approve enough token to buy this item"
);
// Transfer payment to seller
IERC20(currency).safeTransferFrom(buyer, feeToAddress, amount);
// Transfer token to buyer
IERC20(tokenAddress).safeTransferFrom(seller, buyer, tokenAmount);
// emit buy event
emit BuyTransaction(buyer, tokenAddress, currency, amount, tokenAmount);
}
}