文件 1 的 30:Address.sol
pragma solidity ^0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 30:Base64.sol
pragma solidity ^0.8.0;
library Base64 {
string internal constant TABLE =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function encode(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return "";
string memory table = TABLE;
uint256 encodedLen = 4 * ((data.length + 2) / 3);
string memory result = new string(encodedLen + 32);
assembly {
mstore(result, encodedLen)
let tablePtr := add(table, 1)
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
let resultPtr := add(result, 32)
for {
} lt(dataPtr, endPtr) {
} {
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(shr(18, input), 0x3F))))
)
resultPtr := add(resultPtr, 1)
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(shr(12, input), 0x3F))))
)
resultPtr := add(resultPtr, 1)
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(shr(6, input), 0x3F))))
)
resultPtr := add(resultPtr, 1)
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(input, 0x3F))))
)
resultPtr := add(resultPtr, 1)
}
switch mod(mload(data), 3)
case 1 {
mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
}
case 2 {
mstore(sub(resultPtr, 1), shl(248, 0x3d))
}
}
return result;
}
}
文件 3 的 30:BaseTokenURIProvider.sol
pragma solidity ^0.8.0;
import "./ITokenURIProvider.sol";
import "./OpenSeaMetadata.sol";
import "./ChainScoutsExtension.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
abstract contract BaseTokenURIProvider is ITokenURIProvider, ChainScoutsExtension {
string private baseName;
string private defaultDescription;
mapping (uint => string) private names;
mapping (uint => string) private descriptions;
constructor(string memory _baseName, string memory _defaultDescription) {
baseName = _baseName;
defaultDescription = _defaultDescription;
}
modifier stringIsJsonSafe(string memory str) {
bytes memory b = bytes(str);
for (uint i = 0; i < b.length; ++i) {
uint8 char = uint8(b[i]);
if (!(char >= 48 && char <= 57 || char >= 65 && char <= 90 || char >= 97 && char <= 122 || char == 32)) {
revert("BaseTokenURIProvider: All chars must be spaces or alphanumeric");
}
}
_;
}
function setDescription(uint tokenId, string memory description) external canAccessToken(tokenId) stringIsJsonSafe(description) {
descriptions[tokenId] = description;
}
function setName(uint tokenId, string memory name) external canAccessToken(tokenId) stringIsJsonSafe(name) {
names[tokenId] = name;
}
function tokenBgColor(uint tokenId) internal view virtual returns (uint24);
function tokenSvg(uint tokenId) public view virtual returns (string memory);
function tokenAttributes(uint tokenId) internal view virtual returns (Attribute[] memory);
function tokenURI(uint tokenId) external view override returns (string memory) {
string memory name = names[tokenId];
if (bytes(name).length == 0) {
name = string(abi.encodePacked(
baseName,
" #",
Strings.toString(tokenId)
));
}
string memory description = descriptions[tokenId];
if (bytes(description).length == 0) {
description = defaultDescription;
}
return OpenSeaMetadataLibrary.makeMetadata(OpenSeaMetadata(
tokenSvg(tokenId),
description,
name,
tokenBgColor(tokenId),
tokenAttributes(tokenId)
));
}
}
文件 4 的 30:ChainScoutMetadata.sol
pragma solidity ^0.8.0;
import "./Enums.sol";
struct KeyValuePair {
string key;
string value;
}
struct ChainScoutMetadata {
Accessory accessory;
BackAccessory backaccessory;
Background background;
Clothing clothing;
Eyes eyes;
Fur fur;
Head head;
Mouth mouth;
uint24 attack;
uint24 defense;
uint24 luck;
uint24 speed;
uint24 strength;
uint24 intelligence;
uint16 level;
}
文件 5 的 30:ChainScouts.sol
pragma solidity ^0.8.0;
import "./BaseTokenURIProvider.sol";
import "./ChainScoutMetadata.sol";
import "./ExtensibleERC721Enumerable.sol";
import "./Generator.sol";
import "./IChainScouts.sol";
import "./IUtilityERC20.sol";
import "./MerkleWhitelistERC721Enumerable.sol";
import "./Rng.sol";
contract ChainScouts is IChainScouts, MerkleWhitelistERC721Enumerable {
using RngLibrary for Rng;
mapping (string => ChainScoutsExtension) public extensions;
Rng private rng = RngLibrary.newRng();
mapping (uint => ChainScoutMetadata) internal tokenIdToMetadata;
uint private _mintPriceWei = 0.068 ether;
event MetadataChanged(uint tokenId);
constructor(Payee[] memory payees, bytes32 merkleRoot)
ERC721A("Chain Scouts", "CS")
MerkleWhitelistERC721Enumerable(
payees,
5,
6888,
3,
merkleRoot
) {}
function adminCreateChainScout(ChainScoutMetadata calldata tbd, address owner) external override onlyAdmin {
require(totalSupply() < maxSupply, "ChainScouts: totalSupply >= maxSupply");
uint tokenId = _currentIndex;
_mint(owner, 1, "", false);
tokenIdToMetadata[tokenId] = tbd;
}
function adminSetChainScoutMetadata(uint tokenId, ChainScoutMetadata calldata tbd) external override onlyAdmin {
tokenIdToMetadata[tokenId] = tbd;
emit MetadataChanged(tokenId);
}
function adminRemoveExtension(string calldata key) external override onlyAdmin {
delete extensions[key];
}
function adminSetExtension(string calldata key, ChainScoutsExtension extension) external override onlyAdmin {
extensions[key] = extension;
}
function adminSetMintPriceWei(uint max) external onlyAdmin {
_mintPriceWei = max;
}
function getChainScoutMetadata(uint tokenId) external view override returns (ChainScoutMetadata memory) {
return tokenIdToMetadata[tokenId];
}
function createMetadataForMintedToken(uint tokenId) internal override {
(tokenIdToMetadata[tokenId], rng) = Generator.getRandomMetadata(rng);
}
function tokenURI(uint tokenId) public override view returns (string memory) {
return BaseTokenURIProvider(address(extensions["tokenUri"])).tokenURI(tokenId);
}
function mintPriceWei() public view override returns (uint) {
return _mintPriceWei;
}
function whitelistMintAndStake(bytes32[] calldata proof, uint count) external payable returns (uint) {
uint start = whitelistMint(proof, count);
uint[] memory ids = new uint[](count);
for (uint i = 0; i < count; ++i) {
ids[i] = start + i;
}
IUtilityERC20(address(extensions["token"])).stake(ids);
return start;
}
function publicMintAndStake(uint count) external payable returns (uint) {
uint start = publicMint(count);
uint[] memory ids = new uint[](count);
for (uint i = 0; i < count; ++i) {
ids[i] = start + i;
}
IUtilityERC20(address(extensions["token"])).stake(ids);
return start;
}
}
文件 6 的 30:ChainScoutsExtension.sol
pragma solidity ^0.8.0;
import "./IChainScouts.sol";
abstract contract ChainScoutsExtension {
IChainScouts internal chainScouts;
bool public enabled = true;
modifier canAccessToken(uint tokenId) {
require(chainScouts.canAccessToken(msg.sender, tokenId), "ChainScoutsExtension: you don't own the token");
_;
}
modifier onlyAdmin() {
require(chainScouts.isAdmin(msg.sender), "ChainScoutsExtension: admins only");
_;
}
modifier whenEnabled() {
require(enabled, "ChainScoutsExtension: currently disabled");
_;
}
function adminSetEnabled(bool e) external onlyAdmin {
enabled = e;
}
function extensionKey() public virtual view returns (string memory);
function setChainScouts(IChainScouts _contract) external {
require(address(0) == address(chainScouts) || chainScouts.isAdmin(msg.sender), "ChainScoutsExtension: The Chain Scouts contract must not be set or you must be an admin");
chainScouts = _contract;
chainScouts.adminSetExtension(extensionKey(), this);
}
}
文件 7 的 30: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;
}
}
文件 8 的 30:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 9 的 30:ERC721A.sol
pragma solidity ^0.8.4;
import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol';
import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol';
import '@openzeppelin/contracts/utils/Address.sol';
import '@openzeppelin/contracts/utils/Context.sol';
import '@openzeppelin/contracts/utils/Strings.sol';
import '@openzeppelin/contracts/utils/introspection/ERC165.sol';
error ApprovalCallerNotOwnerNorApproved();
error ApprovalQueryForNonexistentToken();
error ApproveToCaller();
error ApprovalToCurrentOwner();
error BalanceQueryForZeroAddress();
error MintedQueryForZeroAddress();
error BurnedQueryForZeroAddress();
error MintToZeroAddress();
error MintZeroQuantity();
error OwnerIndexOutOfBounds();
error OwnerQueryForNonexistentToken();
error TokenIndexOutOfBounds();
error TransferCallerNotOwnerNorApproved();
error TransferFromIncorrectOwner();
error TransferToNonERC721ReceiverImplementer();
error TransferToZeroAddress();
error URIQueryForNonexistentToken();
contract ERC721A is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
using Address for address;
using Strings for uint256;
struct TokenOwnership {
address addr;
uint64 startTimestamp;
bool burned;
}
struct AddressData {
uint64 balance;
uint64 numberMinted;
uint64 numberBurned;
}
uint128 internal _currentIndex;
uint128 internal _burnCounter;
string private _name;
string private _symbol;
mapping(uint256 => TokenOwnership) internal _ownerships;
mapping(address => AddressData) private _addressData;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function totalSupply() public view override returns (uint256) {
unchecked {
return _currentIndex - _burnCounter;
}
}
function tokenByIndex(uint256 index) public view override returns (uint256) {
uint256 numMintedSoFar = _currentIndex;
uint256 tokenIdsIdx;
unchecked {
for (uint256 i; i < numMintedSoFar; i++) {
TokenOwnership memory ownership = _ownerships[i];
if (!ownership.burned) {
if (tokenIdsIdx == index) {
return i;
}
tokenIdsIdx++;
}
}
}
revert TokenIndexOutOfBounds();
}
function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) {
if (index >= balanceOf(owner)) revert OwnerIndexOutOfBounds();
uint256 numMintedSoFar = _currentIndex;
uint256 tokenIdsIdx;
address currOwnershipAddr;
unchecked {
for (uint256 i; i < numMintedSoFar; i++) {
TokenOwnership memory ownership = _ownerships[i];
if (ownership.burned) {
continue;
}
if (ownership.addr != address(0)) {
currOwnershipAddr = ownership.addr;
}
if (currOwnershipAddr == owner) {
if (tokenIdsIdx == index) {
return i;
}
tokenIdsIdx++;
}
}
}
revert();
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
interfaceId == type(IERC721Enumerable).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner) public view override returns (uint256) {
if (owner == address(0)) revert BalanceQueryForZeroAddress();
return uint256(_addressData[owner].balance);
}
function _numberMinted(address owner) internal view returns (uint256) {
if (owner == address(0)) revert MintedQueryForZeroAddress();
return uint256(_addressData[owner].numberMinted);
}
function _numberBurned(address owner) internal view returns (uint256) {
if (owner == address(0)) revert BurnedQueryForZeroAddress();
return uint256(_addressData[owner].numberBurned);
}
function ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) {
uint256 curr = tokenId;
unchecked {
if (curr < _currentIndex) {
TokenOwnership memory ownership = _ownerships[curr];
if (!ownership.burned) {
if (ownership.addr != address(0)) {
return ownership;
}
while (true) {
curr--;
ownership = _ownerships[curr];
if (ownership.addr != address(0)) {
return ownership;
}
}
}
}
}
revert OwnerQueryForNonexistentToken();
}
function ownerOf(uint256 tokenId) public view override returns (address) {
return ownershipOf(tokenId).addr;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
string memory baseURI = _baseURI();
return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : '';
}
function _baseURI() internal view virtual returns (string memory) {
return '';
}
function approve(address to, uint256 tokenId) public override {
address owner = ERC721A.ownerOf(tokenId);
if (to == owner) revert ApprovalToCurrentOwner();
if (_msgSender() != owner && !isApprovedForAll(owner, _msgSender())) {
revert ApprovalCallerNotOwnerNorApproved();
}
_approve(to, tokenId, owner);
}
function getApproved(uint256 tokenId) public view override returns (address) {
if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public override {
if (operator == _msgSender()) revert ApproveToCaller();
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, '');
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public virtual override {
_transfer(from, to, tokenId);
if (!_checkOnERC721Received(from, to, tokenId, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
}
function _exists(uint256 tokenId) internal view returns (bool) {
return tokenId < _currentIndex && !_ownerships[tokenId].burned;
}
function _safeMint(address to, uint256 quantity) internal {
_safeMint(to, quantity, '');
}
function _safeMint(
address to,
uint256 quantity,
bytes memory _data
) internal {
_mint(to, quantity, _data, true);
}
function _mint(
address to,
uint256 quantity,
bytes memory _data,
bool safe
) internal {
uint256 startTokenId = _currentIndex;
if (to == address(0)) revert MintToZeroAddress();
if (quantity == 0) revert MintZeroQuantity();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
unchecked {
_addressData[to].balance += uint64(quantity);
_addressData[to].numberMinted += uint64(quantity);
_ownerships[startTokenId].addr = to;
_ownerships[startTokenId].startTimestamp = uint64(block.timestamp);
uint256 updatedIndex = startTokenId;
for (uint256 i; i < quantity; i++) {
emit Transfer(address(0), to, updatedIndex);
if (safe && !_checkOnERC721Received(address(0), to, updatedIndex, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
updatedIndex++;
}
_currentIndex = uint128(updatedIndex);
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
function _transfer(
address from,
address to,
uint256 tokenId
) private {
TokenOwnership memory prevOwnership = ownershipOf(tokenId);
bool isApprovedOrOwner = (_msgSender() == prevOwnership.addr ||
isApprovedForAll(prevOwnership.addr, _msgSender()) ||
getApproved(tokenId) == _msgSender());
if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
if (prevOwnership.addr != from) revert TransferFromIncorrectOwner();
if (to == address(0)) revert TransferToZeroAddress();
_beforeTokenTransfers(from, to, tokenId, 1);
_approve(address(0), tokenId, prevOwnership.addr);
unchecked {
_addressData[from].balance -= 1;
_addressData[to].balance += 1;
_ownerships[tokenId].addr = to;
_ownerships[tokenId].startTimestamp = uint64(block.timestamp);
uint256 nextTokenId = tokenId + 1;
if (_ownerships[nextTokenId].addr == address(0)) {
if (nextTokenId < _currentIndex) {
_ownerships[nextTokenId].addr = prevOwnership.addr;
_ownerships[nextTokenId].startTimestamp = prevOwnership.startTimestamp;
}
}
}
emit Transfer(from, to, tokenId);
_afterTokenTransfers(from, to, tokenId, 1);
}
function _burn(uint256 tokenId) internal virtual {
TokenOwnership memory prevOwnership = ownershipOf(tokenId);
_beforeTokenTransfers(prevOwnership.addr, address(0), tokenId, 1);
_approve(address(0), tokenId, prevOwnership.addr);
unchecked {
_addressData[prevOwnership.addr].balance -= 1;
_addressData[prevOwnership.addr].numberBurned += 1;
_ownerships[tokenId].addr = prevOwnership.addr;
_ownerships[tokenId].startTimestamp = uint64(block.timestamp);
_ownerships[tokenId].burned = true;
uint256 nextTokenId = tokenId + 1;
if (_ownerships[nextTokenId].addr == address(0)) {
if (nextTokenId < _currentIndex) {
_ownerships[nextTokenId].addr = prevOwnership.addr;
_ownerships[nextTokenId].startTimestamp = prevOwnership.startTimestamp;
}
}
}
emit Transfer(prevOwnership.addr, address(0), tokenId);
_afterTokenTransfers(prevOwnership.addr, address(0), tokenId, 1);
unchecked {
_burnCounter++;
}
}
function _approve(
address to,
uint256 tokenId,
address owner
) private {
_tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert TransferToNonERC721ReceiverImplementer();
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
}
文件 10 的 30:Enums.sol
pragma solidity ^0.8.0;
enum Accessory {
GOLD_EARRINGS,
SCARS,
GOLDEN_CHAIN,
AMULET,
CUBAN_LINK_GOLD_CHAIN,
FANNY_PACK,
NONE
}
enum BackAccessory {
NETRUNNER,
MERCENARY,
RONIN,
ENCHANTER,
VANGUARD,
MINER,
PATHFINDER,
SCOUT
}
enum Background {
STARRY_PINK,
STARRY_YELLOW,
STARRY_PURPLE,
STARRY_GREEN,
NEBULA,
STARRY_RED,
STARRY_BLUE,
SUNSET,
MORNING,
INDIGO,
CITY__PURPLE,
CONTROL_ROOM,
LAB,
GREEN,
ORANGE,
PURPLE,
CITY__GREEN,
CITY__RED,
STATION,
BOUNTY,
BLUE_SKY,
RED_SKY,
GREEN_SKY
}
enum Clothing {
MARTIAL_SUIT,
AMETHYST_ARMOR,
SHIRT_AND_TIE,
THUNDERDOME_ARMOR,
FLEET_UNIFORM__BLUE,
BANANITE_SHIRT,
EXPLORER,
COSMIC_GHILLIE_SUIT__BLUE,
COSMIC_GHILLIE_SUIT__GOLD,
CYBER_JUMPSUIT,
ENCHANTER_ROBES,
HOODIE,
SPACESUIT,
MECHA_ARMOR,
LAB_COAT,
FLEET_UNIFORM__RED,
GOLD_ARMOR,
ENERGY_ARMOR__BLUE,
ENERGY_ARMOR__RED,
MISSION_SUIT__BLACK,
MISSION_SUIT__PURPLE,
COWBOY,
GLITCH_ARMOR,
NONE
}
enum Eyes {
SPACE_VISOR,
ADORABLE,
VETERAN,
SUNGLASSES,
WHITE_SUNGLASSES,
RED_EYES,
WINK,
CASUAL,
CLOSED,
DOWNCAST,
HAPPY,
BLUE_EYES,
HUD_GLASSES,
DARK_SUNGLASSES,
NIGHT_VISION_GOGGLES,
BIONIC,
HIVE_GOGGLES,
MATRIX_GLASSES,
GREEN_GLOW,
ORANGE_GLOW,
RED_GLOW,
PURPLE_GLOW,
BLUE_GLOW,
SKY_GLOW,
RED_LASER,
BLUE_LASER,
GOLDEN_SHADES,
HIPSTER_GLASSES,
PINCENEZ,
BLUE_SHADES,
BLIT_GLASSES,
NOUNS_GLASSES
}
enum Fur {
MAGENTA,
BLUE,
GREEN,
RED,
BLACK,
BROWN,
SILVER,
PURPLE,
PINK,
SEANCE,
TURQUOISE,
CRIMSON,
GREENYELLOW,
GOLD,
DIAMOND,
METALLIC
}
enum Head {
HALO,
ENERGY_FIELD,
BLUE_TOP_HAT,
RED_TOP_HAT,
ENERGY_CRYSTAL,
CROWN,
BANDANA,
BUCKET_HAT,
HOMBURG_HAT,
PROPELLER_HAT,
HEADBAND,
DORAG,
PURPLE_COWBOY_HAT,
SPACESUIT_HELMET,
PARTY_HAT,
CAP,
LEATHER_COWBOY_HAT,
CYBER_HELMET__BLUE,
CYBER_HELMET__RED,
SAMURAI_HAT,
NONE
}
enum Mouth {
SMIRK,
SURPRISED,
SMILE,
PIPE,
OPEN_SMILE,
NEUTRAL,
MASK,
TONGUE_OUT,
GOLD_GRILL,
DIAMOND_GRILL,
NAVY_RESPIRATOR,
RED_RESPIRATOR,
MAGENTA_RESPIRATOR,
GREEN_RESPIRATOR,
MEMPO,
VAPE,
PILOT_OXYGEN_MASK,
CIGAR,
BANANA,
CHROME_RESPIRATOR,
STOIC
}
library Enums {
function toString(Accessory v) external pure returns (string memory) {
if (v == Accessory.GOLD_EARRINGS) {
return "Gold Earrings";
}
if (v == Accessory.SCARS) {
return "Scars";
}
if (v == Accessory.GOLDEN_CHAIN) {
return "Golden Chain";
}
if (v == Accessory.AMULET) {
return "Amulet";
}
if (v == Accessory.CUBAN_LINK_GOLD_CHAIN) {
return "Cuban Link Gold Chain";
}
if (v == Accessory.FANNY_PACK) {
return "Fanny Pack";
}
if (v == Accessory.NONE) {
return "None";
}
revert("invalid accessory");
}
function toString(BackAccessory v) external pure returns (string memory) {
if (v == BackAccessory.NETRUNNER) {
return "Netrunner";
}
if (v == BackAccessory.MERCENARY) {
return "Mercenary";
}
if (v == BackAccessory.RONIN) {
return "Ronin";
}
if (v == BackAccessory.ENCHANTER) {
return "Enchanter";
}
if (v == BackAccessory.VANGUARD) {
return "Vanguard";
}
if (v == BackAccessory.MINER) {
return "Miner";
}
if (v == BackAccessory.PATHFINDER) {
return "Pathfinder";
}
if (v == BackAccessory.SCOUT) {
return "Scout";
}
revert("invalid back accessory");
}
function toString(Background v) external pure returns (string memory) {
if (v == Background.STARRY_PINK) {
return "Starry Pink";
}
if (v == Background.STARRY_YELLOW) {
return "Starry Yellow";
}
if (v == Background.STARRY_PURPLE) {
return "Starry Purple";
}
if (v == Background.STARRY_GREEN) {
return "Starry Green";
}
if (v == Background.NEBULA) {
return "Nebula";
}
if (v == Background.STARRY_RED) {
return "Starry Red";
}
if (v == Background.STARRY_BLUE) {
return "Starry Blue";
}
if (v == Background.SUNSET) {
return "Sunset";
}
if (v == Background.MORNING) {
return "Morning";
}
if (v == Background.INDIGO) {
return "Indigo";
}
if (v == Background.CITY__PURPLE) {
return "City - Purple";
}
if (v == Background.CONTROL_ROOM) {
return "Control Room";
}
if (v == Background.LAB) {
return "Lab";
}
if (v == Background.GREEN) {
return "Green";
}
if (v == Background.ORANGE) {
return "Orange";
}
if (v == Background.PURPLE) {
return "Purple";
}
if (v == Background.CITY__GREEN) {
return "City - Green";
}
if (v == Background.CITY__RED) {
return "City - Red";
}
if (v == Background.STATION) {
return "Station";
}
if (v == Background.BOUNTY) {
return "Bounty";
}
if (v == Background.BLUE_SKY) {
return "Blue Sky";
}
if (v == Background.RED_SKY) {
return "Red Sky";
}
if (v == Background.GREEN_SKY) {
return "Green Sky";
}
revert("invalid background");
}
function toString(Clothing v) external pure returns (string memory) {
if (v == Clothing.MARTIAL_SUIT) {
return "Martial Suit";
}
if (v == Clothing.AMETHYST_ARMOR) {
return "Amethyst Armor";
}
if (v == Clothing.SHIRT_AND_TIE) {
return "Shirt and Tie";
}
if (v == Clothing.THUNDERDOME_ARMOR) {
return "Thunderdome Armor";
}
if (v == Clothing.FLEET_UNIFORM__BLUE) {
return "Fleet Uniform - Blue";
}
if (v == Clothing.BANANITE_SHIRT) {
return "Bananite Shirt";
}
if (v == Clothing.EXPLORER) {
return "Explorer";
}
if (v == Clothing.COSMIC_GHILLIE_SUIT__BLUE) {
return "Cosmic Ghillie Suit - Blue";
}
if (v == Clothing.COSMIC_GHILLIE_SUIT__GOLD) {
return "Cosmic Ghillie Suit - Gold";
}
if (v == Clothing.CYBER_JUMPSUIT) {
return "Cyber Jumpsuit";
}
if (v == Clothing.ENCHANTER_ROBES) {
return "Enchanter Robes";
}
if (v == Clothing.HOODIE) {
return "Hoodie";
}
if (v == Clothing.SPACESUIT) {
return "Spacesuit";
}
if (v == Clothing.MECHA_ARMOR) {
return "Mecha Armor";
}
if (v == Clothing.LAB_COAT) {
return "Lab Coat";
}
if (v == Clothing.FLEET_UNIFORM__RED) {
return "Fleet Uniform - Red";
}
if (v == Clothing.GOLD_ARMOR) {
return "Gold Armor";
}
if (v == Clothing.ENERGY_ARMOR__BLUE) {
return "Energy Armor - Blue";
}
if (v == Clothing.ENERGY_ARMOR__RED) {
return "Energy Armor - Red";
}
if (v == Clothing.MISSION_SUIT__BLACK) {
return "Mission Suit - Black";
}
if (v == Clothing.MISSION_SUIT__PURPLE) {
return "Mission Suit - Purple";
}
if (v == Clothing.COWBOY) {
return "Cowboy";
}
if (v == Clothing.GLITCH_ARMOR) {
return "Glitch Armor";
}
if (v == Clothing.NONE) {
return "None";
}
revert("invalid clothing");
}
function toString(Eyes v) external pure returns (string memory) {
if (v == Eyes.SPACE_VISOR) {
return "Space Visor";
}
if (v == Eyes.ADORABLE) {
return "Adorable";
}
if (v == Eyes.VETERAN) {
return "Veteran";
}
if (v == Eyes.SUNGLASSES) {
return "Sunglasses";
}
if (v == Eyes.WHITE_SUNGLASSES) {
return "White Sunglasses";
}
if (v == Eyes.RED_EYES) {
return "Red Eyes";
}
if (v == Eyes.WINK) {
return "Wink";
}
if (v == Eyes.CASUAL) {
return "Casual";
}
if (v == Eyes.CLOSED) {
return "Closed";
}
if (v == Eyes.DOWNCAST) {
return "Downcast";
}
if (v == Eyes.HAPPY) {
return "Happy";
}
if (v == Eyes.BLUE_EYES) {
return "Blue Eyes";
}
if (v == Eyes.HUD_GLASSES) {
return "HUD Glasses";
}
if (v == Eyes.DARK_SUNGLASSES) {
return "Dark Sunglasses";
}
if (v == Eyes.NIGHT_VISION_GOGGLES) {
return "Night Vision Goggles";
}
if (v == Eyes.BIONIC) {
return "Bionic";
}
if (v == Eyes.HIVE_GOGGLES) {
return "Hive Goggles";
}
if (v == Eyes.MATRIX_GLASSES) {
return "Matrix Glasses";
}
if (v == Eyes.GREEN_GLOW) {
return "Green Glow";
}
if (v == Eyes.ORANGE_GLOW) {
return "Orange Glow";
}
if (v == Eyes.RED_GLOW) {
return "Red Glow";
}
if (v == Eyes.PURPLE_GLOW) {
return "Purple Glow";
}
if (v == Eyes.BLUE_GLOW) {
return "Blue Glow";
}
if (v == Eyes.SKY_GLOW) {
return "Sky Glow";
}
if (v == Eyes.RED_LASER) {
return "Red Laser";
}
if (v == Eyes.BLUE_LASER) {
return "Blue Laser";
}
if (v == Eyes.GOLDEN_SHADES) {
return "Golden Shades";
}
if (v == Eyes.HIPSTER_GLASSES) {
return "Hipster Glasses";
}
if (v == Eyes.PINCENEZ) {
return "Pince-nez";
}
if (v == Eyes.BLUE_SHADES) {
return "Blue Shades";
}
if (v == Eyes.BLIT_GLASSES) {
return "Blit GLasses";
}
if (v == Eyes.NOUNS_GLASSES) {
return "Nouns Glasses";
}
revert("invalid eyes");
}
function toString(Fur v) external pure returns (string memory) {
if (v == Fur.MAGENTA) {
return "Magenta";
}
if (v == Fur.BLUE) {
return "Blue";
}
if (v == Fur.GREEN) {
return "Green";
}
if (v == Fur.RED) {
return "Red";
}
if (v == Fur.BLACK) {
return "Black";
}
if (v == Fur.BROWN) {
return "Brown";
}
if (v == Fur.SILVER) {
return "Silver";
}
if (v == Fur.PURPLE) {
return "Purple";
}
if (v == Fur.PINK) {
return "Pink";
}
if (v == Fur.SEANCE) {
return "Seance";
}
if (v == Fur.TURQUOISE) {
return "Turquoise";
}
if (v == Fur.CRIMSON) {
return "Crimson";
}
if (v == Fur.GREENYELLOW) {
return "Green-Yellow";
}
if (v == Fur.GOLD) {
return "Gold";
}
if (v == Fur.DIAMOND) {
return "Diamond";
}
if (v == Fur.METALLIC) {
return "Metallic";
}
revert("invalid fur");
}
function toString(Head v) external pure returns (string memory) {
if (v == Head.HALO) {
return "Halo";
}
if (v == Head.ENERGY_FIELD) {
return "Energy Field";
}
if (v == Head.BLUE_TOP_HAT) {
return "Blue Top Hat";
}
if (v == Head.RED_TOP_HAT) {
return "Red Top Hat";
}
if (v == Head.ENERGY_CRYSTAL) {
return "Energy Crystal";
}
if (v == Head.CROWN) {
return "Crown";
}
if (v == Head.BANDANA) {
return "Bandana";
}
if (v == Head.BUCKET_HAT) {
return "Bucket Hat";
}
if (v == Head.HOMBURG_HAT) {
return "Homburg Hat";
}
if (v == Head.PROPELLER_HAT) {
return "Propeller Hat";
}
if (v == Head.HEADBAND) {
return "Headband";
}
if (v == Head.DORAG) {
return "Do-rag";
}
if (v == Head.PURPLE_COWBOY_HAT) {
return "Purple Cowboy Hat";
}
if (v == Head.SPACESUIT_HELMET) {
return "Spacesuit Helmet";
}
if (v == Head.PARTY_HAT) {
return "Party Hat";
}
if (v == Head.CAP) {
return "Cap";
}
if (v == Head.LEATHER_COWBOY_HAT) {
return "Leather Cowboy Hat";
}
if (v == Head.CYBER_HELMET__BLUE) {
return "Cyber Helmet - Blue";
}
if (v == Head.CYBER_HELMET__RED) {
return "Cyber Helmet - Red";
}
if (v == Head.SAMURAI_HAT) {
return "Samurai Hat";
}
if (v == Head.NONE) {
return "None";
}
revert("invalid head");
}
function toString(Mouth v) external pure returns (string memory) {
if (v == Mouth.SMIRK) {
return "Smirk";
}
if (v == Mouth.SURPRISED) {
return "Surprised";
}
if (v == Mouth.SMILE) {
return "Smile";
}
if (v == Mouth.PIPE) {
return "Pipe";
}
if (v == Mouth.OPEN_SMILE) {
return "Open Smile";
}
if (v == Mouth.NEUTRAL) {
return "Neutral";
}
if (v == Mouth.MASK) {
return "Mask";
}
if (v == Mouth.TONGUE_OUT) {
return "Tongue Out";
}
if (v == Mouth.GOLD_GRILL) {
return "Gold Grill";
}
if (v == Mouth.DIAMOND_GRILL) {
return "Diamond Grill";
}
if (v == Mouth.NAVY_RESPIRATOR) {
return "Navy Respirator";
}
if (v == Mouth.RED_RESPIRATOR) {
return "Red Respirator";
}
if (v == Mouth.MAGENTA_RESPIRATOR) {
return "Magenta Respirator";
}
if (v == Mouth.GREEN_RESPIRATOR) {
return "Green Respirator";
}
if (v == Mouth.MEMPO) {
return "Mempo";
}
if (v == Mouth.VAPE) {
return "Vape";
}
if (v == Mouth.PILOT_OXYGEN_MASK) {
return "Pilot Oxygen Mask";
}
if (v == Mouth.CIGAR) {
return "Cigar";
}
if (v == Mouth.BANANA) {
return "Banana";
}
if (v == Mouth.CHROME_RESPIRATOR) {
return "Chrome Respirator";
}
if (v == Mouth.STOIC) {
return "Stoic";
}
revert("invalid mouth");
}
}
文件 11 的 30:ExtensibleERC721Enumerable.sol
pragma solidity ^0.8.0;
import "erc721a/contracts/ERC721A.sol";
import "./IExtensibleERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
abstract contract ExtensibleERC721Enumerable is IExtensibleERC721Enumerable, ERC721A, Ownable {
mapping (address => bool) public override isAdmin;
bool public enabled = true;
constructor() {
isAdmin[msg.sender] = true;
}
modifier onlyAdmin() {
require(isAdmin[msg.sender], "ExtensibleERC721Enumerable: admins only");
_;
}
modifier whenEnabled() {
require(enabled, "ExtensibleERC721Enumerable: currently disabled");
_;
}
function addAdmin(address addr) external override onlyAdmin {
isAdmin[addr] = true;
}
function removeAdmin(address addr) external override onlyAdmin {
delete isAdmin[addr];
}
function adminSetEnabled(bool e) external onlyAdmin {
enabled = e;
}
function canAccessToken(address addr, uint tokenId) public view override returns (bool) {
return isAdmin[addr] || ownerOf(tokenId) == addr || address(this) == addr;
}
function isApprovedForAll(address owner, address operator) public view virtual override(IERC721, ERC721A) returns (bool) {
return isAdmin[operator] || super.isApprovedForAll(owner, operator);
}
function transferFrom(address from, address to, uint tokenId) public override(IERC721, ERC721A) whenEnabled {
super.transferFrom(from, to, tokenId);
}
function safeTransferFrom(address from, address to, uint tokenId) public override(IERC721, ERC721A) whenEnabled {
super.safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(address from, address to, uint tokenId, bytes calldata data) public override(IERC721, ERC721A) whenEnabled {
super.safeTransferFrom(from, to, tokenId, data);
}
function adminBurn(uint tokenId) external override onlyAdmin whenEnabled {
_burn(tokenId);
}
function adminTransfer(address from, address to, uint tokenId) external override whenEnabled {
require(canAccessToken(msg.sender, tokenId), "ExtensibleERC721Enumerable: you are not allowed to perform this transfer");
super.transferFrom(from, to, tokenId);
}
}
文件 12 的 30:Generator.sol
pragma solidity ^0.8.0;
import "./Enums.sol";
import "./Rarities.sol";
import "./Rng.sol";
import "./ChainScoutMetadata.sol";
library Generator {
using RngLibrary for Rng;
function getRandom(
Rng memory rng,
uint256 raritySum,
uint16[] memory rarities
) internal view returns (uint256) {
uint256 rn = rng.generate(0, raritySum - 1);
for (uint256 i = 0; i < rarities.length; ++i) {
if (rarities[i] > rn) {
return i;
}
rn -= rarities[i];
}
revert("rn not selected");
}
function makeRandomClass(Rng memory rn)
internal
view
returns (BackAccessory)
{
uint256 r = rn.generate(1, 100);
if (r <= 2) {
return BackAccessory.NETRUNNER;
} else if (r <= 15) {
return BackAccessory.MERCENARY;
} else if (r <= 23) {
return BackAccessory.RONIN;
} else if (r <= 27) {
return BackAccessory.ENCHANTER;
} else if (r <= 38) {
return BackAccessory.VANGUARD;
} else if (r <= 45) {
return BackAccessory.MINER;
} else if (r <= 50) {
return BackAccessory.PATHFINDER;
} else {
return BackAccessory.SCOUT;
}
}
function getAttack(Rng memory rn, BackAccessory sc)
internal
view
returns (uint256)
{
if (sc == BackAccessory.SCOUT) {
return rn.generate(1785, 2415);
} else if (sc == BackAccessory.VANGUARD) {
return rn.generate(1105, 1495);
} else if (sc == BackAccessory.RONIN || sc == BackAccessory.ENCHANTER) {
return rn.generate(2805, 3795);
} else if (sc == BackAccessory.MINER) {
return rn.generate(1615, 2185);
} else if (sc == BackAccessory.NETRUNNER) {
return rn.generate(3740, 5060);
} else {
return rn.generate(2125, 2875);
}
}
function getDefense(Rng memory rn, BackAccessory sc)
internal
view
returns (uint256)
{
if (sc == BackAccessory.SCOUT || sc == BackAccessory.NETRUNNER) {
return rn.generate(1785, 2415);
} else if (sc == BackAccessory.VANGUARD) {
return rn.generate(4250, 5750);
} else if (sc == BackAccessory.RONIN) {
return rn.generate(1530, 2070);
} else if (sc == BackAccessory.MINER) {
return rn.generate(1615, 2185);
} else if (sc == BackAccessory.ENCHANTER) {
return rn.generate(2805, 3795);
} else if (sc == BackAccessory.NETRUNNER) {
return rn.generate(3740, 5060);
} else {
return rn.generate(2125, 2875);
}
}
function exclude(uint trait, uint idx, uint16[][] memory rarities, uint16[] memory limits) internal pure {
limits[trait] -= rarities[trait][idx];
rarities[trait][idx] = 0;
}
function getRandomMetadata(Rng memory rng)
external
view
returns (ChainScoutMetadata memory ret, Rng memory rn)
{
uint16[][] memory rarities = new uint16[][](8);
rarities[0] = Rarities.accessory();
rarities[1] = Rarities.backaccessory();
rarities[2] = Rarities.background();
rarities[3] = Rarities.clothing();
rarities[4] = Rarities.eyes();
rarities[5] = Rarities.fur();
rarities[6] = Rarities.head();
rarities[7] = Rarities.mouth();
uint16[] memory limits = new uint16[](rarities.length);
for (uint i = 0; i < limits.length; ++i) {
limits[i] = 10000;
}
ret.accessory = Accessory(getRandom(rng, limits[0], rarities[0]));
if (
ret.accessory == Accessory.AMULET ||
ret.accessory == Accessory.CUBAN_LINK_GOLD_CHAIN ||
ret.accessory == Accessory.FANNY_PACK ||
ret.accessory == Accessory.GOLDEN_CHAIN
) {
exclude(3, uint(Clothing.FLEET_UNIFORM__BLUE), rarities, limits);
exclude(3, uint(Clothing.FLEET_UNIFORM__RED), rarities, limits);
if (ret.accessory == Accessory.CUBAN_LINK_GOLD_CHAIN) {
exclude(1, uint(BackAccessory.MINER), rarities, limits);
}
}
else if (ret.accessory == Accessory.GOLD_EARRINGS) {
exclude(6, uint(Head.CYBER_HELMET__BLUE), rarities, limits);
exclude(6, uint(Head.CYBER_HELMET__RED), rarities, limits);
exclude(6, uint(Head.SPACESUIT_HELMET), rarities, limits);
}
ret.backaccessory = BackAccessory(getRandom(rng, limits[1], rarities[1]));
if (ret.backaccessory == BackAccessory.PATHFINDER) {
exclude(6, uint(Head.ENERGY_FIELD), rarities, limits);
}
ret.background = Background(getRandom(rng, limits[2], rarities[2]));
if (ret.background == Background.CITY__PURPLE) {
exclude(3, uint(Clothing.FLEET_UNIFORM__BLUE), rarities, limits);
exclude(3, uint(Clothing.MARTIAL_SUIT), rarities, limits);
exclude(3, uint(Clothing.THUNDERDOME_ARMOR), rarities, limits);
exclude(6, uint(Head.ENERGY_FIELD), rarities, limits);
}
else if (ret.background == Background.CITY__RED) {
exclude(6, uint(Head.ENERGY_FIELD), rarities, limits);
}
ret.clothing = Clothing(getRandom(rng, limits[3], rarities[3]));
if (ret.clothing == Clothing.FLEET_UNIFORM__BLUE || ret.clothing == Clothing.FLEET_UNIFORM__RED) {
exclude(7, uint(Mouth.CHROME_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.GREEN_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MAGENTA_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.NAVY_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.RED_RESPIRATOR), rarities, limits);
}
ret.eyes = Eyes(getRandom(rng, limits[4], rarities[4]));
if (ret.eyes == Eyes.BLUE_LASER || ret.eyes == Eyes.RED_LASER) {
exclude(6, uint(Head.BANDANA), rarities, limits);
exclude(6, uint(Head.CYBER_HELMET__BLUE), rarities, limits);
exclude(6, uint(Head.CYBER_HELMET__RED), rarities, limits);
exclude(6, uint(Head.DORAG), rarities, limits);
exclude(6, uint(Head.SPACESUIT_HELMET), rarities, limits);
exclude(7, uint(Mouth.BANANA), rarities, limits);
exclude(7, uint(Mouth.CHROME_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.GREEN_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MAGENTA_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MASK), rarities, limits);
exclude(7, uint(Mouth.MEMPO), rarities, limits);
exclude(7, uint(Mouth.NAVY_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.PILOT_OXYGEN_MASK), rarities, limits);
exclude(7, uint(Mouth.RED_RESPIRATOR), rarities, limits);
}
else if (ret.eyes == Eyes.BLUE_SHADES || ret.eyes == Eyes.DARK_SUNGLASSES || ret.eyes == Eyes.GOLDEN_SHADES) {
exclude(6, uint(Head.SPACESUIT_HELMET), rarities, limits);
exclude(7, uint(Mouth.CHROME_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.GREEN_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MAGENTA_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MASK), rarities, limits);
exclude(7, uint(Mouth.NAVY_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.RED_RESPIRATOR), rarities, limits);
}
else if (ret.eyes == Eyes.HUD_GLASSES || ret.eyes == Eyes.HIVE_GOGGLES || ret.eyes == Eyes.WHITE_SUNGLASSES) {
exclude(6, uint(Head.DORAG), rarities, limits);
exclude(6, uint(Head.HEADBAND), rarities, limits);
exclude(6, uint(Head.SPACESUIT_HELMET), rarities, limits);
}
else if (ret.eyes == Eyes.HAPPY) {
exclude(6, uint(Head.CAP), rarities, limits);
exclude(6, uint(Head.LEATHER_COWBOY_HAT), rarities, limits);
exclude(6, uint(Head.PURPLE_COWBOY_HAT), rarities, limits);
}
else if (ret.eyes == Eyes.HIPSTER_GLASSES) {
exclude(6, uint(Head.BANDANA), rarities, limits);
exclude(6, uint(Head.CYBER_HELMET__BLUE), rarities, limits);
exclude(6, uint(Head.CYBER_HELMET__RED), rarities, limits);
exclude(6, uint(Head.DORAG), rarities, limits);
exclude(6, uint(Head.HEADBAND), rarities, limits);
exclude(6, uint(Head.SPACESUIT_HELMET), rarities, limits);
exclude(7, uint(Mouth.CHROME_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.GREEN_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MAGENTA_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MASK), rarities, limits);
exclude(7, uint(Mouth.MEMPO), rarities, limits);
exclude(7, uint(Mouth.NAVY_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.RED_RESPIRATOR), rarities, limits);
}
else if (ret.eyes == Eyes.MATRIX_GLASSES || ret.eyes == Eyes.NIGHT_VISION_GOGGLES || ret.eyes == Eyes.SUNGLASSES) {
exclude(6, uint(Head.SPACESUIT_HELMET), rarities, limits);
}
else if (ret.eyes == Eyes.NOUNS_GLASSES) {
exclude(6, uint(Head.BANDANA), rarities, limits);
exclude(6, uint(Head.DORAG), rarities, limits);
exclude(6, uint(Head.HEADBAND), rarities, limits);
exclude(6, uint(Head.SPACESUIT_HELMET), rarities, limits);
exclude(7, uint(Mouth.CHROME_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.GREEN_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MAGENTA_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MASK), rarities, limits);
exclude(7, uint(Mouth.MEMPO), rarities, limits);
exclude(7, uint(Mouth.NAVY_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.PILOT_OXYGEN_MASK), rarities, limits);
exclude(7, uint(Mouth.RED_RESPIRATOR), rarities, limits);
}
else if (ret.eyes == Eyes.PINCENEZ) {
exclude(6, uint(Head.SPACESUIT_HELMET), rarities, limits);
exclude(7, uint(Mouth.MASK), rarities, limits);
exclude(7, uint(Mouth.MEMPO), rarities, limits);
}
else if (ret.eyes == Eyes.SPACE_VISOR) {
exclude(6, uint(Head.DORAG), rarities, limits);
exclude(6, uint(Head.HEADBAND), rarities, limits);
exclude(6, uint(Head.SPACESUIT_HELMET), rarities, limits);
exclude(7, uint(Mouth.CHROME_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.GREEN_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MAGENTA_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MEMPO), rarities, limits);
exclude(7, uint(Mouth.NAVY_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.RED_RESPIRATOR), rarities, limits);
}
ret.fur = Fur(getRandom(rng, limits[5], rarities[5]));
ret.head = Head(getRandom(rng, limits[6], rarities[6]));
if (ret.head == Head.BANDANA || ret.head == Head.DORAG) {
exclude(7, uint(Mouth.CHROME_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.GREEN_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MAGENTA_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.NAVY_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.RED_RESPIRATOR), rarities, limits);
}
else if (ret.head == Head.CYBER_HELMET__BLUE || ret.head == Head.CYBER_HELMET__RED || ret.head == Head.SPACESUIT_HELMET) {
exclude(7, uint(Mouth.BANANA), rarities, limits);
exclude(7, uint(Mouth.CHROME_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.CIGAR), rarities, limits);
exclude(7, uint(Mouth.GREEN_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MAGENTA_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.MEMPO), rarities, limits);
exclude(7, uint(Mouth.NAVY_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.PILOT_OXYGEN_MASK), rarities, limits);
exclude(7, uint(Mouth.PIPE), rarities, limits);
exclude(7, uint(Mouth.RED_RESPIRATOR), rarities, limits);
exclude(7, uint(Mouth.VAPE), rarities, limits);
}
if (ret.head == Head.SPACESUIT_HELMET) {
exclude(7, uint(Mouth.MASK), rarities, limits);
}
ret.mouth = Mouth(getRandom(rng, limits[7], rarities[7]));
ret.attack = uint16(getAttack(rng, ret.backaccessory));
ret.defense = uint16(getDefense(rng, ret.backaccessory));
ret.luck = uint16(rng.generate(500, 5000));
ret.speed = uint16(rng.generate(500, 5000));
ret.strength = uint16(rng.generate(500, 5000));
ret.intelligence = uint16(rng.generate(500, 5000));
ret.level = 1;
rn = rng;
}
}
文件 13 的 30:IChainScouts.sol
pragma solidity ^0.8.0;
import "./IExtensibleERC721Enumerable.sol";
import "./ChainScoutsExtension.sol";
import "./ChainScoutMetadata.sol";
interface IChainScouts is IExtensibleERC721Enumerable {
function adminCreateChainScout(
ChainScoutMetadata calldata tbd,
address owner
) external;
function adminRemoveExtension(string calldata key) external;
function adminSetExtension(
string calldata key,
ChainScoutsExtension extension
) external;
function adminSetChainScoutMetadata(
uint256 tokenId,
ChainScoutMetadata calldata tbd
) external;
function getChainScoutMetadata(uint256 tokenId)
external
view
returns (ChainScoutMetadata memory);
}
文件 14 的 30:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 15 的 30:IERC20.sol
pragma solidity ^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);
}
文件 16 的 30:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/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;
}
文件 17 的 30:IERC721Enumerable.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 18 的 30:IERC721Metadata.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 19 的 30:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 20 的 30:IExtensibleERC721Enumerable.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
interface IExtensibleERC721Enumerable is IERC721Enumerable {
function isAdmin(address addr) external view returns (bool);
function addAdmin(address addr) external;
function removeAdmin(address addr) external;
function canAccessToken(address addr, uint tokenId) external view returns (bool);
function adminBurn(uint tokenId) external;
function adminTransfer(address from, address to, uint tokenId) external;
}
文件 21 的 30:ITokenURIProvider.sol
pragma solidity ^0.8.0;
interface ITokenURIProvider {
function tokenURI(uint tokenId) external view returns (string memory);
}
文件 22 的 30:IUtilityERC20.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IUtilityERC20 is IERC20 {
function adminMint(address owner, uint amountWei) external;
function adminSetTokenTimestamp(uint tokenId, uint timestamp) external;
function burn(address owner, uint amountWei) external;
function claimRewards() external;
function stake(uint[] calldata tokenId) external;
}
文件 23 的 30:Integer.sol
pragma solidity ^0.8.0;
library Integer {
function bitAt(uint integer, uint pos) internal pure returns (uint) {
require(pos <= 255, "pos > 255");
return (integer & (1 << pos)) >> pos;
}
function setBitAt(uint integer, uint pos) internal pure returns (uint) {
return integer | (1 << pos);
}
function bitsFrom(uint integer, uint left, uint right) internal pure returns (uint) {
require(left >= right, "left > right");
require(left <= 255, "left > 255");
uint delta = left - right + 1;
return (integer & (((1 << delta) - 1) << right)) >> right;
}
}
文件 24 的 30:MerkleProof.sol
pragma solidity ^0.8.0;
library MerkleProof {
function verify(
bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
bytes32 proofElement = proof[i];
if (computedHash <= proofElement) {
computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
} else {
computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
}
}
return computedHash;
}
}
文件 25 的 30:MerkleWhitelistERC721Enumerable.sol
pragma solidity ^0.8.0;
import "./ExtensibleERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
enum MintingState {
NOT_ALLOWED,
WHITELIST_ONLY,
PUBLIC
}
struct Payee {
address payable addr;
uint16 ratio;
}
abstract contract MerkleWhitelistERC721Enumerable is ExtensibleERC721Enumerable {
mapping (address => uint) public whitelistMintsUsed;
MintingState public mintingState = MintingState.NOT_ALLOWED;
uint public maxMintPerTx;
uint public maxSupply;
uint public maxWhitelistMints;
bytes32 internal root;
address payable[] internal payeeAddresses;
uint16[] internal payeeRatios;
uint internal totalRatio;
event MintingStateChanged(MintingState oldState, MintingState newState);
constructor(Payee[] memory _payees, uint _maxMintPerTx, uint _maxSupply, uint _maxWhitelistMints, bytes32 _root) {
maxMintPerTx = _maxMintPerTx;
maxSupply = _maxSupply;
maxWhitelistMints = _maxWhitelistMints;
root = _root;
payeeAddresses = new address payable[](_payees.length);
payeeRatios = new uint16[](_payees.length);
for (uint i = 0; i < _payees.length; ++i) {
payeeAddresses[i] = _payees[i].addr;
payeeRatios[i] = _payees[i].ratio;
totalRatio += _payees[i].ratio;
}
if (totalRatio == 0) {
revert("Total payee ratio must be > 0");
}
}
function adminSetMaxPerTx(uint max) external onlyAdmin {
maxMintPerTx = max;
}
function adminSetMintingState(MintingState ms) external onlyAdmin {
emit MintingStateChanged(mintingState, ms);
mintingState = ms;
}
function adminSetMaxWhitelistMints(uint max) external onlyAdmin {
maxWhitelistMints = max;
}
function adminSetMerkleRoot(bytes32 _root) external onlyAdmin {
root = _root;
}
function isWhitelisted(bytes32[] calldata proof, address addr) public view returns (bool) {
bytes32 leaf = keccak256(abi.encodePacked(addr));
return MerkleProof.verify(proof, root, leaf);
}
function distributeFunds() internal virtual {
address payable[] memory a = payeeAddresses;
uint16[] memory r = payeeRatios;
uint origValue = msg.value;
uint remainingValue = msg.value;
for (uint i = 0; i < a.length - 1; ++i) {
uint amount = origValue * r[i] / totalRatio;
Address.sendValue(a[i], amount);
remainingValue -= amount;
}
Address.sendValue(a[a.length - 1], remainingValue);
}
function createMetadataForMintedToken(uint tokenId) internal virtual;
function mintPriceWei() public view virtual returns (uint);
function whitelistMint(bytes32[] calldata proof, uint count) public payable returns (uint) {
require(mintingState == MintingState.WHITELIST_ONLY, "Whitelist minting is not allowed atm");
require(isWhitelisted(proof, msg.sender), "Bad whitelist proof");
require(maxWhitelistMints - whitelistMintsUsed[msg.sender] >= count, "Not enough whitelisted mints");
whitelistMintsUsed[msg.sender] += count;
return internalMint(count);
}
function publicMint(uint count) public payable returns (uint) {
if (!isAdmin[msg.sender]) {
require(mintingState == MintingState.PUBLIC, "Public minting is not allowed atm");
require(count <= maxMintPerTx, "Cannot mint more than maxMintPerTx()");
}
return internalMint(count);
}
function internalMint(uint count) internal whenEnabled returns (uint) {
if (!isAdmin[msg.sender]) {
require(count >= 1, "Must mint at least one");
require(!Address.isContract(msg.sender), "Contracts cannot mint");
require(msg.value == count * mintPriceWei(), "Send mintPriceWei() wei for each mint");
}
uint supply = totalSupply();
require(supply + count <= maxSupply, "Cannot mint over maxSupply()");
uint startingIndex = _currentIndex;
for (uint i = startingIndex; i < startingIndex + count; ++i) {
createMetadataForMintedToken(i);
}
_mint(msg.sender, count, "", false);
distributeFunds();
return startingIndex;
}
}
文件 26 的 30:OpenSeaMetadata.sol
pragma solidity ^0.8.0;
import "./Base64.sol";
import "./Integer.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
enum NumericAttributeType {
NUMBER,
BOOST_PERCENTAGE,
BOOST_NUMBER,
DATE
}
struct Attribute {
string displayType;
string key;
string serializedValue;
string maxValue;
}
struct OpenSeaMetadata {
string svg;
string description;
string name;
uint24 backgroundColor;
Attribute[] attributes;
}
library OpenSeaMetadataLibrary {
using Strings for uint;
struct ObjectKeyValuePair {
string key;
string serializedValue;
}
function uintToColorString(uint value, uint nBytes) internal pure returns (string memory) {
bytes memory symbols = "0123456789ABCDEF";
bytes memory buf = new bytes(nBytes * 2);
for (uint i = 0; i < nBytes * 2; ++i) {
buf[nBytes * 2 - 1 - i] = symbols[Integer.bitsFrom(value, (i * 4) + 3, i * 4)];
}
return string(buf);
}
function quote(string memory str) internal pure returns (string memory output) {
return bytes(str).length > 0 ? string(abi.encodePacked(
'"',
str,
'"'
)) : "";
}
function makeStringAttribute(string memory key, string memory value) internal pure returns (Attribute memory) {
return Attribute("", key, quote(value), "");
}
function makeNumericAttribute(NumericAttributeType nat, string memory key, string memory value, string memory maxValue) private pure returns (Attribute memory) {
string memory s = "number";
if (nat == NumericAttributeType.BOOST_PERCENTAGE) {
s = "boost_percentage";
}
else if (nat == NumericAttributeType.BOOST_NUMBER) {
s = "boost_number";
}
else if (nat == NumericAttributeType.DATE) {
s = "date";
}
return Attribute(s, key, value, maxValue);
}
function makeFixedPoint(uint value, uint decimals) internal pure returns (string memory) {
bytes memory st = bytes(value.toString());
while (st.length < decimals) {
st = abi.encodePacked(
"0",
st
);
}
bytes memory ret = new bytes(st.length + 1);
if (decimals >= st.length) {
return string(abi.encodePacked("0.", st));
}
uint dl = st.length - decimals;
uint i = 0;
uint j = 0;
while (i < ret.length) {
if (i == dl) {
ret[i] = '.';
i++;
continue;
}
ret[i] = st[j];
i++;
j++;
}
return string(ret);
}
function makeFixedPointAttribute(NumericAttributeType nat, string memory key, uint value, uint maxValue, uint decimals) internal pure returns (Attribute memory) {
return makeNumericAttribute(nat, key, makeFixedPoint(value, decimals), maxValue == 0 ? "" : makeFixedPoint(maxValue, decimals));
}
function makeUintAttribute(NumericAttributeType nat, string memory key, uint value, uint maxValue) internal pure returns (Attribute memory) {
return makeNumericAttribute(nat, key, value.toString(), maxValue == 0 ? "" : maxValue.toString());
}
function makeBooleanAttribute(string memory key, bool value) internal pure returns (Attribute memory) {
return Attribute("", key, value ? "true" : "false", "");
}
function makeAttributesArray(Attribute[] memory attributes) internal pure returns (string memory output) {
output = "[";
bool empty = true;
for (uint i = 0; i < attributes.length; ++i) {
if (bytes(attributes[i].serializedValue).length > 0) {
ObjectKeyValuePair[] memory kvps = new ObjectKeyValuePair[](4);
kvps[0] = ObjectKeyValuePair("trait_type", quote(attributes[i].key));
kvps[1] = ObjectKeyValuePair("display_type", quote(attributes[i].displayType));
kvps[2] = ObjectKeyValuePair("value", attributes[i].serializedValue);
kvps[3] = ObjectKeyValuePair("max_value", attributes[i].maxValue);
output = string(abi.encodePacked(
output,
empty ? "" : ",",
makeObject(kvps)
));
empty = false;
}
}
output = string(abi.encodePacked(output, "]"));
}
function notEmpty(string memory s) internal pure returns (bool) {
return bytes(s).length > 0;
}
function makeObject(ObjectKeyValuePair[] memory kvps) internal pure returns (string memory output) {
output = "{";
bool empty = true;
for (uint i = 0; i < kvps.length; ++i) {
if (bytes(kvps[i].serializedValue).length > 0) {
output = string(abi.encodePacked(
output,
empty ? "" : ",",
'"',
kvps[i].key,
'":',
kvps[i].serializedValue
));
empty = false;
}
}
output = string(abi.encodePacked(output, "}"));
}
function makeMetadataWithExtraKvps(OpenSeaMetadata memory metadata, ObjectKeyValuePair[] memory extra) internal pure returns (string memory output) {
string memory svgUrl = string(abi.encodePacked(
"data:image/svg+xml;utf8,",
metadata.svg
));
ObjectKeyValuePair[] memory kvps = new ObjectKeyValuePair[](5 + extra.length);
kvps[0] = ObjectKeyValuePair("name", quote(metadata.name));
kvps[1] = ObjectKeyValuePair("description", quote(metadata.description));
kvps[2] = ObjectKeyValuePair("image", quote(svgUrl));
kvps[3] = ObjectKeyValuePair("background_color", quote(uintToColorString(metadata.backgroundColor, 3)));
kvps[4] = ObjectKeyValuePair("attributes", makeAttributesArray(metadata.attributes));
for (uint i = 0; i < extra.length; ++i) {
kvps[i + 5] = extra[i];
}
return string(abi.encodePacked(
"data:application/json;base64,",
Base64.encode(bytes(makeObject(kvps)))
));
}
function makeMetadata(OpenSeaMetadata memory metadata) internal pure returns (string memory output) {
return makeMetadataWithExtraKvps(metadata, new ObjectKeyValuePair[](0));
}
function makeERC1155Metadata(OpenSeaMetadata memory metadata, string memory symbol) internal pure returns (string memory output) {
ObjectKeyValuePair[] memory kvps = new ObjectKeyValuePair[](1);
kvps[0] = ObjectKeyValuePair("symbol", quote(symbol));
return makeMetadataWithExtraKvps(metadata, kvps);
}
}
文件 27 的 30: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() {
_transferOwnership(_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 {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 28 的 30:Rarities.sol
pragma solidity ^0.8.0;
import "./Enums.sol";
library Rarities {
function accessory() internal pure returns (uint16[] memory ret) {
ret = new uint16[](7);
ret[0] = 1200;
ret[1] = 800;
ret[2] = 800;
ret[3] = 400;
ret[4] = 400;
ret[5] = 400;
ret[6] = 6000;
}
function backaccessory() internal pure returns (uint16[] memory ret) {
ret = new uint16[](8);
ret[0] = 200;
ret[1] = 1300;
ret[2] = 800;
ret[3] = 400;
ret[4] = 1100;
ret[5] = 700;
ret[6] = 500;
ret[7] = 5000;
}
function background() internal pure returns (uint16[] memory ret) {
ret = new uint16[](23);
ret[0] = 600;
ret[1] = 600;
ret[2] = 600;
ret[3] = 600;
ret[4] = 500;
ret[5] = 500;
ret[6] = 500;
ret[7] = 500;
ret[8] = 500;
ret[9] = 500;
ret[10] = 100;
ret[11] = 100;
ret[12] = 100;
ret[13] = 600;
ret[14] = 600;
ret[15] = 600;
ret[16] = 100;
ret[17] = 100;
ret[18] = 400;
ret[19] = 400;
ret[20] = 500;
ret[21] = 500;
ret[22] = 500;
}
function clothing() internal pure returns (uint16[] memory ret) {
ret = new uint16[](24);
ret[0] = 500;
ret[1] = 500;
ret[2] = 300;
ret[3] = 300;
ret[4] = 500;
ret[5] = 400;
ret[6] = 300;
ret[7] = 250;
ret[8] = 250;
ret[9] = 500;
ret[10] = 100;
ret[11] = 500;
ret[12] = 300;
ret[13] = 500;
ret[14] = 500;
ret[15] = 500;
ret[16] = 100;
ret[17] = 400;
ret[18] = 400;
ret[19] = 250;
ret[20] = 250;
ret[21] = 250;
ret[22] = 150;
ret[23] = 2000;
}
function eyes() internal pure returns (uint16[] memory ret) {
ret = new uint16[](32);
ret[0] = 250;
ret[1] = 700;
ret[2] = 225;
ret[3] = 350;
ret[4] = 125;
ret[5] = 450;
ret[6] = 700;
ret[7] = 700;
ret[8] = 350;
ret[9] = 350;
ret[10] = 600;
ret[11] = 450;
ret[12] = 250;
ret[13] = 350;
ret[14] = 350;
ret[15] = 225;
ret[16] = 125;
ret[17] = 350;
ret[18] = 200;
ret[19] = 200;
ret[20] = 200;
ret[21] = 200;
ret[22] = 200;
ret[23] = 200;
ret[24] = 50;
ret[25] = 50;
ret[26] = 450;
ret[27] = 450;
ret[28] = 400;
ret[29] = 450;
ret[30] = 25;
ret[31] = 25;
}
function fur() internal pure returns (uint16[] memory ret) {
ret = new uint16[](16);
ret[0] = 1100;
ret[1] = 1100;
ret[2] = 1100;
ret[3] = 525;
ret[4] = 350;
ret[5] = 1100;
ret[6] = 350;
ret[7] = 1100;
ret[8] = 1000;
ret[9] = 525;
ret[10] = 525;
ret[11] = 500;
ret[12] = 525;
ret[13] = 100;
ret[14] = 50;
ret[15] = 50;
}
function head() internal pure returns (uint16[] memory ret) {
ret = new uint16[](21);
ret[0] = 200;
ret[1] = 200;
ret[2] = 350;
ret[3] = 350;
ret[4] = 350;
ret[5] = 150;
ret[6] = 600;
ret[7] = 350;
ret[8] = 350;
ret[9] = 350;
ret[10] = 600;
ret[11] = 600;
ret[12] = 600;
ret[13] = 200;
ret[14] = 350;
ret[15] = 600;
ret[16] = 600;
ret[17] = 50;
ret[18] = 50;
ret[19] = 100;
ret[20] = 3000;
}
function mouth() internal pure returns (uint16[] memory ret) {
ret = new uint16[](21);
ret[0] = 1000;
ret[1] = 1000;
ret[2] = 1000;
ret[3] = 650;
ret[4] = 1000;
ret[5] = 900;
ret[6] = 750;
ret[7] = 650;
ret[8] = 100;
ret[9] = 50;
ret[10] = 100;
ret[11] = 100;
ret[12] = 100;
ret[13] = 100;
ret[14] = 50;
ret[15] = 100;
ret[16] = 100;
ret[17] = 600;
ret[18] = 600;
ret[19] = 50;
ret[20] = 1000;
}
}
文件 29 的 30:Rng.sol
pragma solidity ^0.8.0;
struct Rng {
bytes32 state;
}
library RngLibrary {
function newRng() internal view returns (Rng memory) {
return Rng(getEntropy());
}
function getEntropy() internal view returns (bytes32) {
return keccak256(abi.encodePacked(block.coinbase, msg.sender));
}
function generate(Rng memory self) internal view returns (uint256) {
self.state = keccak256(abi.encodePacked(getEntropy(), self.state));
return uint256(self.state);
}
function generate(Rng memory self, uint min, uint max) internal view returns (uint256) {
require(min <= max, "min > max");
uint delta = max - min;
if (delta == 0) {
return min;
}
return generate(self) % (delta + 1) + min;
}
}
文件 30 的 30:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
{
"compilationTarget": {
"contracts/ChainScouts.sol": "ChainScouts"
},
"evmVersion": "london",
"libraries": {
"contracts/Generator.sol:Generator": "0xc87f9d93feb408e0589051c06f88b6a269c3ec19"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint16","name":"ratio","type":"uint16"}],"internalType":"struct Payee[]","name":"payees","type":"tuple[]"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ApprovalToCurrentOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"OwnerIndexOutOfBounds","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"TokenIndexOutOfBounds","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"MetadataChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum MintingState","name":"oldState","type":"uint8"},{"indexed":false,"internalType":"enum MintingState","name":"newState","type":"uint8"}],"name":"MintingStateChanged","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":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"adminBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum Accessory","name":"accessory","type":"uint8"},{"internalType":"enum BackAccessory","name":"backaccessory","type":"uint8"},{"internalType":"enum Background","name":"background","type":"uint8"},{"internalType":"enum Clothing","name":"clothing","type":"uint8"},{"internalType":"enum Eyes","name":"eyes","type":"uint8"},{"internalType":"enum Fur","name":"fur","type":"uint8"},{"internalType":"enum Head","name":"head","type":"uint8"},{"internalType":"enum Mouth","name":"mouth","type":"uint8"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"luck","type":"uint24"},{"internalType":"uint24","name":"speed","type":"uint24"},{"internalType":"uint24","name":"strength","type":"uint24"},{"internalType":"uint24","name":"intelligence","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"}],"internalType":"struct ChainScoutMetadata","name":"tbd","type":"tuple"},{"internalType":"address","name":"owner","type":"address"}],"name":"adminCreateChainScout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"}],"name":"adminRemoveExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"enum Accessory","name":"accessory","type":"uint8"},{"internalType":"enum BackAccessory","name":"backaccessory","type":"uint8"},{"internalType":"enum Background","name":"background","type":"uint8"},{"internalType":"enum Clothing","name":"clothing","type":"uint8"},{"internalType":"enum Eyes","name":"eyes","type":"uint8"},{"internalType":"enum Fur","name":"fur","type":"uint8"},{"internalType":"enum Head","name":"head","type":"uint8"},{"internalType":"enum Mouth","name":"mouth","type":"uint8"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"luck","type":"uint24"},{"internalType":"uint24","name":"speed","type":"uint24"},{"internalType":"uint24","name":"strength","type":"uint24"},{"internalType":"uint24","name":"intelligence","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"}],"internalType":"struct ChainScoutMetadata","name":"tbd","type":"tuple"}],"name":"adminSetChainScoutMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"e","type":"bool"}],"name":"adminSetEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"contract ChainScoutsExtension","name":"extension","type":"address"}],"name":"adminSetExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"name":"adminSetMaxPerTx","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"name":"adminSetMaxWhitelistMints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_root","type":"bytes32"}],"name":"adminSetMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"name":"adminSetMintPriceWei","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum MintingState","name":"ms","type":"uint8"}],"name":"adminSetMintingState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"adminTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"canAccessToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"extensions","outputs":[{"internalType":"contract ChainScoutsExtension","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getChainScoutMetadata","outputs":[{"components":[{"internalType":"enum Accessory","name":"accessory","type":"uint8"},{"internalType":"enum BackAccessory","name":"backaccessory","type":"uint8"},{"internalType":"enum Background","name":"background","type":"uint8"},{"internalType":"enum Clothing","name":"clothing","type":"uint8"},{"internalType":"enum Eyes","name":"eyes","type":"uint8"},{"internalType":"enum Fur","name":"fur","type":"uint8"},{"internalType":"enum Head","name":"head","type":"uint8"},{"internalType":"enum Mouth","name":"mouth","type":"uint8"},{"internalType":"uint24","name":"attack","type":"uint24"},{"internalType":"uint24","name":"defense","type":"uint24"},{"internalType":"uint24","name":"luck","type":"uint24"},{"internalType":"uint24","name":"speed","type":"uint24"},{"internalType":"uint24","name":"strength","type":"uint24"},{"internalType":"uint24","name":"intelligence","type":"uint24"},{"internalType":"uint16","name":"level","type":"uint16"}],"internalType":"struct ChainScoutMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"address","name":"addr","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintPerTx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxWhitelistMints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintPriceWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintingState","outputs":[{"internalType":"enum MintingState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"name":"publicMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"name":"publicMintAndStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"removeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"whitelistMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"whitelistMintAndStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistMintsUsed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]