110 lines
3.2 KiB
Solidity
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);
|
|
}
|
|
}
|