Last active
September 14, 2022 03:46
-
-
Save ponyjackal/5e607db31e7b219cdd2595dd90ffc9f1 to your computer and use it in GitHub Desktop.
LazyMint using EIP712 - smart contract
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.12; | |
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; | |
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | |
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; | |
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; | |
import "@openzeppelin/contracts-upgradeable/token/common/ERC2981Upgradeable.sol"; | |
import "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol"; | |
import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; | |
import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; | |
import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol"; | |
import "erc721a-upgradeable/contracts/ERC721AUpgradeable.sol"; | |
import "@tableland/evm/contracts/ITablelandTables.sol"; | |
import "hardhat/console.sol"; | |
contract LazyMint is | |
Initializable, | |
ReentrancyGuardUpgradeable, | |
OwnableUpgradeable, | |
PausableUpgradeable, | |
ERC721AUpgradeable, | |
ERC721HolderUpgradeable, | |
ERC2981Upgradeable, | |
EIP712Upgradeable | |
{ | |
uint256 public constant TOTAL_SUPPLY = 15000; | |
uint256 public constant MINT_FEE = 0; | |
uint96 public constant ROYALTY_FEE = 1000; | |
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); | |
string private constant SIGNING_DOMAIN = "LazyMintVoucher"; | |
string private constant SIGNATURE_VERSION = "1"; | |
struct LazyMintVoucher { | |
address receiver; | |
bytes16[] displayTypes; | |
bytes16[] traitTypes; | |
bytes16[] values; | |
bytes signature; | |
} | |
// ----------------------------------------- | |
// LazyMint Events | |
// ----------------------------------------- | |
event LazyMint( | |
address indexed to, | |
uint256 tokenId, | |
bytes16[] displayTypes, | |
bytes16[] indexed traitTypes, | |
bytes16[] values | |
); | |
// ----------------------------------------- | |
// LazyMint Initializer | |
// ----------------------------------------- | |
/** | |
* @dev Initializer function | |
* @param _baseURIString Base URI | |
* @param _description Description | |
* @param _image Image | |
* @param _externalURL External URL | |
* @param _royaltyReceiver Royalty receiver address | |
*/ | |
function initialize( | |
string memory _baseURIString, | |
string memory _description, | |
string memory _image, | |
string memory _externalURL, | |
address payable _royaltyReceiver | |
) external initializerERC721A initializer { | |
__Context_init(); | |
__Ownable_init(); | |
__ReentrancyGuard_init(); | |
__Pausable_init(); | |
__ERC721A_init("Lazy Mint", "LMint"); | |
__ERC721Holder_init(); | |
__ERC2981_init(); | |
__EIP712_init(SIGNING_DOMAIN, SIGNATURE_VERSION); | |
// Use ERC2981 to set royalty receiver and fee | |
_setDefaultRoyalty(_royaltyReceiver, ROYALTY_FEE); | |
} | |
// ----------------------------------------- | |
// LazyMint Mutative Functions | |
// ----------------------------------------- | |
/** | |
* @dev game server mints assets to the user | |
* @param _voucher The LazyMintVoucher | |
*/ | |
function lazyMint(LazyMintVoucher calldata _voucher) external nonContract { | |
address signer = _verify(_voucher); | |
require(_voucher.traitTypes.length == _voucher.values.length, "LazyMint: invalid arguments"); | |
require(signer == gameServer, "LazyMint: invalid signature"); | |
require(msg.sender == _voucher.receiver, "LazyMint: invalid receiver"); | |
_mint(_voucher.receiver, 1); | |
emit LazyMint(_voucher.receiver, tokenId, _voucher.displayTypes, _voucher.traitTypes, _voucher.values); | |
} | |
function supportsInterface(bytes4 interfaceId) | |
public | |
view | |
override(ERC721AUpgradeable, ERC2981Upgradeable) | |
returns (bool) | |
{ | |
return super.supportsInterface(interfaceId); | |
} | |
// ----------------------------------------- | |
// LazyMint Internal Functions | |
// ----------------------------------------- | |
function _bytes16ToString(bytes16 _bytes16) internal pure returns (string memory) { | |
uint8 i = 0; | |
while (i < 16 && _bytes16[i] != 0) { | |
i++; | |
} | |
bytes memory bytesArray = new bytes(i); | |
for (i = 0; i < 16 && _bytes16[i] != 0; i++) { | |
bytesArray[i] = _bytes16[i]; | |
} | |
return string(bytesArray); | |
} | |
/** | |
* @dev return a hash of the given LazyMintVoucher | |
*/ | |
function _hash(LazyMintVoucher calldata _voucher) internal view returns (bytes32) { | |
return | |
_hashTypedDataV4( | |
keccak256( | |
abi.encode( | |
keccak256( | |
"LazyMintVoucher(address receiver,bytes16[] displayTypes,bytes16[] traitTypes,bytes16[] values)" | |
), | |
_voucher.receiver, | |
keccak256(abi.encodePacked(_voucher.displayTypes)), | |
keccak256(abi.encodePacked(_voucher.traitTypes)), | |
keccak256(abi.encodePacked(_voucher.values)) | |
) | |
) | |
); | |
} | |
/** | |
* @dev verify the signature of a given LazyMintVoucher | |
* @param _voucher LazyMintVoucher | |
*/ | |
function _verify(LazyMintVoucher calldata _voucher) internal view returns (address) { | |
bytes32 digest = _hash(_voucher); | |
return ECDSAUpgradeable.recover(digest, _voucher.signature); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment