编译器
0.8.11+commit.d7f03943
文件 1 的 31: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 的 31:BearRenderTech.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@theappstudio/solidity/contracts/utils/DecimalStrings.sol";
import "@theappstudio/solidity/contracts/utils/OnChain.sol";
import "@theappstudio/solidity/contracts/utils/Randomization.sol";
import "@theappstudio/solidity/contracts/utils/SVG.sol";
import "./BearRenderTechErrors.sol";
import "../interfaces/ICubTraits.sol";
import "../interfaces/IBear3Traits.sol";
import "../interfaces/IBearRenderer.sol";
import "../interfaces/IBearRenderTech.sol";
import "../interfaces/IBearRenderTechProvider.sol";
import "../tokens/TwoBitCubs.sol";
contract BearRenderTech is Ownable, IBearRenderTech, IBearRenderTechProvider {
using Strings for uint256;
using DecimalStrings for uint256;
struct NumberEncoding {
uint8 bytesPerPoint;
uint8 decimals;
bool signed;
}
IBearRenderer private _blackBearRenderer;
IBearRenderer private _brownBearRenderer;
IBearRenderer private _pandaBearRenderer;
IBearRenderer private _polarBearRenderer;
TwoBitCubs private immutable _twoBitCubs;
bool private _wenReveal;
constructor(address twoBitCubs) {
_twoBitCubs = TwoBitCubs(twoBitCubs);
}
function applyRenderers(address blackRenderer, address brownRenderer, address pandaRenderer, address polarRenderer) external onlyOwner {
if (address(_blackBearRenderer) != address(0) ||
address(_brownBearRenderer) != address(0) ||
address(_pandaBearRenderer) != address(0) ||
address(_polarBearRenderer) != address(0)) revert AlreadyConfigured();
_blackBearRenderer = IBearRenderer(blackRenderer);
_brownBearRenderer = IBearRenderer(brownRenderer);
_pandaBearRenderer = IBearRenderer(pandaRenderer);
_polarBearRenderer = IBearRenderer(polarRenderer);
}
function backgroundForType(IBear3Traits.BackgroundType background) public pure returns (string memory) {
string[3] memory backgrounds = ["White Tundra", "Green Forest", "Blue Shore"];
return backgrounds[uint(background)];
}
function createSvg(IBear3Traits.Traits memory traits, uint256 tokenId) public view onlyWenRevealed returns (bytes memory) {
IBearRenderer renderer = _rendererForTraits(traits);
ISVGTypes.Color memory eyeColor = renderer.customEyeColor(_twoBitCubs.traitsV1(traits.firstParentTokenId));
return SVG.createElement("svg", SVG.svgAttributes(447, 447), abi.encodePacked(
_defs(renderer, traits, eyeColor, tokenId),
this.rectElement(100, 100, " fill='url(#background)'"),
this.pathElement(hex'224d76126b084c81747bfb4381f57cdd821c7de981df7ee74381a37fe5810880c2802f81514c5b3b99a8435a359a5459049aaf57cc9ab0569ab04356939ab055619a55545b99a94c2f678151432e8e80c22df37fe52db77ee7432d7b7de92da17cdd2e227bfb4c39846b0a4c57ca6b0a566b084c76126b085a', "url(#chest)"),
this.polygonElement(hex'1207160d0408bc0da20a620d040c0a0a9b08bc0a9b056e0a9b', "url(#neck)"),
renderer.customSurfaces(traits.genes, eyeColor, tokenId)
));
}
function dynamicPolygonElement(bytes memory points, bytes memory fill, Substitution[] memory substitutions) external view onlyRenderer returns (bytes memory) {
return SVG.createElement("polygon", abi.encodePacked(" points='", _polygonPoints(points, substitutions), "' fill='", fill, "'"), "");
}
function familyForTraits(IBear3Traits.Traits memory traits) public view override onlyWenRevealed returns (string memory) {
string[18] memory families = ["Hirst", "Stark", "xCopy", "Watkinson", "Davis", "Evan Dennis", "Anderson", "Pak", "Greenawalt", "Capacity", "Hobbs", "Deafbeef", "Rainaud", "Snowfro", "Winkelmann", "Fairey", "Nines", "Maeda"];
return families[(uint(uint8(bytes22(traits.genes)[1])) + uint(traits.familyIndex)) % 18];
}
function linearGradient(bytes memory id, bytes memory points, bytes memory stop1, bytes memory stop2) external view onlyRenderer returns (bytes memory) {
string memory stop = "stop";
NumberEncoding memory encoding = _readEncoding(points);
bytes memory attributes = abi.encodePacked(
" id='", id,
"' x1='", _decimalStringFromBytes(points, 1, encoding),
"' x2='", _decimalStringFromBytes(points, 1 + encoding.bytesPerPoint, encoding),
"' y1='", _decimalStringFromBytes(points, 1 + 2 * encoding.bytesPerPoint, encoding),
"' y2='", _decimalStringFromBytes(points, 1 + 3 * encoding.bytesPerPoint, encoding), "'"
);
return SVG.createElement("linearGradient", attributes, abi.encodePacked(
SVG.createElement(stop, stop1, ""), SVG.createElement(stop, stop2, "")
));
}
function metadata(IBear3Traits.Traits memory traits, uint256 tokenId) external view returns (bytes memory) {
string memory token = tokenId.toString();
if (_wenReveal) {
return OnChain.dictionary(OnChain.commaSeparated(
OnChain.keyValueString("name", abi.encodePacked(nameForTraits(traits), " ", familyForTraits(traits), " the ", moodForType(traits.mood), " ", speciesForType(traits.species), " Bear ", token)),
OnChain.keyValueArray("attributes", _attributesFromTraits(traits)),
OnChain.keyValueString("image", OnChain.svgImageURI(bytes(createSvg(traits, tokenId))))
));
}
return OnChain.dictionary(OnChain.commaSeparated(
OnChain.keyValueString("name", abi.encodePacked("Rendering Bear ", token)),
OnChain.keyValueString("image", "ipfs://QmUZ3ojSLv3rbu8egkS5brb4ETkNXXmcgCFG66HeFBXn54")
));
}
function moodForType(IBear3Traits.MoodType mood) public pure override returns (string memory) {
string[14] memory moods = ["Happy", "Hungry", "Sleepy", "Grumpy", "Cheerful", "Excited", "Snuggly", "Confused", "Ravenous", "Ferocious", "Hangry", "Drowsy", "Cranky", "Furious"];
return moods[uint256(mood)];
}
function nameForTraits(IBear3Traits.Traits memory traits) public view override onlyWenRevealed returns (string memory) {
string[50] memory names = ["Cophi", "Trace", "Abel", "Ekko", "Goomba", "Milk", "Arth", "Roeleman", "Adjudicator", "Kelly", "Tropo", "Type3", "Jak", "Srsly", "Triggity", "SNR", "Drogate", "Scott", "Timm", "Nutsaw", "Rugged", "Vaypor", "XeR0", "Toasty", "BN3", "Dunks", "JFH", "Eallen", "Aspen", "Krueger", "Nouside", "Fonky", "Ian", "Metal", "Bones", "Cruz", "Daniel", "Buz", "Bliargh", "Strada", "Lanky", "Westwood", "Rie", "Moon", "Mango", "Hammer", "Pizza", "Java", "Gremlin", "Hash"];
return names[(uint(uint8(bytes22(traits.genes)[0])) + uint(traits.nameIndex)) % 50];
}
modifier onlyRenderer() {
if (_msgSender() != address(_blackBearRenderer) &&
_msgSender() != address(_brownBearRenderer) &&
_msgSender() != address(_pandaBearRenderer) &&
_msgSender() != address(_polarBearRenderer) &&
_msgSender() != address(this)) revert OnlyRenderer();
_;
}
modifier onlyWenRevealed() {
if (!_wenReveal) revert NotYetRevealed();
_;
}
function pathElement(bytes memory path, bytes memory fill) external view onlyRenderer returns (bytes memory result) {
NumberEncoding memory encoding = _readEncoding(path);
bytes memory attributes = " d='";
uint index = 1;
while (index < path.length) {
bytes1 control = path[index++];
attributes = abi.encodePacked(attributes, control);
if (control == "C") {
attributes = abi.encodePacked(attributes, _readNext(path, encoding, 6, index));
index += 6 * encoding.bytesPerPoint;
} else if (control == "H") {
attributes = abi.encodePacked(attributes, _readNext(path, encoding, 1, index));
index += encoding.bytesPerPoint;
} else if (control == "L") {
attributes = abi.encodePacked(attributes, _readNext(path, encoding, 2, index));
index += 2 * encoding.bytesPerPoint;
} else if (control == "M") {
attributes = abi.encodePacked(attributes, _readNext(path, encoding, 2, index));
index += 2 * encoding.bytesPerPoint;
} else if (control == "V") {
attributes = abi.encodePacked(attributes, _readNext(path, encoding, 1, index));
index += encoding.bytesPerPoint;
}
}
return SVG.createElement("path", abi.encodePacked(attributes, "' fill='", fill, "'"), "");
}
function polygonElement(bytes memory points, bytes memory fill) external view onlyRenderer returns (bytes memory) {
return SVG.createElement("polygon", abi.encodePacked(" points='", _polygonPoints(points, new Substitution[](0)), "' fill='", fill, "'"), "");
}
function rectElement(uint256 widthPercentage, uint256 heightPercentage, bytes memory attributes) external view onlyRenderer returns (bytes memory) {
return abi.encodePacked("<rect width='", widthPercentage.toString(), "%' height='", heightPercentage.toString(), "%'", attributes, "/>");
}
function revealBears() external onlyOwner {
_wenReveal = true;
}
function scarsForTraits(IBear3Traits.Traits memory traits) public view onlyWenRevealed returns (IBear3Traits.ScarColor[] memory) {
bytes22 geneBytes = bytes22(traits.genes);
uint8 scarCountProvider = uint8(geneBytes[18]);
uint scarCount = Randomization.randomIndex(scarCountProvider, _scarCountPercentages());
IBear3Traits.ScarColor[] memory scars = new IBear3Traits.ScarColor[](scarCount == 0 ? 1 : scarCount);
if (scarCount == 0) {
scars[0] = IBear3Traits.ScarColor.None;
} else {
uint8 scarColorProvider = uint8(geneBytes[17]);
uint scarColor = Randomization.randomIndex(scarColorProvider, _scarColorPercentages());
for (uint scar = 0; scar < scarCount; scar++) {
scars[scar] = IBear3Traits.ScarColor(scarColor+1);
}
}
return scars;
}
function scarForType(IBear3Traits.ScarColor scarColor) public pure override returns (string memory) {
string[4] memory scarColors = ["None", "Blue", "Magenta", "Gold"];
return scarColors[uint256(scarColor)];
}
function speciesForType(IBear3Traits.SpeciesType species) public pure override returns (string memory) {
string[4] memory specieses = ["Brown", "Black", "Polar", "Panda"];
return specieses[uint256(species)];
}
function _attributesFromTraits(IBear3Traits.Traits memory traits) private view returns (bytes memory) {
bytes memory attributes = OnChain.commaSeparated(
OnChain.traitAttribute("Species", bytes(speciesForType(traits.species))),
OnChain.traitAttribute("Mood", bytes(moodForType(traits.mood))),
OnChain.traitAttribute("Background", bytes(backgroundForType(traits.background))),
OnChain.traitAttribute("First Name", bytes(nameForTraits(traits))),
OnChain.traitAttribute("Last Name (Gen 4 Scene)", bytes(familyForTraits(traits))),
OnChain.traitAttribute("Parents", abi.encodePacked("#", uint(traits.firstParentTokenId).toString(), " & #", uint(traits.secondParentTokenId).toString()))
);
bytes memory scarAttributes = OnChain.traitAttribute("Scars", _scarDescription(scarsForTraits(traits)));
attributes = abi.encodePacked(attributes, OnChain.continuesWith(scarAttributes));
bytes memory gen4Attributes = OnChain.traitAttribute("Gen 4 Claim Status", bytes(traits.gen4Claimed ? "Claimed" : "Unclaimed"));
return abi.encodePacked(attributes, OnChain.continuesWith(gen4Attributes));
}
function _decimalStringFromBytes(bytes memory encoded, uint startIndex, NumberEncoding memory encoding) private pure returns (bytes memory) {
(uint value, bool isNegative) = _uintFromBytes(encoded, startIndex, encoding);
return value.toDecimalString(encoding.decimals, isNegative);
}
function _defs(IBearRenderer renderer, IBear3Traits.Traits memory traits, ISVGTypes.Color memory eyeColor, uint256 tokenId) private view returns (bytes memory) {
string[3] memory firstStop = ["#fff", "#F3FCEE", "#EAF4F9"];
string[3] memory lastStop = ["#9C9C9C", "#A6B39E", "#98ADB5"];
return SVG.createElement("defs", "", abi.encodePacked(
this.linearGradient("background", hex'32000003ea000003e6',
abi.encodePacked(" offset='0.44521' stop-color='", firstStop[uint(traits.background)], "'"),
abi.encodePacked(" offset='0.986697' stop-color='", lastStop[uint(traits.background)], "'")
),
renderer.customDefs(traits.genes, eyeColor, scarsForTraits(traits), tokenId)
));
}
function _polygonCoordinateFromBytes(bytes memory encoded, uint startIndex, NumberEncoding memory encoding, Substitution[] memory substitutions) private pure returns (bytes memory) {
(uint x, bool xIsNegative) = _uintFromBytes(encoded, startIndex, encoding);
(uint y, bool yIsNegative) = _uintFromBytes(encoded, startIndex + encoding.bytesPerPoint, encoding);
for (uint index = 0; index < substitutions.length; index++) {
if (x == substitutions[index].matchingX && y == substitutions[index].matchingY) {
x = substitutions[index].replacementX;
y = substitutions[index].replacementY;
break;
}
}
return OnChain.commaSeparated(x.toDecimalString(encoding.decimals, xIsNegative), y.toDecimalString(encoding.decimals, yIsNegative));
}
function _polygonPoints(bytes memory points, Substitution[] memory substitutions) private pure returns (bytes memory pointsValue) {
NumberEncoding memory encoding = _readEncoding(points);
pointsValue = abi.encodePacked(_polygonCoordinateFromBytes(points, 1, encoding, substitutions));
uint bytesPerIteration = encoding.bytesPerPoint << 1;
for (uint byteIndex = 1 + bytesPerIteration; byteIndex < points.length; byteIndex += bytesPerIteration) {
pointsValue = abi.encodePacked(pointsValue, " ", _polygonCoordinateFromBytes(points, byteIndex, encoding, substitutions));
}
}
function _readEncoding(bytes memory encoded) private pure returns (NumberEncoding memory encoding) {
encoding.decimals = uint8(encoded[0] >> 4) & 0xF;
encoding.bytesPerPoint = uint8(encoded[0]) & 0x7;
encoding.signed = uint8(encoded[0]) & 0x8 == 0x8;
}
function _readNext(bytes memory encoded, NumberEncoding memory encoding, uint numbers, uint startIndex) private pure returns (bytes memory result) {
result = _decimalStringFromBytes(encoded, startIndex, encoding);
for (uint index = startIndex + encoding.bytesPerPoint; index < startIndex + (numbers * encoding.bytesPerPoint); index += encoding.bytesPerPoint) {
result = abi.encodePacked(result, " ", _decimalStringFromBytes(encoded, index, encoding));
}
}
function _rendererForTraits(IBear3Traits.Traits memory traits) private view returns (IBearRenderer) {
if (traits.species == IBear3Traits.SpeciesType.Black) {
return _blackBearRenderer;
} else if (traits.species == IBear3Traits.SpeciesType.Brown) {
return _brownBearRenderer;
} else if (traits.species == IBear3Traits.SpeciesType.Panda) {
return _pandaBearRenderer;
} else {
return _polarBearRenderer;
}
}
function _scarColorPercentages() private pure returns (uint8[] memory percentages) {
uint8[] memory array = new uint8[](2);
array[0] = 60;
array[1] = 30;
return array;
}
function _scarCountPercentages() private pure returns (uint8[] memory percentages) {
uint8[] memory array = new uint8[](2);
array[0] = 70;
array[1] = 20;
return array;
}
function _scarDescription(IBear3Traits.ScarColor[] memory scarColors) private pure returns (bytes memory) {
if (scarColors.length == 0 || scarColors[0] == IBear3Traits.ScarColor.None) {
return bytes(scarForType(IBear3Traits.ScarColor.None));
} else {
return abi.encodePacked(scarColors.length.toString(), " ", scarForType(scarColors[0]));
}
}
function _uintFromBytes(bytes memory encoded, uint startIndex, NumberEncoding memory encoding) private pure returns (uint result, bool isNegative) {
result = uint8(encoded[startIndex]);
if (encoding.signed) {
isNegative = result & 0x80 == 0x80;
result &= 0x7F;
}
uint stopIndex = startIndex + encoding.bytesPerPoint;
for (uint index = startIndex + 1; index < stopIndex; index++) {
result = (result << 8) + uint(uint8(encoded[index]));
}
}
}
文件 3 的 31:BearRenderTechErrors.sol
pragma solidity ^0.8.4;
error AlreadyConfigured();
error NotYetRevealed();
error OnlyRenderer();
文件 4 的 31: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;
}
}
文件 5 的 31:DecimalStrings.sol
pragma solidity ^0.8.0;
library DecimalStrings {
function toDecimalString(uint256 value, uint256 decimals, bool isNegative) internal pure returns (bytes memory) {
uint256 temp = value;
uint256 characters;
do {
characters++;
temp /= 10;
} while (temp != 0);
if (characters <= decimals) {
characters += 2 + (decimals - characters);
} else if (decimals > 0) {
characters += 1;
}
temp = isNegative ? 1 : 0;
characters += temp;
bytes memory buffer = new bytes(characters);
while (characters > temp) {
characters -= 1;
if (decimals > 0 && (buffer.length - characters - 1) == decimals) {
buffer[characters] = bytes1(uint8(46));
decimals = 0;
} else if (value != 0) {
buffer[characters] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
} else {
buffer[characters] = bytes1(uint8(48));
}
}
if (isNegative) {
buffer[0] = bytes1(uint8(45));
}
return buffer;
}
}
文件 6 的 31: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;
}
}
文件 7 的 31:ERC721.sol
pragma solidity ^0.8.0;
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
using Address for address;
using Strings for uint256;
string private _name;
string private _symbol;
mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
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) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
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 virtual override {
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
function getApproved(uint256 tokenId) public view virtual override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_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 {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_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 {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
function _safeMint(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
}
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC721: approve to caller");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
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.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}
文件 8 的 31:IBear3TraitProvider.sol
pragma solidity ^0.8.0;
import "./IBear3Traits.sol";
interface IBear3TraitProvider{
function bearTraits(uint256 tokenId) external view returns (IBear3Traits.Traits memory);
function hasGen2Mated(uint256 tokenId) external view returns (bool);
function generation4Claimed(uint256 tokenId) external view returns (bool);
function scarColors(uint256 tokenId) external view returns (IBear3Traits.ScarColor[] memory);
}
文件 9 的 31:IBear3Traits.sol
pragma solidity ^0.8.0;
interface IBear3Traits {
enum BackgroundType {
White, Green, Blue
}
enum ScarColor {
None, Blue, Magenta, Gold
}
enum SpeciesType {
Brown, Black, Polar, Panda
}
enum MoodType {
Happy, Hungry, Sleepy, Grumpy, Cheerful, Excited, Snuggly, Confused, Ravenous, Ferocious, Hangry, Drowsy, Cranky, Furious
}
struct Traits {
BackgroundType background;
MoodType mood;
SpeciesType species;
bool gen4Claimed;
uint8 nameIndex;
uint8 familyIndex;
uint16 firstParentTokenId;
uint16 secondParentTokenId;
uint176 genes;
}
}
文件 10 的 31:IBearRenderTech.sol
pragma solidity ^0.8.0;
import "./IBear3Traits.sol";
interface IBearRenderTech {
function backgroundForType(IBear3Traits.BackgroundType background) external pure returns (string memory);
function createSvg(IBear3Traits.Traits memory traits, uint256 tokenId) external view returns (bytes memory);
function familyForTraits(IBear3Traits.Traits memory traits) external view returns (string memory);
function metadata(IBear3Traits.Traits memory traits, uint256 tokenId) external view returns (bytes memory);
function moodForType(IBear3Traits.MoodType mood) external pure returns (string memory);
function nameForTraits(IBear3Traits.Traits memory traits) external view returns (string memory);
function scarsForTraits(IBear3Traits.Traits memory traits) external view returns (IBear3Traits.ScarColor[] memory);
function scarForType(IBear3Traits.ScarColor scarColor) external pure returns (string memory);
function speciesForType(IBear3Traits.SpeciesType species) external pure returns (string memory);
}
文件 11 的 31:IBearRenderTechProvider.sol
pragma solidity ^0.8.0;
import "./IBear3Traits.sol";
interface IBearRenderTechProvider {
struct Substitution {
uint matchingX;
uint matchingY;
uint replacementX;
uint replacementY;
}
function dynamicPolygonElement(bytes memory points, bytes memory fill, Substitution[] memory substitutions) external view returns (bytes memory);
function linearGradient(bytes memory id, bytes memory points, bytes memory stop1, bytes memory stop2) external view returns (bytes memory);
function pathElement(bytes memory path, bytes memory fill) external view returns (bytes memory);
function polygonElement(bytes memory points, bytes memory fill) external view returns (bytes memory);
function rectElement(uint256 widthPercentage, uint256 heightPercentage, bytes memory attributes) external view returns (bytes memory);
}
文件 12 的 31:IBearRenderer.sol
pragma solidity ^0.8.0;
import "@theappstudio/solidity/contracts/interfaces/ISVGTypes.sol";
import "./IBear3Traits.sol";
import "./ICubTraits.sol";
interface IBearRenderer {
function customDefs(uint176 genes, ISVGTypes.Color memory eyeColor, IBear3Traits.ScarColor[] memory scars, uint256 tokenId) external view returns (bytes memory);
function customEyeColor(ICubTraits.TraitsV1 memory dominantParent) external view returns (ISVGTypes.Color memory);
function customSurfaces(uint176 genes, ISVGTypes.Color memory eyeColor, uint256 tokenId) external view returns (bytes memory);
}
文件 13 的 31:ICubTraitProvider.sol
pragma solidity ^0.8.0;
import "./ICubTraits.sol";
interface ICubTraitProvider{
function familyForTraits(ICubTraits.TraitsV1 memory traits) external pure returns (string memory);
function moodForType(ICubTraits.CubMoodType moodType) external pure returns (string memory);
function moodFromParents(uint256 firstParentTokenId, uint256 secondParentTokenId) external view returns (ICubTraits.CubMoodType);
function nameForTraits(ICubTraits.TraitsV1 memory traits) external pure returns (string memory);
function speciesForType(ICubTraits.CubSpeciesType speciesType) external pure returns (string memory);
function traitsV1(uint256 tokenId) external view returns (ICubTraits.TraitsV1 memory traits);
}
文件 14 的 31:ICubTraits.sol
pragma solidity ^0.8.0;
import "@theappstudio/solidity/contracts/interfaces/ISVGTypes.sol";
interface ICubTraits {
enum CubSpeciesType {
Brown, Black, Polar, Panda
}
enum CubMoodType {
Happy, Hungry, Sleepy, Grumpy, Cheerful, Excited, Snuggly, Confused, Ravenous, Ferocious, Hangry, Drowsy, Cranky, Furious
}
struct DNA {
uint16 firstParentTokenId;
uint16 secondParentTokenId;
uint224 genes;
}
struct TraitsV1 {
uint256 age;
ISVGTypes.Color topColor;
ISVGTypes.Color bottomColor;
uint8 nameIndex;
uint8 familyIndex;
CubMoodType mood;
CubSpeciesType species;
}
}
文件 15 的 31:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 16 的 31: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 的 31: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 的 31: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 的 31:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 20 的 31:ISVGTypes.sol
pragma solidity ^0.8.0;
interface ISVGTypes {
struct Color {
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha;
}
enum ColorAttribute {
Fill, Stroke, Stop
}
enum ColorAttributeKind {
RGB, URL
}
}
文件 21 的 31:OnChain.sol
pragma solidity ^0.8.4;
import "base64-sol/base64.sol";
library OnChain {
function baseSvgImageURI() internal pure returns (bytes memory) {
return "data:image/svg+xml;base64,";
}
function baseURI() internal pure returns (bytes memory) {
return "data:application/json;base64,";
}
function commaSeparated(bytes memory contents1, bytes memory contents2) internal pure returns (bytes memory) {
return abi.encodePacked(contents1, continuesWith(contents2));
}
function commaSeparated(bytes memory contents1, bytes memory contents2, bytes memory contents3) internal pure returns (bytes memory) {
return abi.encodePacked(commaSeparated(contents1, contents2), continuesWith(contents3));
}
function commaSeparated(bytes memory contents1, bytes memory contents2, bytes memory contents3, bytes memory contents4) internal pure returns (bytes memory) {
return abi.encodePacked(commaSeparated(contents1, contents2, contents3), continuesWith(contents4));
}
function commaSeparated(bytes memory contents1, bytes memory contents2, bytes memory contents3, bytes memory contents4, bytes memory contents5) internal pure returns (bytes memory) {
return abi.encodePacked(commaSeparated(contents1, contents2, contents3, contents4), continuesWith(contents5));
}
function commaSeparated(bytes memory contents1, bytes memory contents2, bytes memory contents3, bytes memory contents4, bytes memory contents5, bytes memory contents6) internal pure returns (bytes memory) {
return abi.encodePacked(commaSeparated(contents1, contents2, contents3, contents4, contents5), continuesWith(contents6));
}
function continuesWith(bytes memory contents) internal pure returns (bytes memory) {
return abi.encodePacked(",", contents);
}
function dictionary(bytes memory contents) internal pure returns (bytes memory) {
return abi.encodePacked("{", contents, "}");
}
function keyValueArray(string memory key, bytes memory value) internal pure returns (bytes memory) {
return abi.encodePacked("\"", key, "\":[", value, "]");
}
function keyValueString(string memory key, bytes memory value) internal pure returns (bytes memory) {
return abi.encodePacked("\"", key, "\":\"", value, "\"");
}
function svgImageURI(bytes memory svg) internal pure returns (bytes memory) {
return abi.encodePacked(baseSvgImageURI(), Base64.encode(svg));
}
function tokenURI(bytes memory metadata) internal pure returns (bytes memory) {
return abi.encodePacked(baseURI(), Base64.encode(metadata));
}
function traitAttribute(string memory name, bytes memory value) internal pure returns (bytes memory) {
return dictionary(commaSeparated(
keyValueString("trait_type", bytes(name)),
keyValueString("value", value)
));
}
}
文件 22 的 31: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);
}
}
文件 23 的 31:Randomization.sol
pragma solidity ^0.8.4;
import "./RandomizationErrors.sol";
library Randomization {
function randomIndex(uint8 random, uint8[] memory percentages) internal pure returns (uint256) {
uint256 spread = (3921 * uint256(random) / 10000) % 100;
uint256 remainingPercent = 100;
for (uint256 i = 0; i < percentages.length; i++) {
uint256 nextPercentage = percentages[i];
if (remainingPercent < nextPercentage) revert PercentagesGreaterThan100();
remainingPercent -= nextPercentage;
if (spread >= remainingPercent) {
return i;
}
}
return percentages.length;
}
function randomSeed(uint256 initialSeed) internal view returns (uint256) {
return uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), msg.sender, initialSeed >> 1)));
}
}
文件 24 的 31:RandomizationErrors.sol
pragma solidity ^0.8.4;
error PercentagesGreaterThan100();
文件 25 的 31:SVG.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Strings.sol";
import "../interfaces/ISVGTypes.sol";
import "./OnChain.sol";
import "./SVGErrors.sol";
library SVG {
using Strings for uint256;
function createElement(string memory name, bytes memory attributes, bytes memory contents) internal pure returns (bytes memory) {
return abi.encodePacked(
"<", attributes.length == 0 ? bytes(name) : abi.encodePacked(name, attributes),
contents.length == 0 ? bytes("/>") : abi.encodePacked(">", contents, "</", name, ">")
);
}
function svgAttributes(uint256 width, uint256 height) internal pure returns (bytes memory) {
return abi.encodePacked(" viewBox='0 0 ", width.toString(), " ", height.toString(), "' xmlns='http://www.w3.org/2000/svg'");
}
function colorAttribute(ISVGTypes.ColorAttribute attribute, bytes memory value) internal pure returns (bytes memory) {
if (attribute == ISVGTypes.ColorAttribute.Fill) return _attribute("fill", value);
if (attribute == ISVGTypes.ColorAttribute.Stop) return _attribute("stop-color", value);
return _attribute("stroke", value);
}
function colorAttributeRGBValue(ISVGTypes.Color memory color) internal pure returns (bytes memory) {
return _colorValue(ISVGTypes.ColorAttributeKind.RGB, OnChain.commaSeparated(
bytes(uint256(color.red).toString()),
bytes(uint256(color.green).toString()),
bytes(uint256(color.blue).toString())
));
}
function colorAttributeURLValue(bytes memory url) internal pure returns (bytes memory) {
return _colorValue(ISVGTypes.ColorAttributeKind.URL, url);
}
function brightenColor(ISVGTypes.Color memory source, uint32 percentage, uint8 minimumBump) internal pure returns (ISVGTypes.Color memory color) {
color.red = _brightenComponent(source.red, percentage, minimumBump);
color.green = _brightenComponent(source.green, percentage, minimumBump);
color.blue = _brightenComponent(source.blue, percentage, minimumBump);
color.alpha = source.alpha;
}
function fromPackedColor(uint24 packedColor) internal pure returns (ISVGTypes.Color memory color) {
color.red = uint8(packedColor >> 16);
color.green = uint8(packedColor >> 8);
color.blue = uint8(packedColor);
color.alpha = 0xFF;
}
function mixColors(ISVGTypes.Color memory color1, ISVGTypes.Color memory color2, uint32 ratioPercentage, uint32 totalPercentage) internal pure returns (ISVGTypes.Color memory color) {
if (ratioPercentage > 100) revert RatioInvalid();
color.red = _mixComponents(color1.red, color2.red, ratioPercentage, totalPercentage);
color.green = _mixComponents(color1.green, color2.green, ratioPercentage, totalPercentage);
color.blue = _mixComponents(color1.blue, color2.blue, ratioPercentage, totalPercentage);
color.alpha = _mixComponents(color1.alpha, color2.alpha, ratioPercentage, totalPercentage);
}
function randomizeColors(ISVGTypes.Color memory start, ISVGTypes.Color memory stop, ISVGTypes.Color memory random) internal pure returns (ISVGTypes.Color memory color) {
uint16 percent = uint16((1320 * (uint(random.red) + uint(random.green) + uint(random.blue)) / 10000) % 101);
color.red = _randomizeComponent(start.red, stop.red, random.red, percent);
color.green = _randomizeComponent(start.green, stop.green, random.green, percent);
color.blue = _randomizeComponent(start.blue, stop.blue, random.blue, percent);
color.alpha = 0xFF;
}
function _attribute(bytes memory name, bytes memory contents) private pure returns (bytes memory) {
return abi.encodePacked(" ", name, "='", contents, "'");
}
function _brightenComponent(uint8 component, uint32 percentage, uint8 minimumBump) private pure returns (uint8 result) {
uint32 wideComponent = uint32(component);
uint32 brightenedComponent = wideComponent * (percentage + 100) / 100;
uint32 wideMinimumBump = uint32(minimumBump);
if (brightenedComponent - wideComponent < wideMinimumBump) {
brightenedComponent = wideComponent + wideMinimumBump;
}
if (brightenedComponent > 0xFF) {
result = 0xFF;
} else {
result = uint8(brightenedComponent);
}
}
function _colorValue(ISVGTypes.ColorAttributeKind attributeKind, bytes memory contents) private pure returns (bytes memory) {
return abi.encodePacked(attributeKind == ISVGTypes.ColorAttributeKind.RGB ? "rgb(" : "url(#", contents, ")");
}
function _mixComponents(uint8 component1, uint8 component2, uint32 ratioPercentage, uint32 totalPercentage) private pure returns (uint8 component) {
uint32 mixedComponent = (uint32(component1) * ratioPercentage + uint32(component2) * (100 - ratioPercentage)) * totalPercentage / 10000;
if (mixedComponent > 0xFF) {
component = 0xFF;
} else {
component = uint8(mixedComponent);
}
}
function _randomizeComponent(uint8 start, uint8 stop, uint8 random, uint16 percent) private pure returns (uint8 component) {
if (start == stop) {
component = start;
} else {
(uint8 floor, uint8 ceiling) = start < stop ? (start, stop) : (stop, start);
component = floor + uint8(uint16(ceiling - (random & 0x01) - floor) * percent / uint16(100));
}
}
}
文件 26 的 31:SVGErrors.sol
pragma solidity ^0.8.4;
error RatioInvalid();
文件 27 的 31: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);
}
}
文件 28 的 31:TwoBitBears3.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@theappstudio/solidity/contracts/utils/OnChain.sol";
import "@theappstudio/solidity/contracts/utils/Randomization.sol";
import "../interfaces/IBear3TraitProvider.sol";
import "../interfaces/ICubTraitProvider.sol";
import "../utils/BearRenderTech.sol";
import "../utils/TwoBitBears3Errors.sol";
import "./TwoBitCubs.sol";
contract TwoBitBears3 is ERC721, IBear3TraitProvider, IERC721Enumerable, Ownable {
IBearRenderTech private immutable _bearRenderTech;
uint256 private immutable _cubAdultAge;
uint256[] private _cubEligibility;
mapping(uint256 => bool) private _generation4Claims;
address private _gen4Contract;
mapping(uint256 => bool) private _matedCubs;
uint256 private _seed;
uint256[] private _tokenIdsToDNA;
TwoBitCubs private immutable _twoBitCubs;
constructor(uint256 seed, address renderTech, address twoBitCubs) ERC721("TwoBitBears3", "TB3") {
_seed = seed;
_bearRenderTech = IBearRenderTech(renderTech);
_twoBitCubs = TwoBitCubs(twoBitCubs);
_cubAdultAge = _twoBitCubs.ADULT_AGE();
}
function applySlots(uint256[] calldata slotIndices, uint256[] calldata slotValues) external onlyOwner {
for (uint i = 0; i < slotIndices.length; i++) {
uint slotIndex = slotIndices[i];
uint slotValue = slotValues[i];
if (slotIndex >= _cubEligibility.length) {
while (slotIndex > _cubEligibility.length) {
_cubEligibility.push(0);
}
_cubEligibility.push(slotValue);
} else if (_cubEligibility[slotIndex] != slotValue) {
_cubEligibility[slotIndex] = slotValue;
}
}
}
function assignGen4(address gen4Contract) external onlyOwner {
if (gen4Contract == address(0)) revert InvalidAddress();
_gen4Contract = gen4Contract;
}
function bearTraits(uint256 tokenId) external view onlyWhenExists(tokenId) returns (IBear3Traits.Traits memory) {
return _traitsForToken(tokenId);
}
function calculateSlot(uint256 slotIndex, uint256 totalTokens) external view onlyOwner returns (uint256 slotValue) {
uint tokenStart = slotIndex * 32;
uint tokenId = tokenStart + 32;
if (tokenId > totalTokens) {
tokenId = totalTokens;
}
uint adults = 0;
do {
tokenId -= 1;
slotValue = (slotValue << 8) | _getEligibility(tokenId);
if (slotValue >= 0x80) {
adults++;
}
} while (tokenId > tokenStart);
if (adults == 0 || (slotIndex < _cubEligibility.length && slotValue == _cubEligibility[slotIndex])) {
slotValue = 0;
}
}
function claimGen4(uint256 tokenId) external onlyWhenExists(tokenId) {
if (_gen4Contract == address(0) || _msgSender() != _gen4Contract) revert InvalidCaller();
_generation4Claims[tokenId] = true;
}
function decimals() external pure returns (uint256) {
return 0;
}
function hasGen2Mated(uint256 tokenId) external view returns (bool) {
return _matedCubs[tokenId];
}
function generation4Claimed(uint256 tokenId) external view onlyWhenExists(tokenId) returns (bool) {
return _generation4Claims[tokenId];
}
function slotParameters() external view onlyOwner returns (uint256 totalSlots, uint256 totalTokens) {
totalTokens = _twoBitCubs.totalSupply();
totalSlots = 1 + totalTokens / 32;
}
function imageSVG(uint256 tokenId) external view returns (string memory) {
return string(_imageBytes(tokenId));
}
function imageURI(uint256 tokenId) external view returns (string memory) {
return string(OnChain.svgImageURI(_imageBytes(tokenId)));
}
function mateBears(uint256 parentOne, uint256 parentTwo) external {
if (_matedCubs[parentOne]) revert ParentAlreadyMated(parentOne);
if (_matedCubs[parentTwo]) revert ParentAlreadyMated(parentTwo);
if (_twoBitCubs.ownerOf(parentOne) != _msgSender()) revert ParentNotOwned(parentOne);
if (_twoBitCubs.ownerOf(parentTwo) != _msgSender()) revert ParentNotOwned(parentTwo);
uint parentOneInfo = _getEligibility(parentOne);
uint parentTwoInfo = _getEligibility(parentTwo);
uint parentOneSpecies = parentOneInfo & 0x03;
if (parentOne == parentTwo || parentOneSpecies != (parentTwoInfo & 0x03)) revert InvalidParentCombination();
if (parentOneInfo < 0x80) revert ParentTooYoung(parentOne);
if (parentTwoInfo < 0x80) revert ParentTooYoung(parentTwo);
_matedCubs[parentOne] = true;
_matedCubs[parentTwo] = true;
uint seed = Randomization.randomSeed(_seed);
uint rawDna = (seed << 48) | (parentOne << 32) | (parentTwo << 16) | (parentOneSpecies << 8) | ((parentOneInfo & 0x7F) >> 2);
uint tokenId = _tokenIdsToDNA.length;
_tokenIdsToDNA.push(rawDna);
_seed = seed;
_safeMint(_msgSender(), tokenId, "");
}
function matingGas(address minter, uint256 parentOne, uint256 parentTwo) external view returns (uint256 result) {
result = 146000;
if (_tokenIdsToDNA.length == 0) {
result += 16500;
}
if (balanceOf(minter) == 0) {
result += 17500;
}
uint fetchCount = 0;
if (_eligibility(parentOne) < 0x80) {
result += 47000;
if (uint(_twoBitCubs.traitsV1(parentOne).mood) >= 4) {
result += 33500;
}
fetchCount += 1;
}
if (_eligibility(parentTwo) < 0x80) {
result += 47000;
if (uint(_twoBitCubs.traitsV1(parentTwo).mood) >= 4) {
result += 33500;
}
fetchCount += 1;
}
if (fetchCount == 1) {
result += 10000;
}
}
modifier onlyWhenExists(uint256 tokenId) {
if (!_exists(tokenId)) revert InvalidTokenId();
_;
}
function scarColors(uint256 tokenId) external view onlyWhenExists(tokenId) returns (IBear3Traits.ScarColor[] memory) {
IBear3Traits.Traits memory traits = _traitsForToken(tokenId);
return _bearRenderTech.scarsForTraits(traits);
}
function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC721) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
function tokenByIndex(uint256 index) external view returns (uint256) {
require(index < this.totalSupply(), "global index out of bounds");
return index;
}
function tokenOfOwnerByIndex(address owner_, uint256 index) external view returns (uint256 tokenId) {
require(index < ERC721.balanceOf(owner_), "owner index out of bounds");
for (uint tokenIndex = 0; tokenIndex < _tokenIdsToDNA.length; tokenIndex++) {
if (_exists(tokenIndex) && ownerOf(tokenIndex) == owner_) {
if (index == 0) {
tokenId = tokenIndex;
break;
}
index--;
}
}
}
function tokenURI(uint256 tokenId) public view override onlyWhenExists(tokenId) returns (string memory) {
IBear3Traits.Traits memory traits = _traitsForToken(tokenId);
return string(OnChain.tokenURI(_bearRenderTech.metadata(traits, tokenId)));
}
function totalSupply() external view returns (uint256) {
return _tokenIdsToDNA.length;
}
function _eligibility(uint256 parent) private view returns (uint8 result) {
uint slotIndex = parent / 32;
if (slotIndex < _cubEligibility.length) {
result = uint8(_cubEligibility[slotIndex] >> ((parent % 32) * 8));
}
}
function _getEligibility(uint256 parent) private view returns (uint8 result) {
result = _eligibility(parent);
if (result < 0x80) {
result = _packedInfo(_twoBitCubs.traitsV1(parent));
}
}
function _imageBytes(uint256 tokenId) private view onlyWhenExists(tokenId) returns (bytes memory) {
IBear3Traits.Traits memory traits = _traitsForToken(tokenId);
return _bearRenderTech.createSvg(traits, tokenId);
}
function _traitsForToken(uint256 tokenId) private view returns (IBear3Traits.Traits memory traits) {
uint dna = _tokenIdsToDNA[tokenId];
traits.mood = IBear3Traits.MoodType(dna & 0xFF);
traits.species = IBear3Traits.SpeciesType((dna >> 8) & 0xFF);
traits.firstParentTokenId = uint16(dna >> 16) & 0xFFFF;
traits.secondParentTokenId = uint16(dna >> 32) & 0xFFFF;
traits.nameIndex = uint8((dna >> 48) & 0xFF);
traits.familyIndex = uint8((dna >> 56) & 0xFF);
traits.background = IBear3Traits.BackgroundType(((dna >> 64) & 0xFF) % 3);
traits.gen4Claimed = _generation4Claims[tokenId];
traits.genes = uint176(dna >> 80);
}
function _packedInfo(ICubTraits.TraitsV1 memory traits) private view returns (uint8 info) {
info |= uint8(traits.species);
info |= uint8(traits.mood) << 2;
if (traits.age >= _cubAdultAge) {
info |= 0x80;
}
}
}
文件 29 的 31:TwoBitBears3Errors.sol
pragma solidity ^0.8.4;
error InvalidAddress();
error InvalidCaller();
error InvalidParentCombination();
error InvalidTokenId();
error ParentAlreadyMated(uint256 tokenId);
error ParentNotOwned(uint256 tokenId);
error ParentTooYoung(uint256 tokenId);
文件 30 的 31:TwoBitCubs.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "../interfaces/ICubTraitProvider.sol";
abstract contract TwoBitCubs is IERC721Enumerable, ICubTraitProvider {
uint256 public constant ADULT_AGE = 44000;
}
文件 31 的 31:base64.sol
pragma solidity >=0.6.0;
library Base64 {
string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
bytes internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000"
hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"
hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"
hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";
function encode(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return '';
string memory table = TABLE_ENCODE;
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)
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, 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;
}
function decode(string memory _data) internal pure returns (bytes memory) {
bytes memory data = bytes(_data);
if (data.length == 0) return new bytes(0);
require(data.length % 4 == 0, "invalid base64 decoder input");
bytes memory table = TABLE_DECODE;
uint256 decodedLen = (data.length / 4) * 3;
bytes memory result = new bytes(decodedLen + 32);
assembly {
let lastBytes := mload(add(data, mload(data)))
if eq(and(lastBytes, 0xFF), 0x3d) {
decodedLen := sub(decodedLen, 1)
if eq(and(lastBytes, 0xFFFF), 0x3d3d) {
decodedLen := sub(decodedLen, 1)
}
}
mstore(result, decodedLen)
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, 4)
let input := mload(dataPtr)
let output := add(
add(
shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)),
shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))),
add(
shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)),
and(mload(add(tablePtr, and( input , 0xFF))), 0xFF)
)
)
mstore(resultPtr, shl(232, output))
resultPtr := add(resultPtr, 3)
}
}
return result;
}
}
{
"compilationTarget": {
"contracts/tokens/TwoBitBears3.sol": "TwoBitBears3"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"address","name":"renderTech","type":"address"},{"internalType":"address","name":"twoBitCubs","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidParentCombination","type":"error"},{"inputs":[],"name":"InvalidTokenId","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ParentAlreadyMated","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ParentNotOwned","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ParentTooYoung","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":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":"uint256[]","name":"slotIndices","type":"uint256[]"},{"internalType":"uint256[]","name":"slotValues","type":"uint256[]"}],"name":"applySlots","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":"gen4Contract","type":"address"}],"name":"assignGen4","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":"uint256","name":"tokenId","type":"uint256"}],"name":"bearTraits","outputs":[{"components":[{"internalType":"enum IBear3Traits.BackgroundType","name":"background","type":"uint8"},{"internalType":"enum IBear3Traits.MoodType","name":"mood","type":"uint8"},{"internalType":"enum IBear3Traits.SpeciesType","name":"species","type":"uint8"},{"internalType":"bool","name":"gen4Claimed","type":"bool"},{"internalType":"uint8","name":"nameIndex","type":"uint8"},{"internalType":"uint8","name":"familyIndex","type":"uint8"},{"internalType":"uint16","name":"firstParentTokenId","type":"uint16"},{"internalType":"uint16","name":"secondParentTokenId","type":"uint16"},{"internalType":"uint176","name":"genes","type":"uint176"}],"internalType":"struct IBear3Traits.Traits","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"slotIndex","type":"uint256"},{"internalType":"uint256","name":"totalTokens","type":"uint256"}],"name":"calculateSlot","outputs":[{"internalType":"uint256","name":"slotValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"claimGen4","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"generation4Claimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"hasGen2Mated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"imageSVG","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"imageURI","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"uint256","name":"parentOne","type":"uint256"},{"internalType":"uint256","name":"parentTwo","type":"uint256"}],"name":"mateBears","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"parentOne","type":"uint256"},{"internalType":"uint256","name":"parentTwo","type":"uint256"}],"name":"matingGas","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"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":[],"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":"uint256","name":"tokenId","type":"uint256"}],"name":"scarColors","outputs":[{"internalType":"enum IBear3Traits.ScarColor[]","name":"","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"slotParameters","outputs":[{"internalType":"uint256","name":"totalSlots","type":"uint256"},{"internalType":"uint256","name":"totalTokens","type":"uint256"}],"stateMutability":"view","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":"tokenId","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"}]