重构代码, 将一些重复的代码提出来

This commit is contained in:
cebgcontract 2022-08-16 16:00:49 +08:00
parent 92876d4160
commit 1858260d00
10 changed files with 211 additions and 199 deletions

View File

@ -1,8 +1,10 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.10; pragma solidity 0.8.10;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "../utils/Approval.sol";
contract HasSignature { contract HasSignature is Ownable, Approval{
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID; uint256 private immutable _CACHED_CHAIN_ID;
address private immutable _CACHED_THIS; address private immutable _CACHED_THIS;
@ -10,6 +12,7 @@ contract HasSignature {
bytes32 private immutable _HASHED_NAME; bytes32 private immutable _HASHED_NAME;
bytes32 private immutable _HASHED_VERSION; bytes32 private immutable _HASHED_VERSION;
bytes32 private immutable _TYPE_HASH; bytes32 private immutable _TYPE_HASH;
mapping(bytes => bool) private _usedSignatures;
constructor(string memory name, string memory version) { constructor(string memory name, string memory version) {
bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedName = keccak256(bytes(name));
@ -112,4 +115,25 @@ contract HasSignature {
address recovered = ECDSA.recover(ethSignedMessageHash, signature); address recovered = ECDSA.recover(ethSignedMessageHash, signature);
require(recovered == signer, "[BE] invalid signature"); require(recovered == signer, "[BE] invalid signature");
} }
modifier signatureValid(
bytes calldata signature
) {
require(
!_usedSignatures[signature],
"signature used. please send another transaction with new signature"
);
_;
}
/**
* @dev mark signature used
*/
function useSignature(
bytes calldata signature
) public approvaled {
if (!_usedSignatures[signature]) {
_usedSignatures[signature] = true;
}
}
} }

View File

@ -23,7 +23,7 @@ interface INFTFactory {
IBEERC1155 nft IBEERC1155 nft
) external; ) external;
function ignoreSignature( function useSignature(
bytes calldata signature bytes calldata signature
) external; ) external;
} }

View File

@ -6,28 +6,24 @@ import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "../interfaces/IBEERC721.sol"; import "../interfaces/IBEERC721.sol";
import "../interfaces/IBEERC1155.sol"; import "../interfaces/IBEERC1155.sol";
import "../utils/UInt.sol"; import "../utils/UInt.sol";
import "../utils/TimeChecker.sol";
import "../core/HasSignature.sol"; import "../core/HasSignature.sol";
// this contract will transfer ownership to BETimelockController after deployed // this contract will transfer ownership to BETimelockController after deployed
// all onlyowner method would add timelock // all onlyowner method would add timelock
contract EvolveFactory is Ownable, Initializable, HasSignature { contract EvolveFactory is Ownable, TimeChecker, Initializable, HasSignature {
using UInt for uint256; using UInt for uint256;
IBEERC721 public hero; IBEERC721 public hero;
IBEERC721 public equip; IBEERC721 public equip;
IBEERC1155 public chip; IBEERC1155 public chip;
uint256 private _duration;
mapping(bytes => bool) public usedSignatures;
address public executor; address public executor;
event TokenEvolved( event TokenEvolved(
uint256 indexed evolveEventId,
address indexed owner, address indexed owner,
uint256 tokenEvolved, uint256[3] tokenIds
uint256 tokenBurned,
uint256 chip
); );
constructor() constructor()
@ -48,70 +44,14 @@ contract EvolveFactory is Ownable, Initializable, HasSignature {
executor = account; executor = account;
} }
/** function evolve721NFT(
* @dev evolve function to Blissful Elites Hero NFT address to,
* tokenIds: [hero_to_evolve, hero_for_burn, chip]
*/
function evolveHero(
uint256 evolveEventId,
uint256[3] calldata tokenIds, uint256[3] calldata tokenIds,
uint256 startTime,
uint256 saltNonce, uint256 saltNonce,
bytes calldata signature bytes calldata signature,
) external { IBEERC721 nft
require( ) internal signatureValid(signature) timeValid(startTime){
tokenIds[0] > 0 && tokenIds[1] > 0,
"EvolveFactory: hero to evolve and burn can not be 0"
);
require(
tokenIds[0] != tokenIds[1],
"EvolveFactory: hero to evolve and burn can not be same"
);
require(
hero.ownerOf(tokenIds[0]) == msg.sender,
"EvolveFactory: not owner of this hero now"
);
require(
!usedSignatures[signature],
"EvolveFactory: signature used. please send another transaction with new signature"
);
bytes32 criteriaMessageHash = getMessageHash(
evolveEventId,
tokenIds[0],
tokenIds[1],
tokenIds[2],
saltNonce
);
checkSigner(executor, criteriaMessageHash, signature);
hero.burn(msg.sender, tokenIds[1]);
if (tokenIds[2] > 0) {
uint256 amount = 1;
chip.burnBatch(msg.sender,
tokenIds[2].asSingletonArray(),
amount.asSingletonArray());
}
usedSignatures[signature] = true;
emit TokenEvolved(
evolveEventId,
msg.sender,
tokenIds[0],
tokenIds[1],
tokenIds[2]
);
}
/**
* @dev evolve function to Blissful Elites Equip NFT
* tokenIds: [equip_to_evolve, equip_for_burn, chip]
*/
function evolveEquip(
uint256 evolveEventId,
uint256[3] calldata tokenIds,
uint256 saltNonce,
bytes calldata signature
) external{
require( require(
tokenIds[0] > 0 && tokenIds[1] > 0, tokenIds[0] > 0 && tokenIds[1] > 0,
"EvolveFactory: equip to evolve and burn can not be 0" "EvolveFactory: equip to evolve and burn can not be 0"
@ -123,56 +63,60 @@ contract EvolveFactory is Ownable, Initializable, HasSignature {
); );
require( require(
equip.ownerOf(tokenIds[0]) == msg.sender, nft.ownerOf(tokenIds[0]) == to,
"EvolveFactory: current address is not owner of this equip now" "EvolveFactory: current address is not owner of this nft now"
); );
require( require(
!usedSignatures[signature], nft.ownerOf(tokenIds[1]) == to,
"EvolveFactory: signature used. please send another transaction with new signature" "EvolveFactory: current address is not owner of this nft now"
); );
if (tokenIds[2] > 0) {
require(
nft.ownerOf(tokenIds[2]) == to,
"EvolveFactory: current address is not owner of this nft now"
);
}
uint256[] memory signArray = new uint256[](3);
for (uint256 i = 0; i < tokenIds.length; ++ i) {
signArray[i] = tokenIds[i];
}
bytes32 criteriaMessageHash = getMessageHash( bytes32 criteriaMessageHash = getMessageHash(
evolveEventId, to,
tokenIds[0], startTime,
tokenIds[1], saltNonce,
tokenIds[2], signArray
saltNonce
); );
checkSigner(executor, criteriaMessageHash, signature); checkSigner(executor, criteriaMessageHash, signature);
equip.burn(msg.sender, tokenIds[1]); nft.burn(to, tokenIds[1]);
if (tokenIds[2] > 0) { if (tokenIds[2] > 0) {
uint256 amount = 1; uint256 amount = 1;
chip.burnBatch(msg.sender, chip.burnBatch(to,
tokenIds[2].asSingletonArray(), tokenIds[2].asSingletonArray(),
amount.asSingletonArray()); amount.asSingletonArray());
} }
usedSignatures[signature] = true; useSignature(signature);
emit TokenEvolved( emit TokenEvolved(
evolveEventId, to,
msg.sender, tokenIds
tokenIds[0],
tokenIds[1],
tokenIds[2]
); );
} }
function getMessageHash( function getMessageHash(
uint256 _eventId, address _to,
uint256 _mainToken, uint256 _startTime,
uint256 _burnToken, uint256 _saltNonce,
uint256 _chipToken, uint256[] memory _ids
uint256 _saltNonce
) public pure returns (bytes32) { ) public pure returns (bytes32) {
return bytes memory encoded = abi.encodePacked(_to, _startTime, _saltNonce);
keccak256( uint256 len = _ids.length;
abi.encodePacked( for (uint256 i = 0; i < len; ++i) {
_eventId, encoded = bytes.concat(encoded, abi.encodePacked(_ids[i]));
_mainToken, }
_burnToken, return keccak256(encoded);
_chipToken,
_saltNonce
)
);
} }
} }

View File

@ -6,9 +6,10 @@ import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "../interfaces/IBEERC721.sol"; import "../interfaces/IBEERC721.sol";
import "../interfaces/IBEERC1155.sol"; import "../interfaces/IBEERC1155.sol";
import "../utils/UInt.sol"; import "../utils/UInt.sol";
import "../utils/TimeChecker.sol";
import "../core/HasSignature.sol"; import "../core/HasSignature.sol";
contract MinterFactory is Ownable, Initializable, HasSignature { contract MinterFactory is Ownable, TimeChecker, Initializable, HasSignature {
using UInt for uint256; using UInt for uint256;
address public executor; address public executor;
// NFT contract // NFT contract
@ -16,8 +17,6 @@ contract MinterFactory is Ownable, Initializable, HasSignature {
IBEERC721 public equip; IBEERC721 public equip;
IBEERC1155 public chip; IBEERC1155 public chip;
IBEERC1155 public shard; IBEERC1155 public shard;
uint256 private _duration;
mapping(address => bool) public approvalLists;
event TokenMinted( event TokenMinted(
address contractAddress, address contractAddress,
@ -33,7 +32,6 @@ contract MinterFactory is Ownable, Initializable, HasSignature {
uint256[] amounts uint256[] amounts
); );
mapping(bytes => bool) public usedSignatures;
constructor() HasSignature("MinterFactory", "1") {} constructor() HasSignature("MinterFactory", "1") {}
@ -42,23 +40,8 @@ contract MinterFactory is Ownable, Initializable, HasSignature {
equip = IBEERC721(_erc721s[1]); equip = IBEERC721(_erc721s[1]);
chip = IBEERC1155(_erc721s[2]); chip = IBEERC1155(_erc721s[2]);
shard = IBEERC1155(_erc721s[3]); shard = IBEERC1155(_erc721s[3]);
_duration = 1 days;
} }
/**
* @dev Allow operation to reverse signature.
*/
function addApprovalList(address user) external onlyOwner {
require(!approvalLists[user], "MinterFactory: Invalid user address");
approvalLists[user] = true;
}
/**
* @dev Remove operation from approval list.
*/
function removeApprovalList(address user) external onlyOwner {
approvalLists[user] = false;
}
/** /**
* @dev update executor * @dev update executor
@ -68,21 +51,6 @@ contract MinterFactory is Ownable, Initializable, HasSignature {
executor = account; executor = account;
} }
/**
* @dev Returns the max duration for function called by user
*/
function getDuration() external view
returns (uint256 duration) {
return _duration;
}
/**
* @dev Change duration value
*/
function updateDuation(uint256 valNew) external onlyOwner {
_duration = valNew;
}
/** /**
* @dev mint function to distribute Hero NFT to user * @dev mint function to distribute Hero NFT to user
*/ */
@ -158,21 +126,13 @@ contract MinterFactory is Ownable, Initializable, HasSignature {
uint256 saltNonce, uint256 saltNonce,
bytes calldata signature, bytes calldata signature,
IBEERC721 nft IBEERC721 nft
) external { ) external signatureValid(signature) timeValid(startTime){
require(
startTime + _duration >= block.timestamp,
"MinterFactory: signature expired, please send another transaction with new signature"
);
require(
!usedSignatures[signature],
"MinterFactory: signature used. please send another transaction with new signature"
);
uint256[] memory signArray = new uint256[](1); uint256[] memory signArray = new uint256[](1);
signArray[0] = id; signArray[0] = id;
bytes32 criteriaMessageHash = getMessageHash(to, startTime, saltNonce, signArray); bytes32 criteriaMessageHash = getMessageHash(to, startTime, saltNonce, signArray);
checkSigner(executor, criteriaMessageHash, signature); checkSigner(executor, criteriaMessageHash, signature);
mint721NFT(to, id, nft); mint721NFT(to, id, nft);
usedSignatures[signature] = true; useSignature(signature);
} }
function mint1155BatchByUser( function mint1155BatchByUser(
@ -183,21 +143,13 @@ contract MinterFactory is Ownable, Initializable, HasSignature {
uint256 saltNonce, uint256 saltNonce,
bytes calldata signature, bytes calldata signature,
IBEERC1155 nft IBEERC1155 nft
) external { ) external signatureValid(signature) timeValid(startTime){
uint256 len = ids.length; uint256 len = ids.length;
require(len > 0, "MinterFactory: ids cannot be empty"); require(len > 0, "MinterFactory: ids cannot be empty");
require( require(
len == amounts.length, len == amounts.length,
"MinterFactory: ids and amounts length mismatch" "MinterFactory: ids and amounts length mismatch"
); );
require(
startTime + _duration >= block.timestamp,
"MinterFactory: signature expired, please send another transaction with new signature"
);
require(
!usedSignatures[signature],
"MinterFactory: signature used. please send another transaction with new signature"
);
uint256[] memory signArray = new uint256[](len * 2); uint256[] memory signArray = new uint256[](len * 2);
for (uint256 i = 0; i < len; ++i) { for (uint256 i = 0; i < len; ++i) {
require( require(
@ -210,7 +162,7 @@ contract MinterFactory is Ownable, Initializable, HasSignature {
bytes32 criteriaMessageHash = getMessageHash(to, startTime, saltNonce, signArray); bytes32 criteriaMessageHash = getMessageHash(to, startTime, saltNonce, signArray);
checkSigner(executor, criteriaMessageHash, signature); checkSigner(executor, criteriaMessageHash, signature);
mint1155NFTBatch(to, ids, amounts, nft); mint1155NFTBatch(to, ids, amounts, nft);
usedSignatures[signature] = true; useSignature(signature);
} }
function mint721NFT( function mint721NFT(
@ -244,17 +196,6 @@ contract MinterFactory is Ownable, Initializable, HasSignature {
emit TokenMintedBatch(address(nft), to, ids, amounts); emit TokenMintedBatch(address(nft), to, ids, amounts);
} }
function ignoreSignature(
bytes calldata signature
) external {
require(
approvalLists[_msgSender()],
"Must be valid approval list"
);
if (!usedSignatures[signature]) {
usedSignatures[signature] = true;
}
}
function getMessageHash( function getMessageHash(
address _to, address _to,

View File

@ -0,0 +1,48 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "../interfaces/INFTFactory.sol";
import "../interfaces/IBEERC721.sol";
import "../interfaces/IBEERC1155.sol";
contract UserEvolveFactory is Ownable, Initializable {
IBEERC721 public hero;
IBEERC721 public equip;
IBEERC1155 public chip;
IBEERC1155 public shard;
event TokenEvolveFail (
address indexed to,
uint256 mainToken,
bytes signature,
string reason,
bytes byteReason
);
function init() external initializer onlyOwner {
}
/**
* @dev evolve function to Blissful Elites Hero NFT
* tokenIds: [hero_to_evolve, hero_for_burn, chip]
*/
function evolveHero(
uint256[3] calldata tokenIds,
uint256 saltNonce,
bytes calldata signature
) external {
}
/**
* @dev evolve function to Blissful Elites Equip NFT
* tokenIds: [equip_to_evolve, equip_for_burn, chip]
*/
function evolveEquip(
uint256[3] calldata tokenIds,
uint256 saltNonce,
bytes calldata signature
) external{
}
}

View File

@ -42,7 +42,7 @@ contract UserMinterFactory is Ownable, Initializable {
return true; return true;
} catch Error(string memory reason) { } catch Error(string memory reason) {
bytes memory by; bytes memory by;
factory.ignoreSignature(signature); factory.useSignature(signature);
emit TokenMintFail( emit TokenMintFail(
to, to,
signature, signature,
@ -51,6 +51,7 @@ contract UserMinterFactory is Ownable, Initializable {
); );
return false; return false;
} catch (bytes memory lowLevelData) { } catch (bytes memory lowLevelData) {
factory.useSignature(signature);
string memory reason; string memory reason;
emit TokenMintFail( emit TokenMintFail(
to, to,
@ -77,7 +78,7 @@ contract UserMinterFactory is Ownable, Initializable {
return true; return true;
} catch Error(string memory reason) { } catch Error(string memory reason) {
bytes memory by; bytes memory by;
factory.ignoreSignature(signature); factory.useSignature(signature);
emit TokenMintFail( emit TokenMintFail(
to, to,
signature, signature,
@ -86,6 +87,7 @@ contract UserMinterFactory is Ownable, Initializable {
); );
return false; return false;
} catch (bytes memory lowLevelData) { } catch (bytes memory lowLevelData) {
factory.useSignature(signature);
string memory reason; string memory reason;
emit TokenMintFail( emit TokenMintFail(
to, to,
@ -117,7 +119,7 @@ contract UserMinterFactory is Ownable, Initializable {
return true; return true;
} catch Error(string memory reason) { } catch Error(string memory reason) {
bytes memory by; bytes memory by;
factory.ignoreSignature(signature); factory.useSignature(signature);
emit TokenMintFail( emit TokenMintFail(
to, to,
signature, signature,
@ -126,6 +128,7 @@ contract UserMinterFactory is Ownable, Initializable {
); );
return false; return false;
} catch (bytes memory lowLevelData) { } catch (bytes memory lowLevelData) {
factory.useSignature(signature);
string memory reason; string memory reason;
emit TokenMintFail( emit TokenMintFail(
to, to,
@ -152,7 +155,7 @@ contract UserMinterFactory is Ownable, Initializable {
return true; return true;
} catch Error(string memory reason) { } catch Error(string memory reason) {
bytes memory by; bytes memory by;
factory.ignoreSignature(signature); factory.useSignature(signature);
emit TokenMintFail( emit TokenMintFail(
to, to,
signature, signature,
@ -161,6 +164,7 @@ contract UserMinterFactory is Ownable, Initializable {
); );
return false; return false;
} catch (bytes memory lowLevelData) { } catch (bytes memory lowLevelData) {
factory.useSignature(signature);
string memory reason; string memory reason;
emit TokenMintFail( emit TokenMintFail(
to, to,

View File

@ -36,7 +36,6 @@ contract BEBoxMall is Ownable, HasSignature, TimelockController{
); );
address public paymentReceivedAddress; address public paymentReceivedAddress;
mapping(bytes => bool) public usedSignatures;
function setPaymentReceivedAddress(address _paymentReceivedAddress) function setPaymentReceivedAddress(address _paymentReceivedAddress)
public public
@ -62,17 +61,13 @@ contract BEBoxMall is Ownable, HasSignature, TimelockController{
address paymentErc20, address paymentErc20,
uint256 saltNonce, uint256 saltNonce,
bytes calldata signature bytes calldata signature
) external onlyOwner { ) external onlyOwner signatureValid(signature){
require( require(
!userAddress.isContract(), !userAddress.isContract(),
"BEBoxPayment: Only user address is allowed to buy box" "BEBoxPayment: Only user address is allowed to buy box"
); );
require(_type > 0, "BEBoxPayment: Invalid box type"); require(_type > 0, "BEBoxPayment: Invalid box type");
require(price > 0, "BEBoxPayment: Invalid payment amount"); require(price > 0, "BEBoxPayment: Invalid payment amount");
require(
!usedSignatures[signature],
"BEBoxPayment: signature used. please send another transaction with new signature"
);
bytes32 criteriaMessageHash = getMessageHash( bytes32 criteriaMessageHash = getMessageHash(
_type, _type,
paymentErc20, paymentErc20,
@ -97,7 +92,7 @@ contract BEBoxMall is Ownable, HasSignature, TimelockController{
paymentReceivedAddress, paymentReceivedAddress,
price price
); );
usedSignatures[signature] = true; useSignature(signature);
// Emit payment event // Emit payment event
emit BEBoxPaid(boxId, userAddress, _type, price, paymentErc20); emit BEBoxPaid(boxId, userAddress, _type, price, paymentErc20);
} }

View File

@ -81,11 +81,7 @@ contract MarketPlace is Ownable, HasSignature {
address[2] calldata addresses, address[2] calldata addresses,
uint256[3] calldata values, uint256[3] calldata values,
bytes calldata signature bytes calldata signature
) external { ) external signatureValid(signature){
require(
!usedSignatures[signature],
"Marketplace: this signature has added to ignore list already"
);
bytes32 criteriaMessageHash = getMessageHash( bytes32 criteriaMessageHash = getMessageHash(
addresses[0], addresses[0],
values[0], values[0],
@ -95,8 +91,7 @@ contract MarketPlace is Ownable, HasSignature {
); );
checkSigner(_msgSender(), criteriaMessageHash, signature); checkSigner(_msgSender(), criteriaMessageHash, signature);
useSignature(signature);
usedSignatures[signature] = true;
} }
/** /**
@ -106,7 +101,7 @@ contract MarketPlace is Ownable, HasSignature {
address[3] calldata addresses, address[3] calldata addresses,
uint256[3] calldata values, uint256[3] calldata values,
bytes calldata signature bytes calldata signature
) external returns (bool) { ) external signatureValid(signature) returns (bool) {
// address[3] [seller_address,nft_address,payment_token_address] // address[3] [seller_address,nft_address,payment_token_address]
// uint256[3] [token_id,price,salt_nonce] // uint256[3] [token_id,price,salt_nonce]
// bytes seller_signature // bytes seller_signature
@ -115,11 +110,6 @@ contract MarketPlace is Ownable, HasSignature {
"Marketplace: invalid payment method" "Marketplace: invalid payment method"
); );
require(
!usedSignatures[signature],
"Marketplace: signature used. please send another transaction with new signature"
);
bytes32 criteriaMessageHash = getMessageHash( bytes32 criteriaMessageHash = getMessageHash(
addresses[1], addresses[1],
values[0], values[0],
@ -167,7 +157,7 @@ contract MarketPlace is Ownable, HasSignature {
// transfer item to buyer // transfer item to buyer
nft.safeTransferFrom(addresses[0], _msgSender(), values[0]); nft.safeTransferFrom(addresses[0], _msgSender(), values[0]);
usedSignatures[signature] = true; useSignature(signature);
// emit sale event // emit sale event
emitEvent(addresses, values); emitEvent(addresses, values);
return true; return true;

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "@openzeppelin/contracts/access/Ownable.sol";
contract Approval is Ownable {
mapping(address => bool) private approvalLists;
/**
* @dev Allow operation to reverse signature.
*/
function addApprovalList(address user) external onlyOwner {
require(!approvalLists[user], "MinterFactory: Invalid user address");
approvalLists[user] = true;
}
/**
* @dev Remove operation from approval list.
*/
function removeApprovalList(address user) external onlyOwner {
approvalLists[user] = false;
}
modifier approvaled() {
require(
_msgSender() == address(this) || approvalLists[_msgSender()],
"Must be valid approval list"
);
_;
}
}

View File

@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "@openzeppelin/contracts/access/Ownable.sol";
contract TimeChecker is Ownable {
mapping(address => bool) private approvalLists;
uint256 private _duration;
constructor() {
_duration = 1 days;
}
modifier timeValid(uint256 time) {
require(
time + _duration >= block.timestamp,
"expired, please send another transaction with new signature"
);
_;
}
/**
* @dev Returns the max duration for function called by user
*/
function getDuration() external view
returns (uint256 duration) {
return _duration;
}
/**
* @dev Change duration value
*/
function updateDuation(uint256 valNew) external onlyOwner {
_duration = valNew;
}
}