becrypto/contracts/logic/NftChipLocker.sol
2022-11-08 11:41:20 +08:00

213 lines
7.2 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "../core/HasSignature.sol";
import "../utils/TimeChecker.sol";
import "../interfaces/IBEERC1155.sol";
import "../interfaces/IBEERC721.sol";
contract NftChipLocker is Ownable, ERC1155Holder, HasSignature, TimeChecker{
mapping(address => bool) public nftTokenSupported;
using EnumerableSet for EnumerableSet.UintSet;
uint256 public constant MAX_CHIP_NUM = 4;
constructor() HasSignature("NftChipLocker", "1") {}
/**
* nft address => chip address => nftid => slot => chip tokenid
*/
mapping( address => mapping(address => mapping(uint256 => mapping(uint256 => uint256)))) chipPlugined;
/**
* nft address => chip address => chip tokenid => nftid
*/
mapping( address => mapping(address => mapping(uint256 => uint256))) chipOwner;
event ChipPlugin(
address indexed nft,
uint256 indexed nftId,
uint256 indexed nonce,
address chip,
uint256[] ids
);
event ChipUnplug(
address indexed nft,
uint256 indexed nftId,
uint256 indexed nonce,
address chip,
uint256[] ids
);
function addNFTTokenSupport(address nftToken) external onlyOwner {
nftTokenSupported[nftToken] = true;
}
function removeNFTTokenSupport(address nftToken) external onlyOwner {
nftTokenSupported[nftToken] = false;
}
function pluginChip(
address[3] calldata addresses,
uint256[3] calldata values,
uint256[] memory chipIds,
uint256[] memory chipSlot,
bytes calldata signature
)
external signatureValid(signature) timeValid(values[2])
{
// addresses[2] [nft, chip, svr_address]
// uint256[3] [token_id,salt_nonce,startTime]
require(chipIds.length == chipSlot.length, "NftChipLocker: chip id and index mislength");
require(chipIds.length <= MAX_CHIP_NUM, "NftChipLocker: chip num reach max allow");
require(nftTokenSupported[addresses[0]], "NftChipLocker: Unsupported NFT");
require(nftTokenSupported[addresses[1]], "NftChipLocker: Unsupported Chip");
require(!IBEERC721(addresses[0]).isLocked(values[0]), "NftChipLocker: Can not pluin chip to locked token");
require(IERC721(addresses[0]).ownerOf(values[0]) == msg.sender, "NftChipLocker: not owner of this nft now");
uint256[] memory signArray = new uint256[](values.length + chipIds.length * 2);
for (uint256 i = 0; i < values.length; ++i ) {
signArray[i] = values[i];
}
uint256[] memory amounts = new uint256[](chipIds.length);
for (uint256 i = 0; i < chipIds.length; ++i) {
require(
chipSlot[i] < MAX_CHIP_NUM,
"NftChipLocker: slot error"
);
require(
IERC1155(addresses[1]).balanceOf(msg.sender, chipIds[i]) > 0,
"NftChipLocker: not enough chip"
);
require(
!IBEERC1155(addresses[1]).isLocked(chipIds[i]),
"NftChipLocker: chip is locked"
);
require(
chipPlugined[addresses[0]][addresses[1]][values[0]][chipSlot[i]] == 0,
"NftChipLocker: slot already plugined"
);
chipPlugined[addresses[0]][addresses[1]][values[0]][chipSlot[i]] = chipIds[i];
chipOwner[addresses[0]][addresses[1]][chipIds[i]] = values[0];
amounts[i] = 1;
signArray[values.length + 2 * i] = chipIds[i];
signArray[values.length + 2 * i + 1] = chipSlot[i];
}
bytes32 criteriaMessageHash = getMessageHash(
addresses[0],
addresses[1],
_msgSender(),
signArray
);
checkSigner(addresses[2], criteriaMessageHash, signature);
IERC1155(addresses[1]).safeBatchTransferFrom(msg.sender, address(this), chipIds, amounts, "");
_useSignature(signature);
emit ChipPlugin(addresses[0], values[0], values[1], addresses[1], chipIds);
}
function unplugChip(
address[3] calldata addresses,
uint256[3] calldata values,
uint256[] memory chipIds,
uint256[] memory chipSlot,
bytes calldata signature
)
external signatureValid(signature) timeValid(values[2])
{
// addresses[2] [nftId, chip]
// uint256[3] [token_id,salt_nonce,startTime]
require(chipIds.length == chipSlot.length, "NftChipLocker: chip id and index mislength");
require(chipIds.length <= MAX_CHIP_NUM, "NftChipLocker: chip num reach max allow");
require(nftTokenSupported[addresses[0]], "NftChipLocker: Unsupported NFT");
require(nftTokenSupported[addresses[1]], "NftChipLocker: Unsupported Chip");
require(!IBEERC721(addresses[0]).isLocked(values[0]), "NftChipLocker: Can not pluin chip to locked token");
require(IERC721(addresses[0]).ownerOf(values[0]) == msg.sender, "NftChipLocker: not owner of this nft now");
uint256[] memory signArray = new uint256[](values.length + chipIds.length * 2);
for (uint256 i = 0; i < values.length; ++i ) {
signArray[i] = values[i];
}
uint256[] memory amounts = new uint256[](chipIds.length);
for (uint256 i = 0; i < chipIds.length; ++i) {
require(
chipPlugined[addresses[0]][addresses[1]][values[0]][chipSlot[i]] > 0,
"NftChipLocker: chip not exists"
);
delete chipPlugined[addresses[0]][addresses[1]][values[0]][chipSlot[i]];
delete chipOwner[addresses[0]][addresses[1]][chipIds[i]];
amounts[i] = 1;
signArray[values.length + 2 * i] = chipIds[i];
signArray[values.length + 2 * i + 1] = chipSlot[i];
}
bytes32 criteriaMessageHash = getMessageHash(
addresses[0],
addresses[1],
_msgSender(),
signArray
);
checkSigner(addresses[2], criteriaMessageHash, signature);
IERC1155(addresses[1]).safeBatchTransferFrom(address(this), msg.sender, chipIds, amounts, "");
_useSignature(signature);
emit ChipUnplug(addresses[0], values[0], values[1], addresses[1], chipIds);
}
function chipOwnerTokenid(address nft, address chip, uint256 chipId)
external
view
returns(uint256)
{
return chipOwner[nft][chip][chipId];
}
function pluginedChipNum(address nft, address chip, uint256 tokenId)
public
view
returns(uint256)
{
uint256 len = 0;
for (uint256 i = 0; i < MAX_CHIP_NUM; ++i) {
if (chipPlugined[nft][chip][tokenId][i] > 0) {
len ++;
}
}
return len;
}
function pluginedChips(address nft, address chip, uint256 tokenId)
external
view
returns(uint256[] memory)
{
uint256[] memory result = new uint256[](MAX_CHIP_NUM);
for (uint256 i = 0; i < MAX_CHIP_NUM; ++i) {
result[i] = chipPlugined[nft][chip][tokenId][i];
}
return result;
}
function getMessageHash(
address _nftAddress,
address _chipAddress,
address _userAddress,
uint256[] memory _datas
) public pure returns (bytes32) {
bytes memory encoded = abi.encodePacked(
_nftAddress,
_chipAddress,
_userAddress
);
uint256 len = _datas.length;
for (uint256 i = 0; i < len; ++i) {
encoded = bytes.concat(encoded, abi.encodePacked(_datas[i]));
}
return keccak256(encoded);
}
}