文件 1 的 8:Context.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 2 的 8:EnumerableSet.sol
pragma solidity >=0.6.0 <0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping (bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
bytes32 lastvalue = set._values[lastIndex];
set._values[toDeleteIndex] = lastvalue;
set._indexes[lastvalue] = toDeleteIndex + 1;
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
require(set._values.length > index, "EnumerableSet: index out of bounds");
return set._values[index];
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
}
文件 3 的 8:IERC165.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 4 的 8:IERC20.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 5 的 8:IERC721.sol
pragma solidity >=0.6.2 <0.8.0;
import "../../introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}
文件 6 的 8:IRNG.sol
pragma solidity ^0.7.0;
abstract contract IRNG {
function requestRandomNumber() external virtual returns (bytes32 requestId);
function requestRandomNumberWithCallback()
external
virtual
returns (bytes32);
function isRequestComplete(bytes32 requestId)
external
view
virtual
returns (bool isCompleted);
function randomNumber(bytes32 requestId)
external
view
virtual
returns (uint256 randomNum);
}
文件 7 的 8:LameloDrop.sol
pragma solidity >=0.6.0 <0.8.0;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/EnumerableSet.sol";
import "./interfaces/IRNG.sol";
contract LameloDrop is Ownable {
uint8 constant PoolIds_RED_MARS = 1;
uint8 constant PoolIds_BLUE_NEPTUNE = 2;
uint8 constant PoolIds_SILVER = 3;
mapping(uint8 => mapping(uint16 => uint16)) public participantingIdsPerPool;
mapping(uint8 => uint16) public poolCount;
mapping(uint16 => uint8) internal tokenData;
bytes32 public requestHash;
bool public canResolve = false;
bool public resolved = false;
uint256 public random = 0;
bool public hasPrizes = false;
IERC721 public lameloContract;
IRNG public rnd;
uint256 public startTime;
uint256 public endTime;
address public winner_address_RED_MARS;
address public winner_address_BLUE_NEPTUNE;
address public winner_address_SILVER;
constructor(
address _LBCAddress,
address _rndContractAddress,
uint256 _startTime,
uint256 _endTime
) {
lameloContract = IERC721(_LBCAddress);
rnd = IRNG(_rndContractAddress);
startTime = _startTime;
endTime = _endTime;
}
function onERC721Received(
address,
address,
uint256 receivedTokenId,
bytes calldata
) external returns (bytes4) {
require(
msg.sender == address(lameloContract),
"Must be lameloContract address"
);
if (
receivedTokenId == 498 ||
receivedTokenId == 499 ||
receivedTokenId == 500
) {
if (
lameloContract.ownerOf(498) == address(this) &&
lameloContract.ownerOf(499) == address(this) &&
lameloContract.ownerOf(500) == address(this)
) {
hasPrizes = true;
}
return this.onERC721Received.selector;
}
revert("bad token received");
}
function registerForDrop(uint16[] calldata tokenIds) public {
require(hasPrizes, "Does not have prize tokens");
require(getTimestamp() > startTime, "Not started");
require(getTimestamp() < endTime, "Already ended");
for (uint16 i = 0; i < tokenIds.length; i++) {
uint16 thisId = tokenIds[i];
require(!isTokenUsed(thisId), "Already has a ticket");
require(thisId > 500, "Token id must be over 500");
uint8 poolId = 0;
if(500 < thisId && thisId <= 1500 ) {
poolId = PoolIds_SILVER;
} else if (1500 < thisId && thisId <= 3500 ) {
poolId = PoolIds_BLUE_NEPTUNE;
} else if (3500 < thisId ) {
poolId = PoolIds_RED_MARS;
}
poolCount[poolId]++;
participantingIdsPerPool[poolId][poolCount[poolId]] = thisId;
setTokenUsed(thisId);
}
}
function requestVRF() public onlyOwner {
require(getTimestamp() > endTime, "Not ended");
requestHash = rnd.requestRandomNumberWithCallback();
}
function process(uint256 _random, bytes32 _requestId) public {
require(msg.sender == address(rnd), "Unauthorised");
require(requestHash == _requestId, "Unauthorised");
require(!canResolve, "VRF already received");
require(!resolved, "Already resolved");
canResolve = true;
random = _random;
}
function resolveDrop() public onlyOwner {
require(canResolve, "NO VRF YET");
require(!resolved, "Already resolved");
require(getTimestamp() > endTime, "Already ended");
uint16 _index = uint16(random % poolCount[PoolIds_RED_MARS]) + 1;
uint16 winingTokenId = participantingIdsPerPool[PoolIds_RED_MARS][_index];
winner_address_RED_MARS = lameloContract.ownerOf(winingTokenId);
random = random >> 8;
_index = uint16(random % poolCount[PoolIds_BLUE_NEPTUNE]) + 1;
winingTokenId = participantingIdsPerPool[PoolIds_BLUE_NEPTUNE][_index];
winner_address_BLUE_NEPTUNE = lameloContract.ownerOf(winingTokenId);
random = random >> 8;
_index = uint16(random % poolCount[PoolIds_SILVER]) + 1;
winingTokenId = participantingIdsPerPool[PoolIds_SILVER][_index];
winner_address_SILVER = lameloContract.ownerOf(winingTokenId);
random = random >> 8;
resolved = true;
lameloContract.transferFrom(address(this), winner_address_RED_MARS, 498);
lameloContract.transferFrom(address(this), winner_address_BLUE_NEPTUNE, 499);
lameloContract.transferFrom(address(this), winner_address_SILVER, 500);
}
function recoverTokens() external onlyOwner {
require(hasPrizes, "Does not have prize tokens");
require(!canResolve, "VRF already received");
require(!resolved, "Already resolved");
lameloContract.transferFrom(address(this), msg.sender, 500);
lameloContract.transferFrom(address(this), msg.sender, 499);
lameloContract.transferFrom(address(this), msg.sender, 498);
}
function isTokenUsed(uint16 _position) public view returns (bool result) {
uint16 byteNum = uint16(_position / 8);
uint16 bitPos = uint8(_position - byteNum * 8);
if (tokenData[byteNum] == 0) return false;
return tokenData[byteNum] & (0x01 * 2**bitPos) != 0;
}
function setTokenUsed(uint16 _position) public {
uint16 byteNum = uint16(_position / 8);
uint16 bitPos = uint8(_position - byteNum * 8);
tokenData[byteNum] = uint8(tokenData[byteNum] | (2**bitPos));
}
function getUsedTokenData(uint8 _page, uint16 _perPage)
public
view
returns (uint8[] memory)
{
_perPage = _perPage / 8;
uint16 i = _perPage * _page;
uint16 max = i + (_perPage);
uint16 j = 0;
uint8[] memory retValues;
assembly {
mstore(retValues, _perPage)
}
while (i < max) {
retValues[j] = tokenData[i];
j++;
i++;
}
assembly {
mstore(0x40, msize())
}
return retValues;
}
function getStats() public view returns (
uint16[3] memory _poolCounts,
address[3] memory _winners,
uint8[] memory _tokenData
) {
_tokenData = getUsedTokenData(0, 10000);
_poolCounts = [
poolCount[PoolIds_RED_MARS],
poolCount[PoolIds_BLUE_NEPTUNE],
poolCount[PoolIds_SILVER]
];
_winners = [
winner_address_RED_MARS,
winner_address_BLUE_NEPTUNE,
winner_address_SILVER
];
}
function getTimestamp() public view virtual returns(uint256) {
return block.timestamp;
}
function retrieveERC20(address _tracker, uint256 amount)
external
onlyOwner
{
IERC20(_tracker).transfer(msg.sender, amount);
}
function retrieve721(address _tracker, uint256 id) external onlyOwner {
IERC721(_tracker).transferFrom(address(this), msg.sender, id);
}
}
文件 8 的 8:Ownable.sol
pragma solidity >=0.6.0 <0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), 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 {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
{
"compilationTarget": {
"contracts/LameloDrop.sol": "LameloDrop"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_LBCAddress","type":"address"},{"internalType":"address","name":"_rndContractAddress","type":"address"},{"internalType":"uint256","name":"_startTime","type":"uint256"},{"internalType":"uint256","name":"_endTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"canResolve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStats","outputs":[{"internalType":"uint16[3]","name":"_poolCounts","type":"uint16[3]"},{"internalType":"address[3]","name":"_winners","type":"address[3]"},{"internalType":"uint8[]","name":"_tokenData","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_page","type":"uint8"},{"internalType":"uint16","name":"_perPage","type":"uint16"}],"name":"getUsedTokenData","outputs":[{"internalType":"uint8[]","name":"","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasPrizes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_position","type":"uint16"}],"name":"isTokenUsed","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lameloContract","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"receivedTokenId","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":"uint8","name":"","type":"uint8"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"participantingIdsPerPool","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolCount","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_random","type":"uint256"},{"internalType":"bytes32","name":"_requestId","type":"bytes32"}],"name":"process","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"random","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"recoverTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"tokenIds","type":"uint16[]"}],"name":"registerForDrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requestVRF","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resolveDrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resolved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tracker","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"retrieve721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tracker","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"retrieveERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rnd","outputs":[{"internalType":"contract IRNG","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_position","type":"uint16"}],"name":"setTokenUsed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"winner_address_BLUE_NEPTUNE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"winner_address_RED_MARS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"winner_address_SILVER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]