文件 1 的 1:Crates2020Locksmith.sol
pragma solidity ^0.6.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;
}
}
pragma solidity ^0.6.0;
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 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;
}
}
pragma solidity ^0.6.0;
library ECDSA {
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
if (signature.length != 65) {
revert("ECDSA: invalid signature length");
}
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
revert("ECDSA: invalid signature 's' value");
}
if (v != 27 && v != 28) {
revert("ECDSA: invalid signature 'v' value");
}
address signer = ecrecover(hash, v, r, s);
require(signer != address(0), "ECDSA: invalid signature");
return signer;
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
}
pragma solidity 0.6.8;
interface IERC20 {
event Transfer(
address indexed _from,
address indexed _to,
uint256 _value
);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value
);
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);
}
pragma solidity 0.6.8;
library Crates2020RNGLib {
struct Metadata {
uint256 tokenType;
uint256 tokenSubType;
uint256 model;
uint256 team;
uint256 tokenRarity;
uint256 label;
uint256 driver;
uint256 stat1;
uint256 stat2;
uint256 stat3;
uint256 counter;
}
uint256 constant CRATE_TIER_LEGENDARY = 0;
uint256 constant CRATE_TIER_EPIC = 1;
uint256 constant CRATE_TIER_RARE = 2;
uint256 constant CRATE_TIER_COMMON = 3;
uint256 internal constant _NF_FLAG = 1 << 255;
uint256 internal constant _SEASON_ID_2020 = 3;
uint256 internal constant _TYPE_ID_CAR = 1;
uint256 internal constant _TYPE_ID_DRIVER = 2;
uint256 internal constant _TYPE_ID_PART = 3;
uint256 internal constant _TYPE_ID_GEAR = 4;
uint256 internal constant _TYPE_ID_TYRES = 5;
uint256 internal constant _TEAM_ID_ALFA_ROMEO_RACING = 1;
uint256 internal constant _TEAM_ID_SCUDERIA_FERRARI = 2;
uint256 internal constant _TEAM_ID_HAAS_F1_TEAM = 3;
uint256 internal constant _TEAM_ID_MCLAREN_F1_TEAM = 4;
uint256 internal constant _TEAM_ID_MERCEDES_AMG_PETRONAS_MOTORSPORT = 5;
uint256 internal constant _TEAM_ID_SPSCORE_RACING_POINT_F1_TEAM = 6;
uint256 internal constant _TEAM_ID_ASTON_MARTIN_RED_BULL_RACING = 7;
uint256 internal constant _TEAM_ID_RENAULT_F1_TEAM = 8;
uint256 internal constant _TEAM_ID_RED_BULL_TORO_ROSSO_HONDA = 9;
uint256 internal constant _TEAM_ID_ROKIT_WILLIAMS_RACING = 10;
uint256 internal constant _DRIVER_ID_KIMI_RAIKKONEN = 7;
uint256 internal constant _DRIVER_ID_ANTONIO_GIOVINAZZI = 99;
uint256 internal constant _DRIVER_ID_SEBASTIAN_VETTEL = 5;
uint256 internal constant _DRIVER_ID_CHARLES_LECLERC = 16;
uint256 internal constant _DRIVER_ID_ROMAIN_GROSJEAN = 8;
uint256 internal constant _DRIVER_ID_KEVIN_MAGNUSSEN = 20;
uint256 internal constant _DRIVER_ID_LANDO_NORRIS = 4;
uint256 internal constant _DRIVER_ID_CARLOS_SAINZ = 55;
uint256 internal constant _DRIVER_ID_LEWIS_HAMILTON = 44;
uint256 internal constant _DRIVER_ID_VALTTERI_BOTTAS = 77;
uint256 internal constant _DRIVER_ID_SERGIO_PEREZ = 11;
uint256 internal constant _DRIVER_ID_LANCE_STROLL = 18;
uint256 internal constant _DRIVER_ID_PIERRE_GASLY = 10;
uint256 internal constant _DRIVER_ID_MAX_VERSTAPPEN = 33;
uint256 internal constant _DRIVER_ID_DANIEL_RICCIARDO = 3;
uint256 internal constant _DRIVER_ID_ALEXANDER_ALBON = 23;
uint256 internal constant _DRIVER_ID_DANIIL_KVYAT = 26;
uint256 internal constant _DRIVER_ID_GEORGE_RUSSEL = 63;
uint256 internal constant _DRIVER_ID_ESTEBAN_OCON = 31;
uint256 internal constant _DRIVER_ID_NICHOLAS_LATIFI = 6;
uint256 internal constant _RACING_STATS_T1_RARITY_1_MIN = 800;
uint256 internal constant _RACING_STATS_T1_RARITY_1_MAX = 900;
uint256 internal constant _RACING_STATS_T1_RARITY_2_MIN = 710;
uint256 internal constant _RACING_STATS_T1_RARITY_2_MAX = 810;
uint256 internal constant _RACING_STATS_T1_RARITY_3_MIN = 680;
uint256 internal constant _RACING_STATS_T1_RARITY_3_MAX = 780;
uint256 internal constant _RACING_STATS_T1_RARITY_4_MIN = 610;
uint256 internal constant _RACING_STATS_T1_RARITY_4_MAX = 710;
uint256 internal constant _RACING_STATS_T1_RARITY_5_MIN = 570;
uint256 internal constant _RACING_STATS_T1_RARITY_5_MAX = 680;
uint256 internal constant _RACING_STATS_T1_RARITY_6_MIN = 540;
uint256 internal constant _RACING_STATS_T1_RARITY_6_MAX = 650;
uint256 internal constant _RACING_STATS_T1_RARITY_7_MIN = 500;
uint256 internal constant _RACING_STATS_T1_RARITY_7_MAX = 580;
uint256 internal constant _RACING_STATS_T1_RARITY_8_MIN = 480;
uint256 internal constant _RACING_STATS_T1_RARITY_8_MAX = 550;
uint256 internal constant _RACING_STATS_T1_RARITY_9_MIN = 450;
uint256 internal constant _RACING_STATS_T1_RARITY_9_MAX = 540;
uint256 internal constant _RACING_STATS_T2_RARITY_1_MIN = 500;
uint256 internal constant _RACING_STATS_T2_RARITY_1_MAX = 600;
uint256 internal constant _RACING_STATS_T2_RARITY_2_MIN = 420;
uint256 internal constant _RACING_STATS_T2_RARITY_2_MAX = 520;
uint256 internal constant _RACING_STATS_T2_RARITY_3_MIN = 380;
uint256 internal constant _RACING_STATS_T2_RARITY_3_MAX = 480;
uint256 internal constant _RACING_STATS_T2_RARITY_4_MIN = 340;
uint256 internal constant _RACING_STATS_T2_RARITY_4_MAX = 440;
uint256 internal constant _RACING_STATS_T2_RARITY_5_MIN = 330;
uint256 internal constant _RACING_STATS_T2_RARITY_5_MAX = 430;
uint256 internal constant _RACING_STATS_T2_RARITY_6_MIN = 290;
uint256 internal constant _RACING_STATS_T2_RARITY_6_MAX = 390;
uint256 internal constant _RACING_STATS_T2_RARITY_7_MIN = 250;
uint256 internal constant _RACING_STATS_T2_RARITY_7_MAX = 350;
uint256 internal constant _RACING_STATS_T2_RARITY_8_MIN = 240;
uint256 internal constant _RACING_STATS_T2_RARITY_8_MAX = 340;
uint256 internal constant _RACING_STATS_T2_RARITY_9_MIN = 200;
uint256 internal constant _RACING_STATS_T2_RARITY_9_MAX = 300;
uint256 internal constant _RACING_STATS_T3_RARITY_1_MIN = 500;
uint256 internal constant _RACING_STATS_T3_RARITY_1_MAX = 600;
uint256 internal constant _RACING_STATS_T3_RARITY_2_MIN = 420;
uint256 internal constant _RACING_STATS_T3_RARITY_2_MAX = 520;
uint256 internal constant _RACING_STATS_T3_RARITY_3_MIN = 380;
uint256 internal constant _RACING_STATS_T3_RARITY_3_MAX = 480;
uint256 internal constant _RACING_STATS_T3_RARITY_4_MIN = 340;
uint256 internal constant _RACING_STATS_T3_RARITY_4_MAX = 440;
uint256 internal constant _RACING_STATS_T3_RARITY_5_MIN = 330;
uint256 internal constant _RACING_STATS_T3_RARITY_5_MAX = 430;
uint256 internal constant _RACING_STATS_T3_RARITY_6_MIN = 290;
uint256 internal constant _RACING_STATS_T3_RARITY_6_MAX = 390;
uint256 internal constant _RACING_STATS_T3_RARITY_7_MIN = 250;
uint256 internal constant _RACING_STATS_T3_RARITY_7_MAX = 350;
uint256 internal constant _RACING_STATS_T3_RARITY_8_MIN = 240;
uint256 internal constant _RACING_STATS_T3_RARITY_8_MAX = 340;
uint256 internal constant _RACING_STATS_T3_RARITY_9_MIN = 200;
uint256 internal constant _RACING_STATS_T3_RARITY_9_MAX = 300;
uint256 internal constant _TYPE_DROP_RATE_THRESH_COMPONENT = 82500;
uint256 internal constant _COMMON_CRATE_DROP_RATE_THRESH_COMMON = 98.899 * 1000;
uint256 internal constant _COMMON_CRATE_DROP_RATE_THRESH_RARE = 1 * 1000 + _COMMON_CRATE_DROP_RATE_THRESH_COMMON;
uint256 internal constant _COMMON_CRATE_DROP_RATE_THRESH_EPIC = 0.1 * 1000 + _COMMON_CRATE_DROP_RATE_THRESH_RARE;
uint256 internal constant _RARE_CRATE_DROP_RATE_THRESH_COMMON = 96.490 * 1000;
uint256 internal constant _RARE_CRATE_DROP_RATE_THRESH_RARE = 2.5 * 1000 + _RARE_CRATE_DROP_RATE_THRESH_COMMON;
uint256 internal constant _RARE_CRATE_DROP_RATE_THRESH_EPIC = 1 * 1000 + _RARE_CRATE_DROP_RATE_THRESH_RARE;
uint256 internal constant _EPIC_CRATE_DROP_RATE_THRESH_COMMON = 92.4 * 1000;
uint256 internal constant _EPIC_CRATE_DROP_RATE_THRESH_RARE = 5 * 1000 + _EPIC_CRATE_DROP_RATE_THRESH_COMMON;
uint256 internal constant _EPIC_CRATE_DROP_RATE_THRESH_EPIC = 2.5 * 1000 + _EPIC_CRATE_DROP_RATE_THRESH_RARE;
uint256 internal constant _LEGENDARY_CRATE_DROP_RATE_THRESH_COMMON = 84 * 1000;
uint256 internal constant _LEGENDARY_CRATE_DROP_RATE_THRESH_RARE = 10 * 1000 + _LEGENDARY_CRATE_DROP_RATE_THRESH_COMMON;
uint256 internal constant _LEGENDARY_CRATE_DROP_RATE_THRESH_EPIC = 5 * 1000 + _LEGENDARY_CRATE_DROP_RATE_THRESH_RARE;
function generateCrate(uint256 crateSeed, uint256 crateTier, uint256 counter) internal pure returns (uint256[] memory tokens) {
tokens = new uint256[](5);
if (crateTier == CRATE_TIER_COMMON) {
uint256 guaranteedRareDropIndex = crateSeed % 5;
for (uint256 i = 0; i != 5; ++i) {
uint256 tokenSeed = uint256(keccak256(abi.encodePacked(crateSeed, i)));
tokens[i] = _makeTokenId(
_generateMetadata(
tokenSeed,
crateTier,
counter,
i,
i == guaranteedRareDropIndex? CRATE_TIER_RARE: CRATE_TIER_COMMON
)
);
}
} else if (crateTier == CRATE_TIER_RARE) {
(
uint256 guaranteedRareDropIndex1,
uint256 guaranteedRareDropIndex2,
uint256 guaranteedRareDropIndex3
) = _generateThreeTokenIndices(crateSeed);
for (uint256 i = 0; i != 5; ++i) {
uint256 tokenSeed = uint256(keccak256(abi.encodePacked(crateSeed, i)));
tokens[i] = _makeTokenId(
_generateMetadata(
tokenSeed,
crateTier,
counter,
i,
(
i == guaranteedRareDropIndex1 ||
i == guaranteedRareDropIndex2 ||
i == guaranteedRareDropIndex3
) ? CRATE_TIER_RARE: CRATE_TIER_COMMON
)
);
}
} else if (crateTier == CRATE_TIER_EPIC) {
(
uint256 guaranteedRareDropIndex,
uint256 guaranteedEpicDropIndex
) = _generateTwoTokenIndices(crateSeed);
for (uint256 i = 0; i != 5; ++i) {
uint256 tokenSeed = uint256(keccak256(abi.encodePacked(crateSeed, i)));
uint256 minRarityTier = CRATE_TIER_COMMON;
if (i == guaranteedRareDropIndex) {
minRarityTier = CRATE_TIER_RARE;
} else if (i == guaranteedEpicDropIndex) {
minRarityTier = CRATE_TIER_EPIC;
}
tokens[i] = _makeTokenId(
_generateMetadata(
tokenSeed,
crateTier,
counter,
i,
minRarityTier
)
);
}
} else if (crateTier == CRATE_TIER_LEGENDARY) {
(
uint256 guaranteedRareDropIndex,
uint256 guaranteedLegendaryDropIndex
) = _generateTwoTokenIndices(crateSeed);
for (uint256 i = 0; i != 5; ++i) {
uint256 tokenSeed = uint256(keccak256(abi.encodePacked(crateSeed, i)));
uint256 minRarityTier = CRATE_TIER_COMMON;
if (i == guaranteedRareDropIndex) {
minRarityTier = CRATE_TIER_RARE;
} else if (i == guaranteedLegendaryDropIndex) {
minRarityTier = CRATE_TIER_LEGENDARY;
}
tokens[i] = _makeTokenId(
_generateMetadata(
tokenSeed,
crateTier,
counter,
i,
minRarityTier
)
);
}
} else {
revert("Crates2020RNG: wrong crate tier");
}
}
function _generateTwoTokenIndices(uint256 crateSeed) internal pure returns (uint256, uint256) {
uint256 firstIndex = crateSeed % 5;
return(
firstIndex,
(firstIndex + 1 + ((crateSeed >> 4) % 4)) % 5
);
}
function _generateThreeTokenIndices(uint256 crateSeed) internal pure returns (uint256, uint256, uint256) {
uint256 value = crateSeed % 10;
if (value == 0) return (2, 3, 4);
if (value == 1) return (1, 3, 4);
if (value == 2) return (1, 2, 4);
if (value == 3) return (1, 2, 3);
if (value == 4) return (0, 3, 4);
if (value == 5) return (0, 2, 4);
if (value == 6) return (0, 2, 3);
if (value == 7) return (0, 1, 4);
if (value == 8) return (0, 1, 3);
if (value == 9) return (0, 1, 2);
}
function _generateMetadata(
uint256 tokenSeed,
uint256 crateTier,
uint256 counter,
uint256 index,
uint256 minRarityTier
) private pure returns (Metadata memory metadata) {
(uint256 tokenType, uint256 tokenSubType) = _generateType(tokenSeed >> 4, index);
metadata.tokenType = tokenType;
if (tokenSubType != 0) {
metadata.tokenSubType = tokenSubType;
}
uint256 tokenRarity = _generateRarity(tokenSeed >> 41, crateTier, minRarityTier);
metadata.tokenRarity = tokenRarity;
if (tokenType == _TYPE_ID_CAR || tokenType == _TYPE_ID_DRIVER) {
if (tokenRarity > 3) {
metadata.model = _generateModel(tokenSeed >> 73);
} else {
uint256 team = _generateTeam(tokenSeed >> 73);
metadata.team = team;
if (tokenType == _TYPE_ID_DRIVER) {
metadata.driver = _generateDriver(tokenSeed >> 81, team);
}
}
}
(metadata.stat1, metadata.stat2, metadata.stat3) = _generateRacingStats(
tokenSeed >> 128,
tokenType,
tokenRarity
);
metadata.counter = counter + index;
}
function _generateType(uint256 seed, uint256 index)
private
pure
returns (uint256 tokenType, uint256 tokenSubType)
{
if (index == 0) {
tokenType = 1 + (seed % 2);
tokenSubType = 0;
} else {
uint256 seedling = seed % 100000;
if (seedling < _TYPE_DROP_RATE_THRESH_COMPONENT) {
uint256 componentTypeSeed = (seed >> 32) % 3;
if (componentTypeSeed == 1) {
tokenType = _TYPE_ID_GEAR;
tokenSubType = 1 + ((seed >> 34) % 4);
} else {
tokenType = _TYPE_ID_PART;
tokenSubType = 1 + ((seed >> 34) % 8);
}
} else {
tokenType = _TYPE_ID_TYRES;
tokenSubType = 1 + ((seed >> 32) % 5);
}
}
}
function _generateRarity(
uint256 seed,
uint256 crateTier,
uint256 minRarityTier
) private pure returns (uint256 tokenRarity) {
uint256 seedling = seed % 100000;
if (crateTier == CRATE_TIER_COMMON) {
if (minRarityTier == CRATE_TIER_COMMON && seedling < _COMMON_CRATE_DROP_RATE_THRESH_COMMON) {
return 7 + (seedling % 3);
}
if (seedling < _COMMON_CRATE_DROP_RATE_THRESH_RARE) {
return 4 + (seedling % 3);
}
if (seedling < _COMMON_CRATE_DROP_RATE_THRESH_EPIC) {
return 2 + (seedling % 2);
}
return 1;
}
if (crateTier == CRATE_TIER_RARE) {
if (minRarityTier == CRATE_TIER_COMMON && seedling < _RARE_CRATE_DROP_RATE_THRESH_COMMON) {
return 7 + (seedling % 3);
}
if (seedling < _RARE_CRATE_DROP_RATE_THRESH_RARE) {
return 4 + (seedling % 3);
}
if (seedling < _RARE_CRATE_DROP_RATE_THRESH_EPIC) {
return 2 + (seedling % 2);
}
return 1;
}
if (crateTier == CRATE_TIER_EPIC) {
if (minRarityTier == CRATE_TIER_COMMON && seedling < _EPIC_CRATE_DROP_RATE_THRESH_COMMON) {
return 7 + (seedling % 3);
}
if (
(minRarityTier == CRATE_TIER_COMMON || minRarityTier == CRATE_TIER_RARE)
&& seedling < _EPIC_CRATE_DROP_RATE_THRESH_RARE
) {
return 4 + (seedling % 3);
}
if (seedling < _EPIC_CRATE_DROP_RATE_THRESH_EPIC) {
return 2 + (seedling % 2);
}
return 1;
}
if (crateTier == CRATE_TIER_LEGENDARY) {
if (minRarityTier == CRATE_TIER_COMMON && seedling < _LEGENDARY_CRATE_DROP_RATE_THRESH_COMMON) {
return 7 + (seedling % 3);
}
if (minRarityTier == CRATE_TIER_COMMON || minRarityTier == CRATE_TIER_RARE) {
if (seedling < _LEGENDARY_CRATE_DROP_RATE_THRESH_RARE) {
return 4 + (seedling % 3);
}
if (seedling < _LEGENDARY_CRATE_DROP_RATE_THRESH_EPIC) {
return 2 + (seedling % 2);
}
}
return 1;
}
}
function _generateModel(uint256 seed) private pure returns (uint256 model) {
model = 1 + (seed % 10);
}
function _generateTeam(uint256 seed) private pure returns (uint256 team) {
team = 1 + (seed % 10);
}
function _generateDriver(uint256 seed, uint256 team) private pure returns (uint256 driver) {
uint256 index = (seed) % 2;
if (team == _TEAM_ID_ALFA_ROMEO_RACING) {
driver = [
_DRIVER_ID_KIMI_RAIKKONEN,
_DRIVER_ID_ANTONIO_GIOVINAZZI
][index];
} else if (team == _TEAM_ID_SCUDERIA_FERRARI) {
driver = [
_DRIVER_ID_SEBASTIAN_VETTEL,
_DRIVER_ID_CHARLES_LECLERC
][index];
} else if (team == _TEAM_ID_HAAS_F1_TEAM) {
driver = [
_DRIVER_ID_ROMAIN_GROSJEAN,
_DRIVER_ID_KEVIN_MAGNUSSEN
][index];
} else if (team == _TEAM_ID_MCLAREN_F1_TEAM) {
driver = [
_DRIVER_ID_LANDO_NORRIS,
_DRIVER_ID_CARLOS_SAINZ
][index];
} else if (team == _TEAM_ID_MERCEDES_AMG_PETRONAS_MOTORSPORT) {
driver = [
_DRIVER_ID_LEWIS_HAMILTON,
_DRIVER_ID_VALTTERI_BOTTAS
][index];
} else if (team == _TEAM_ID_SPSCORE_RACING_POINT_F1_TEAM) {
driver = [
_DRIVER_ID_SERGIO_PEREZ,
_DRIVER_ID_LANCE_STROLL
][index];
} else if (team == _TEAM_ID_ASTON_MARTIN_RED_BULL_RACING) {
driver = [
_DRIVER_ID_ALEXANDER_ALBON,
_DRIVER_ID_MAX_VERSTAPPEN
][index];
} else if (team == _TEAM_ID_RENAULT_F1_TEAM) {
driver = [
_DRIVER_ID_DANIEL_RICCIARDO,
_DRIVER_ID_ESTEBAN_OCON
][index];
} else if (team == _TEAM_ID_RED_BULL_TORO_ROSSO_HONDA) {
driver = [
_DRIVER_ID_PIERRE_GASLY,
_DRIVER_ID_DANIIL_KVYAT
][index];
} else if (team == _TEAM_ID_ROKIT_WILLIAMS_RACING) {
driver = [
_DRIVER_ID_GEORGE_RUSSEL,
_DRIVER_ID_NICHOLAS_LATIFI
][index];
}
}
function _generateRacingStats(
uint256 seed,
uint256 tokenType,
uint256 tokenRarity
)
private
pure
returns (
uint256 stat1,
uint256 stat2,
uint256 stat3
)
{
uint256 min;
uint256 max;
if (tokenType == _TYPE_ID_CAR || tokenType == _TYPE_ID_DRIVER) {
if (tokenRarity == 1) {
(min, max) = (_RACING_STATS_T1_RARITY_1_MIN, _RACING_STATS_T1_RARITY_1_MAX);
} else if (tokenRarity == 2) {
(min, max) = (_RACING_STATS_T1_RARITY_2_MIN, _RACING_STATS_T1_RARITY_2_MAX);
} else if (tokenRarity == 3) {
(min, max) = (_RACING_STATS_T1_RARITY_3_MIN, _RACING_STATS_T1_RARITY_3_MAX);
} else if (tokenRarity == 4) {
(min, max) = (_RACING_STATS_T1_RARITY_4_MIN, _RACING_STATS_T1_RARITY_4_MAX);
} else if (tokenRarity == 5) {
(min, max) = (_RACING_STATS_T1_RARITY_5_MIN, _RACING_STATS_T1_RARITY_5_MAX);
} else if (tokenRarity == 6) {
(min, max) = (_RACING_STATS_T1_RARITY_6_MIN, _RACING_STATS_T1_RARITY_6_MAX);
} else if (tokenRarity == 7) {
(min, max) = (_RACING_STATS_T1_RARITY_7_MIN, _RACING_STATS_T1_RARITY_7_MAX);
} else if (tokenRarity == 8) {
(min, max) = (_RACING_STATS_T1_RARITY_8_MIN, _RACING_STATS_T1_RARITY_8_MAX);
} else if (tokenRarity == 9) {
(min, max) = (_RACING_STATS_T1_RARITY_9_MIN, _RACING_STATS_T1_RARITY_9_MAX);
} else {
revert("Wrong token rarity");
}
} else if (tokenType == _TYPE_ID_GEAR || tokenType == _TYPE_ID_PART) {
if (tokenRarity == 1) {
(min, max) = (_RACING_STATS_T2_RARITY_1_MIN, _RACING_STATS_T2_RARITY_1_MAX);
} else if (tokenRarity == 2) {
(min, max) = (_RACING_STATS_T2_RARITY_2_MIN, _RACING_STATS_T2_RARITY_2_MAX);
} else if (tokenRarity == 3) {
(min, max) = (_RACING_STATS_T2_RARITY_3_MIN, _RACING_STATS_T2_RARITY_3_MAX);
} else if (tokenRarity == 4) {
(min, max) = (_RACING_STATS_T2_RARITY_4_MIN, _RACING_STATS_T2_RARITY_4_MAX);
} else if (tokenRarity == 5) {
(min, max) = (_RACING_STATS_T2_RARITY_5_MIN, _RACING_STATS_T2_RARITY_5_MAX);
} else if (tokenRarity == 6) {
(min, max) = (_RACING_STATS_T2_RARITY_6_MIN, _RACING_STATS_T2_RARITY_6_MAX);
} else if (tokenRarity == 7) {
(min, max) = (_RACING_STATS_T2_RARITY_7_MIN, _RACING_STATS_T2_RARITY_7_MAX);
} else if (tokenRarity == 8) {
(min, max) = (_RACING_STATS_T2_RARITY_8_MIN, _RACING_STATS_T2_RARITY_8_MAX);
} else if (tokenRarity == 9) {
(min, max) = (_RACING_STATS_T2_RARITY_9_MIN, _RACING_STATS_T2_RARITY_9_MAX);
} else {
revert("Wrong token rarity");
}
} else if (tokenType == _TYPE_ID_TYRES) {
if (tokenRarity == 1) {
(min, max) = (_RACING_STATS_T3_RARITY_1_MIN, _RACING_STATS_T3_RARITY_1_MAX);
} else if (tokenRarity == 2) {
(min, max) = (_RACING_STATS_T3_RARITY_2_MIN, _RACING_STATS_T3_RARITY_2_MAX);
} else if (tokenRarity == 3) {
(min, max) = (_RACING_STATS_T3_RARITY_3_MIN, _RACING_STATS_T3_RARITY_3_MAX);
} else if (tokenRarity == 4) {
(min, max) = (_RACING_STATS_T3_RARITY_4_MIN, _RACING_STATS_T3_RARITY_4_MAX);
} else if (tokenRarity == 5) {
(min, max) = (_RACING_STATS_T3_RARITY_5_MIN, _RACING_STATS_T3_RARITY_5_MAX);
} else if (tokenRarity == 6) {
(min, max) = (_RACING_STATS_T3_RARITY_6_MIN, _RACING_STATS_T3_RARITY_6_MAX);
} else if (tokenRarity == 7) {
(min, max) = (_RACING_STATS_T3_RARITY_7_MIN, _RACING_STATS_T3_RARITY_7_MAX);
} else if (tokenRarity == 8) {
(min, max) = (_RACING_STATS_T3_RARITY_8_MIN, _RACING_STATS_T3_RARITY_8_MAX);
} else if (tokenRarity == 9) {
(min, max) = (_RACING_STATS_T3_RARITY_9_MIN, _RACING_STATS_T3_RARITY_9_MAX);
} else {
revert("Wrong token rarity");
}
} else {
revert("Wrong token type");
}
uint256 delta = max - min;
stat1 = min + (seed % delta);
stat2 = min + ((seed >> 16) % delta);
stat3 = min + ((seed >> 32) % delta);
}
function _makeTokenId(Metadata memory metadata) private pure returns (uint256 tokenId) {
tokenId = _NF_FLAG;
tokenId |= (metadata.tokenType << 240);
tokenId |= (metadata.tokenSubType << 232);
tokenId |= (_SEASON_ID_2020 << 224);
tokenId |= (metadata.model << 192);
tokenId |= (metadata.team << 184);
tokenId |= (metadata.tokenRarity << 176);
tokenId |= (metadata.label << 152);
tokenId |= (metadata.driver << 136);
tokenId |= (metadata.stat1 << 120);
tokenId |= (metadata.stat2 << 104);
tokenId |= (metadata.stat3 << 88);
tokenId |= metadata.counter;
}
}
pragma solidity ^0.6.8;
interface IF1DTBurnableCrateKey {
function burn(uint256 amount) external;
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transferOwnership(address newOwner) external;
}
interface IF1DTInventory {
function batchMint(address[] calldata to, uint256[] calldata ids, bytes32[] calldata uris, uint256[] calldata values, bool safe) external;
}
contract Crates2020 is Ownable {
using Crates2020RNGLib for uint256;
IF1DTInventory immutable public INVENTORY;
IF1DTBurnableCrateKey immutable public CRATE_KEY_COMMON;
IF1DTBurnableCrateKey immutable public CRATE_KEY_RARE;
IF1DTBurnableCrateKey immutable public CRATE_KEY_EPIC;
IF1DTBurnableCrateKey immutable public CRATE_KEY_LEGENDARY;
uint256 public counter;
constructor(
IF1DTInventory INVENTORY_,
IF1DTBurnableCrateKey CRATE_KEY_COMMON_,
IF1DTBurnableCrateKey CRATE_KEY_RARE_,
IF1DTBurnableCrateKey CRATE_KEY_EPIC_,
IF1DTBurnableCrateKey CRATE_KEY_LEGENDARY_,
uint256 counter_
) public {
require(
address(INVENTORY_) != address(0) &&
address(CRATE_KEY_COMMON_) != address(0) &&
address(CRATE_KEY_EPIC_) != address(0) &&
address(CRATE_KEY_LEGENDARY_) != address(0),
"Crates: zero address"
);
INVENTORY = INVENTORY_;
CRATE_KEY_COMMON = CRATE_KEY_COMMON_;
CRATE_KEY_RARE = CRATE_KEY_RARE_;
CRATE_KEY_EPIC = CRATE_KEY_EPIC_;
CRATE_KEY_LEGENDARY = CRATE_KEY_LEGENDARY_;
counter = counter_;
}
function transferCrateKeyOwnership(uint256 crateTier, address newOwner) external onlyOwner {
IF1DTBurnableCrateKey crateKey = _getCrateKey(crateTier);
crateKey.transferOwnership(newOwner);
}
function _openCrates(uint256 crateTier, uint256 quantity, uint256 seed) internal {
require(quantity != 0, "Crates: zero quantity");
IF1DTBurnableCrateKey crateKey = _getCrateKey(crateTier);
address sender = _msgSender();
uint256 amount = quantity * 1000000000000000000;
crateKey.transferFrom(sender, address(this), amount);
crateKey.burn(amount);
bytes32[] memory uris = new bytes32[](5);
uint256[] memory values = new uint256[](5);
address[] memory to = new address[](5);
for (uint256 i; i != 5; ++i) {
values[i] = 1;
to[i] = sender;
}
uint256 counter_ = counter;
for (uint256 i; i != quantity; ++i) {
if (i != 0) {
seed = uint256(keccak256(abi.encode(seed)));
}
uint256[] memory tokens = seed.generateCrate(crateTier, counter_);
INVENTORY.batchMint(to, tokens, uris, values, false);
counter_ += 5;
}
counter = counter_;
}
function _getCrateKey(uint256 crateTier) view internal returns (IF1DTBurnableCrateKey) {
if (crateTier == Crates2020RNGLib.CRATE_TIER_COMMON) {
return CRATE_KEY_COMMON;
} else if (crateTier == Crates2020RNGLib.CRATE_TIER_RARE) {
return CRATE_KEY_RARE;
} else if (crateTier == Crates2020RNGLib.CRATE_TIER_EPIC) {
return CRATE_KEY_EPIC;
} else if (crateTier == Crates2020RNGLib.CRATE_TIER_LEGENDARY) {
return CRATE_KEY_LEGENDARY;
} else {
revert("Crates: wrong crate tier");
}
}
}
pragma solidity ^0.6.8;
contract Crates2020Locksmith is Crates2020 {
using ECDSA for bytes32;
mapping(address => mapping(uint256 => uint256)) public nonces;
address public signerKey;
constructor(
IF1DTInventory INVENTORY_,
IF1DTBurnableCrateKey COMMON_CRATE_,
IF1DTBurnableCrateKey RARE_CRATE_,
IF1DTBurnableCrateKey EPIC_CRATE_,
IF1DTBurnableCrateKey LEGENDARY_CRATE_,
uint256 counter_
) public Crates2020(INVENTORY_, COMMON_CRATE_, RARE_CRATE_, EPIC_CRATE_, LEGENDARY_CRATE_, counter_) {}
function setSignerKey(address signerKey_) external onlyOwner {
signerKey = signerKey_;
}
function insertKeys(uint256 crateTier, uint256 quantity, bytes calldata sig) external {
require(crateTier <= Crates2020RNGLib.CRATE_TIER_COMMON, "Locksmith: wrong crate tier");
require(quantity <= 5, "Locksmith: above max quantity");
address signerKey_ = signerKey;
require(signerKey_ != address(0), "Locksmith: signer key not set");
address sender = _msgSender();
uint256 nonce = nonces[sender][crateTier];
bytes32 hash_ = keccak256(abi.encode(sender, crateTier, nonce));
require(hash_.toEthSignedMessageHash().recover(sig) == signerKey_, "Locksmith: invalid signature");
uint256 seed = uint256(keccak256(sig));
_openCrates(crateTier, quantity, seed);
nonces[sender][crateTier] = nonce + 1;
}
}