增加一个转账的NFTMall

This commit is contained in:
CounterFire2023 2023-08-30 13:14:14 +08:00
parent 698e9e9be8
commit c12e4afe53
4 changed files with 30372 additions and 20 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,173 @@
// 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 "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "../core/HasSignature.sol";
import "../interfaces/IBEERC1155.sol";
import "../utils/TimeChecker.sol";
import "../utils/UInt.sol";
import "./MallBase.sol";
contract BENftMallTrans is
MallBase,
ReentrancyGuard,
HasSignature,
TimeChecker
{
using SafeERC20 for IERC20;
using UInt for uint256;
mapping(address => bool) public erc721Supported;
mapping(address => bool) public erc1155Supported;
// Events
event BuyTransaction(
address indexed buyer,
uint256 indexed orderId,
address currency,
uint256 price,
address[] nftAddresses,
uint256[] ids,
uint256[] amounts
);
event AddNFTSuppout(address nftToken);
event RemoveNFTSuppout(address nftToken);
/**
* @dev Add ERC20 support
*/
function addERC721Support(address nftToken) external onlyOwner {
erc721Supported[nftToken] = true;
emit AddNFTSuppout(nftToken);
}
/**
* @dev Remove 721 NFT support
*/
function removeERC721Support(address nftToken) external onlyOwner {
erc721Supported[nftToken] = false;
emit RemoveNFTSuppout(nftToken);
}
/**
* @dev Add 1155 NFT support
*/
function addERC1155Support(address nftToken) external onlyOwner {
erc1155Supported[nftToken] = true;
emit AddNFTSuppout(nftToken);
}
/**
* @dev Remove 1155 NFT support
*/
function removeERC1155Support(address nftToken) external onlyOwner {
erc1155Supported[nftToken] = false;
emit RemoveNFTSuppout(nftToken);
}
/**
* @dev Buy NFT and other Game item from mall
*/
function buyNFT(
address currency,
address[] memory nftAddresses,
uint256[] memory ids,
uint256[] memory amounts,
uint256[] memory values, // [orderId, price, startTime, saltNonce]
bytes calldata signature
) external nonReentrant signatureValid(signature) timeValid(values[2]) {
require(erc20Supported[currency], "BENftMall: invalid payment method");
require(values.length == 4, "BENftMall: invalid values length");
require(
nftAddresses.length == ids.length && ids.length == amounts.length,
"BENftMall: nftAddresses, ids and amounts length mismatch"
);
require(nftAddresses.length > 0, "BENftMall: ids length is zero");
for (uint256 i = 0; i < nftAddresses.length; ++i) {
require(
erc721Supported[nftAddresses[i]] || erc1155Supported[nftAddresses[i]],
"BENftMall: nft token is not supported"
);
}
uint256[] memory signArray = new uint256[](ids.length * 2 + 4);
for (uint256 i = 0; i < nftAddresses.length; ++i) {
signArray[i * 2] = ids[i];
signArray[i * 2 + 1] = amounts[i];
}
for (uint256 i = 0; i < values.length; ++i) {
signArray[ids.length * 2 + i] = values[i];
}
bytes32 criteriaMessageHash = getMessageHash(
currency,
_msgSender(),
nftAddresses,
signArray
);
checkSigner(executor, criteriaMessageHash, signature);
// Check payment approval and buyer balance
require(
IERC20(currency).balanceOf(_msgSender()) >= values[1],
"BENftMall: buyer doesn't have enough token to buy this item"
);
require(
IERC20(currency).allowance(_msgSender(), address(this)) >= values[1],
"BENftMall: buyer doesn't approve enough token to buy this item"
);
// Transfer payment to seller
IERC20(currency).safeTransferFrom(_msgSender(), feeToAddress, values[1]);
for (uint256 i = 0; i < nftAddresses.length; ++i) {
if (erc721Supported[nftAddresses[i]]) {
IERC721(nftAddresses[i]).safeTransferFrom(
address(this),
_msgSender(),
ids[i]
);
} else if (erc1155Supported[nftAddresses[i]]) {
IERC1155(nftAddresses[i]).safeTransferFrom(
address(this),
_msgSender(),
ids[i],
amounts[i],
""
);
}
}
_useSignature(signature);
// emit buy event
emit BuyTransaction(
_msgSender(),
values[0],
currency,
values[1],
nftAddresses,
ids,
amounts
);
}
function getMessageHash(
address _tokenAddress,
address _buyerAddress,
address[] memory _nftAddresses,
uint256[] memory _datas
) public pure returns (bytes32) {
bytes memory encoded = abi.encodePacked(_tokenAddress, _buyerAddress);
for (uint256 i = 0; i < _nftAddresses.length; i++) {
encoded = bytes.concat(encoded, abi.encodePacked(_nftAddresses[i]));
}
for (uint256 i = 0; i < _datas.length; ++i) {
encoded = bytes.concat(encoded, abi.encodePacked(_datas[i]));
}
return keccak256(encoded);
}
}

View File

@ -1,5 +1,6 @@
const BENftMarket = artifacts.require("market/BENftMarket"); const BENftMarket = artifacts.require("market/BENftMarket");
const BENftMall = artifacts.require("market/BENftMall"); // const BENftMall = artifacts.require("market/BENftMall");
const BENftMallTrans = artifacts.require("market/BENftMallTrans");
const GameItemMarket = artifacts.require("market/GameItemMarket"); const GameItemMarket = artifacts.require("market/GameItemMarket");
const GameItemMall = artifacts.require("market/GameItemMall"); const GameItemMall = artifacts.require("market/GameItemMall");
const FT = artifacts.require("tokens/erc20/FT"); const FT = artifacts.require("tokens/erc20/FT");
@ -33,30 +34,42 @@ module.exports = async function (deployer, network, accounts) {
// address: nftMallInstance.address, // address: nftMallInstance.address,
// network, // network,
// }); // });
let cfgs = base.loadData({ network }); await deployer.deploy(BENftMallTrans);
const cegInstance = await FT.at(cfgs.find((c) => c.name === "CEG").address); const nftMallInstance = await BENftMallTrans.deployed();
await deployer.deploy( if (nftMallInstance) {
BETokenMall, console.log("BENftMallTrans successfully deployed.");
cegInstance.address,
config.market.feeToAddress
);
const tokenMallInstance = await BETokenMall.deployed();
if (tokenMallInstance) {
console.log("BETokenMall successfully deployed.");
} }
await tokenMallInstance.setFeeToAddress(config.market.feeToAddress);
const usdcInstance = await FT.at(
cfgs.find((c) => c.name === "BEUSDC").address
);
await tokenMallInstance.addERC20Support(usdcInstance.address);
await tokenMallInstance.updateTokenPrice(usdcInstance.address, "10000000");
base.updateArray({ base.updateArray({
name: "BETokenMall", name: "BENftMallTrans",
type: "logic", type: "logic",
json: "assets/contracts/BETokenMall.json", json: "assets/contracts/BENftMallTrans.json",
address: tokenMallInstance.address, address: nftMallInstance.address,
network, network,
}); });
// let cfgs = base.loadData({ network });
// const cegInstance = await FT.at(cfgs.find((c) => c.name === "CEG").address);
// await deployer.deploy(
// BETokenMall,
// cegInstance.address,
// config.market.feeToAddress
// );
// const tokenMallInstance = await BETokenMall.deployed();
// if (tokenMallInstance) {
// console.log("BETokenMall successfully deployed.");
// }
// await tokenMallInstance.setFeeToAddress(config.market.feeToAddress);
// const usdcInstance = await FT.at(
// cfgs.find((c) => c.name === "BEUSDC").address
// );
// await tokenMallInstance.addERC20Support(usdcInstance.address);
// await tokenMallInstance.updateTokenPrice(usdcInstance.address, "10000000");
// base.updateArray({
// name: "BETokenMall",
// type: "logic",
// json: "assets/contracts/BETokenMall.json",
// address: tokenMallInstance.address,
// network,
// });
// await deployer.deploy(GameItemMarket); // await deployer.deploy(GameItemMarket);
// const gameMarketInstance = await GameItemMarket.deployed(); // const gameMarketInstance = await GameItemMarket.deployed();

View File

@ -136,5 +136,11 @@
"type": "erc721", "type": "erc721",
"json": "assets/contracts/NFT.json", "json": "assets/contracts/NFT.json",
"address": "0x6f9c3F80C7F92064560eC09ab66dc132928Ff2dF" "address": "0x6f9c3F80C7F92064560eC09ab66dc132928Ff2dF"
},
{
"name": "BENftMallTrans",
"type": "logic",
"json": "assets/contracts/BENftMallTrans.json",
"address": "0x9A41d4D09B2fa6334c49f87ee4Ab0095C4dd8D1E"
} }
] ]