// 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/ERC20/utils/SafeERC20.sol"; import "../interfaces/IBEERC1155.sol"; import "../interfaces/IAsset.sol"; import "../core/HasSignature.sol"; import "../utils/TimeChecker.sol"; import "../market/MallBase.sol"; import "../utils/UInt.sol"; contract ShardAssembler is Ownable, TimeChecker, HasSignature, MallBase { using SafeERC20 for IERC20; using UInt for uint256; IAsset public hero; IBEERC1155 public shard; struct AssembleParams { uint256 tokenId; address payToken; uint256 tokenAmount; uint256 startTime; uint256 saltNonce; } event ShardAssembled( address indexed to, uint256 indexed tokenId, address indexed payToken, uint256 tokenAmount ); // generate constructor constructor(address[2] memory _addresses){ hero = IAsset(_addresses[0]); shard = IBEERC1155(_addresses[1]); } function assembleShard( AssembleParams calldata params, uint256[] memory ids, uint256[] memory amounts, bytes calldata signature ) external signatureValid(signature) timeValid(params.startTime) { require(ids.length > 0, "ShardAssembler: ids length must > 0"); require(params.tokenId > 0, "ShardAssembler: tokenId can not be 0"); require(erc20Supported[params.payToken], "ShardAssembler: payToken not supported"); address user = _msgSender(); uint256[] memory signArray = new uint256[](ids.length * 2); for (uint256 i = 0; i < ids.length; ++i) { signArray[i * 2] = ids[i]; signArray[i * 2 + 1] = amounts[i]; } bytes32 criteriaMessageHash = getMessageHash(params, user, address(hero), address(this), signArray); checkSigner(executor, criteriaMessageHash, signature); shard.burnBatch(user, ids, amounts); hero.batchMint(user, params.tokenId.asSingletonArray()); _useSignature(signature); IERC20(params.payToken).transferFrom(user, feeToAddress, params.tokenAmount); emit ShardAssembled(user, params.tokenId, params.payToken, params.tokenAmount); } function getMessageHash( AssembleParams memory params, address user, address nftAddress, address contractAddress, uint256[] memory _ids ) internal pure returns (bytes32) { bytes memory encoded = abi.encodePacked( user, nftAddress, contractAddress, params.tokenId, params.payToken, params.tokenAmount, params.startTime, params.saltNonce ); uint256 len = _ids.length; for (uint256 i = 0; i < len; ++i) { encoded = bytes.concat(encoded, abi.encodePacked(_ids[i])); } return keccak256(encoded); } }