文件 1 的 6:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 6:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 3 的 6:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_setOwner(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 4 的 6:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 5 的 6:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
文件 6 的 6:YokaiEthereumBridge.sol
pragma solidity ^0.8.6;
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
interface IYokaiMasks {
function mintMaskFromBridge(address _to, uint256 _mintIndex) external;
function ownerOf(uint256 tokenId) external returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
function tokenExists(uint256 _tokenId) external view returns (bool);
}
contract YokaiMasksEthereumBridge is IERC721Receiver, Ownable, ReentrancyGuard {
using SafeMath for uint256;
address public signerAddress;
address public yokaiMasksContract;
uint256 public constant MAX_ETH_SUPPLY = 2103;
uint256 public ethMaskCount = 0;
uint256 public ethPrice = 150000000000000000;
address public devAddr;
address public devAddr2 = 0xC780542ED2C6bD3Fb18BfE97C081480ee8315bA5;
mapping(address => mapping(uint256 => bool)) public processedNonces;
event SentToBridge(
address indexed from,
uint256 indexed mintIndex,
uint256 indexed date,
uint256 nonce,
bytes signature
);
event MaskClaimed(
address indexed to,
uint256 indexed mintIndex,
uint256 indexed date,
uint256 nonce,
bytes signature
);
constructor() {
signerAddress = 0x13cacbc303b5d45164e31E6b6d73c1c445b4BA52;
devAddr = msg.sender;
yokaiMasksContract = 0xFF4245b8Fd43f75476608a94768EbB29bb678c2C;
}
function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
function sendMaskToBridge(uint256 _mintIndex, uint256 _nonce, bytes calldata _signature) external {
address from = msg.sender;
bytes32 message = prefixed(keccak256(abi.encodePacked(
from,
_mintIndex,
_nonce
)));
require(recoverSigner(message, _signature) == signerAddress, 'Wrong signature');
require(processedNonces[from][_nonce] == false, 'Transfer already processed');
processedNonces[from][_nonce] = true;
IYokaiMasks(yokaiMasksContract).safeTransferFrom(msg.sender, address(this), _mintIndex);
emit SentToBridge(msg.sender, _mintIndex, block.timestamp, _nonce, _signature);
}
function claimMask(uint256 _mintIndex, uint256 _nonce, bytes calldata _signature) external {
address from = msg.sender;
bytes32 message = prefixed(keccak256(abi.encodePacked(
from,
_mintIndex,
_nonce
)));
require(recoverSigner(message, _signature) == signerAddress, 'Wrong signature');
require(processedNonces[from][_nonce] == false, 'Transfer already processed');
processedNonces[from][_nonce] = true;
if (
IYokaiMasks(yokaiMasksContract).tokenExists(_mintIndex) &&
IYokaiMasks(yokaiMasksContract).ownerOf(_mintIndex) == address(this)
) {
IYokaiMasks(yokaiMasksContract).safeTransferFrom(address(this), msg.sender, _mintIndex);
} else {
IYokaiMasks(yokaiMasksContract).mintMaskFromBridge(msg.sender, _mintIndex);
}
emit MaskClaimed(msg.sender, _mintIndex, block.timestamp, _nonce, _signature);
}
function mintEthMask(uint256 _numberOfMasks, uint256 _timestamp, bytes calldata _signature) public payable nonReentrant {
address from = msg.sender;
bytes32 message = prefixed(keccak256(abi.encodePacked(
from,
_numberOfMasks,
_timestamp
)));
require(recoverSigner(message, _signature) == signerAddress, 'Wrong signature');
require(ethMaskCount < MAX_ETH_SUPPLY, "Sale over");
require(ethMaskCount.add(_numberOfMasks) <= MAX_ETH_SUPPLY, "Over supply");
require(_numberOfMasks <= 10, "Max 10 masks per txn");
require(ethPrice.mul(_numberOfMasks) == msg.value, "Incorrect ETH value");
require(msg.value != 0, "No ETH sent");
uint256 fortyPercent = (msg.value).mul(40).div(100);
uint256 sixtyPercent = (msg.value).mul(60).div(100);
payable(devAddr).transfer(fortyPercent);
payable(devAddr2).transfer(sixtyPercent);
for (uint256 i = 0; i < _numberOfMasks; i++) {
uint256 mintIndex = 3001 - MAX_ETH_SUPPLY + ethMaskCount;
IYokaiMasks(yokaiMasksContract).mintMaskFromBridge(from, mintIndex);
ethMaskCount = ethMaskCount.add(1);
}
}
function prefixed(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(
'\x19Ethereum Signed Message:\n32',
hash
));
}
function recoverSigner(bytes32 message, bytes memory sig)
internal
pure
returns (address)
{
uint8 v;
bytes32 r;
bytes32 s;
(v, r, s) = splitSignature(sig);
return ecrecover(message, v, r, s);
}
function splitSignature(bytes memory sig)
internal
pure
returns (uint8, bytes32, bytes32)
{
require(sig.length == 65);
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
return (v, r, s);
}
function setSigner(address payable _signerAddress) external onlyOwner {
signerAddress = _signerAddress;
}
function setYokaiMasksContract(address _address) external onlyOwner {
yokaiMasksContract = _address;
}
function withdrawDevFunds() public onlyOwner nonReentrant {
payable(msg.sender).transfer(address(this).balance);
}
function setEthPrice(uint256 _newPrice) external onlyOwner {
ethPrice = _newPrice;
}
}
{
"compilationTarget": {
"contracts/YokaiEthereumBridge.sol": "YokaiMasksEthereumBridge"
},
"evmVersion": "berlin",
"libraries": {
":__CACHE_BREAKER__": "0x00000000d41867734bbee4c6863d9255b2b06ac1"
},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"mintIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"date","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"}],"name":"MaskClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"uint256","name":"mintIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"date","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"}],"name":"SentToBridge","type":"event"},{"inputs":[],"name":"MAX_ETH_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mintIndex","type":"uint256"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"claimMask","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"devAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"devAddr2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethMaskCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numberOfMasks","type":"uint256"},{"internalType":"uint256","name":"_timestamp","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"mintEthMask","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"processedNonces","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mintIndex","type":"uint256"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"sendMaskToBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPrice","type":"uint256"}],"name":"setEthPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_signerAddress","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setYokaiMasksContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawDevFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"yokaiMasksContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]