// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)pragmasolidity ^0.8.0;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in// construction, since the code is only stored at the end of the// constructor execution.uint256 size;
assembly {
size :=extcodesize(account)
}
return size >0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable 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");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(address(this).balance>= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytesmemory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/functionverifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalpurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;/// @dev When the renderers are already configurederrorAlreadyConfigured();
/// @dev When Reveal is falseerrorNotYetRevealed();
/// @dev Only the Renderer can make these callserrorOnlyRenderer();
Contract Source Code
File 4 of 31: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 5 of 31: DecimalStrings.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @dev String operations with decimalslibraryDecimalStrings{
/// @dev Converts a `uint256` to its ASCII `string` representation with decimal places.functiontoDecimalString(uint256 value, uint256 decimals, bool isNegative) internalpurereturns (bytesmemory) {
// Inspired by OpenZeppelin's implementation - MIT licence// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.soluint256 temp = value;
uint256 characters;
do {
characters++;
temp /=10;
} while (temp !=0);
if (characters <= decimals) {
characters +=2+ (decimals - characters);
} elseif (decimals >0) {
characters +=1;
}
temp = isNegative ? 1 : 0; // reuse 'temp' as a sign symbol offset
characters += temp;
bytesmemory buffer =newbytes(characters);
while (characters > temp) {
characters -=1;
if (decimals >0&& (buffer.length- characters -1) == decimals) {
buffer[characters] =bytes1(uint8(46));
decimals =0; // Cut off any further checks for the decimal place
} elseif (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;
}
}
Contract Source Code
File 6 of 31: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 7 of 31: ERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/ERC721.sol)pragmasolidity ^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";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/contractERC721isContext, ERC165, IERC721, IERC721Metadata{
usingAddressforaddress;
usingStringsforuint256;
// Token namestringprivate _name;
// Token symbolstringprivate _symbol;
// Mapping from token ID to owner addressmapping(uint256=>address) private _owners;
// Mapping owner address to token countmapping(address=>uint256) private _balances;
// Mapping from token ID to approved addressmapping(uint256=>address) private _tokenApprovals;
// Mapping from owner to operator approvalsmapping(address=>mapping(address=>bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/constructor(stringmemory name_, stringmemory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC165, IERC165) returns (bool) {
return
interfaceId ==type(IERC721).interfaceId||
interfaceId ==type(IERC721Metadata).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/functionbalanceOf(address owner) publicviewvirtualoverridereturns (uint256) {
require(owner !=address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/functionownerOf(uint256 tokenId) publicviewvirtualoverridereturns (address) {
address owner = _owners[tokenId];
require(owner !=address(0), "ERC721: owner query for nonexistent token");
return owner;
}
/**
* @dev See {IERC721Metadata-name}.
*/functionname() publicviewvirtualoverridereturns (stringmemory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/functionsymbol() publicviewvirtualoverridereturns (stringmemory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/functiontokenURI(uint256 tokenId) publicviewvirtualoverridereturns (stringmemory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
stringmemory baseURI = _baseURI();
returnbytes(baseURI).length>0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overriden in child contracts.
*/function_baseURI() internalviewvirtualreturns (stringmemory) {
return"";
}
/**
* @dev See {IERC721-approve}.
*/functionapprove(address to, uint256 tokenId) publicvirtualoverride{
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);
}
/**
* @dev See {IERC721-getApproved}.
*/functiongetApproved(uint256 tokenId) publicviewvirtualoverridereturns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/functionsetApprovalForAll(address operator, bool approved) publicvirtualoverride{
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/functionisApprovedForAll(address owner, address operator) publicviewvirtualoverridereturns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) publicvirtualoverride{
//solhint-disable-next-line max-line-lengthrequire(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) publicvirtualoverride{
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytesmemory _data
) publicvirtualoverride{
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* `_data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/function_safeTransfer(addressfrom,
address to,
uint256 tokenId,
bytesmemory _data
) internalvirtual{
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted (`_mint`),
* and stop existing when they are burned (`_burn`).
*/function_exists(uint256 tokenId) internalviewvirtualreturns (bool) {
return _owners[tokenId] !=address(0);
}
/**
* @dev Returns whether `spender` is allowed to manage `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/function_isApprovedOrOwner(address spender, uint256 tokenId) internalviewvirtualreturns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
/**
* @dev Safely mints `tokenId` and transfers it to `to`.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/function_safeMint(address to, uint256 tokenId) internalvirtual{
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/function_safeMint(address to,
uint256 tokenId,
bytesmemory _data
) internalvirtual{
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/function_mint(address to, uint256 tokenId) internalvirtual{
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);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/function_burn(uint256 tokenId) internalvirtual{
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
// Clear approvals
_approve(address(0), tokenId);
_balances[owner] -=1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/function_transfer(addressfrom,
address to,
uint256 tokenId
) internalvirtual{
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);
// Clear approvals from the previous owner
_approve(address(0), tokenId);
_balances[from] -=1;
_balances[to] +=1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* Emits a {Approval} event.
*/function_approve(address to, uint256 tokenId) internalvirtual{
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits a {ApprovalForAll} event.
*/function_setApprovalForAll(address owner,
address operator,
bool approved
) internalvirtual{
require(owner != operator, "ERC721: approve to caller");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return bool whether the call correctly returned the expected magic value
*/function_checkOnERC721Received(addressfrom,
address to,
uint256 tokenId,
bytesmemory _data
) privatereturns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytesmemory reason) {
if (reason.length==0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
returntrue;
}
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, ``from``'s `tokenId` will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/function_beforeTokenTransfer(addressfrom,
address to,
uint256 tokenId
) internalvirtual{}
}
Contract Source Code
File 8 of 31: IBear3TraitProvider.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./IBear3Traits.sol";
/// @title Gen 3 TwoBitBear traits provider/// @notice Provides IBear3Traits to the blockchaininterfaceIBear3TraitProvider{
/// Returns the traits associated with a given token ID/// @dev Throws if the token ID is not valid/// @param tokenId The ID of the token that represents the Bear/// @return traits memoryfunctionbearTraits(uint256 tokenId) externalviewreturns (IBear3Traits.Traits memory);
/// Returns whether a Gen 2 Bear (TwoBitCubs) has breeded a Gen 3 TwoBitBear/// @dev Does not throw if the tokenId is not valid/// @param tokenId The token ID of the Gen 2 bear/// @return Returns whether the Gen 2 Bear has matedfunctionhasGen2Mated(uint256 tokenId) externalviewreturns (bool);
/// Returns whether a Gen 3 Bear has produced a Gen 4 TwoBitBear/// @dev Throws if the token ID is not valid/// @param tokenId The token ID of the Gen 3 bear/// @return Returns whether the Gen 3 Bear has been used for Gen 4 mintingfunctiongeneration4Claimed(uint256 tokenId) externalviewreturns (bool);
/// Returns the scar colors of a given token Id/// @dev Throws if the token ID is not valid or if not revealed/// @param tokenId The token ID of the Gen 3 bear/// @return Returns the scar colorsfunctionscarColors(uint256 tokenId) externalviewreturns (IBear3Traits.ScarColor[] memory);
}
Contract Source Code
File 9 of 31: IBear3Traits.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @title Gen 3 TwoBitBear traits/// @notice Describes the traits of a Gen 3 TwoBitBearinterfaceIBear3Traits{
/// Represents the backgrounds of a Gen 3 TwoBitBearenumBackgroundType {
White, Green, Blue
}
/// Represents the scars of a Gen 3 TwoBitBearenumScarColor {
None, Blue, Magenta, Gold
}
/// Represents the species of a Gen 3 TwoBitBearenumSpeciesType {
Brown, Black, Polar, Panda
}
/// Represents the mood of a Gen 3 TwoBitBearenumMoodType {
Happy, Hungry, Sleepy, Grumpy, Cheerful, Excited, Snuggly, Confused, Ravenous, Ferocious, Hangry, Drowsy, Cranky, Furious
}
/// Represents the traits of a Gen 3 TwoBitBearstructTraits {
BackgroundType background;
MoodType mood;
SpeciesType species;
bool gen4Claimed;
uint8 nameIndex;
uint8 familyIndex;
uint16 firstParentTokenId;
uint16 secondParentTokenId;
uint176 genes;
}
}
Contract Source Code
File 10 of 31: IBearRenderTech.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./IBear3Traits.sol";
/// @title Main Tech for Gen 3 TwoBitBear rendering/// @dev Supports the ERC-721 contractinterfaceIBearRenderTech{
/// Returns the text of a background based on the supplied type/// @param background The BackgroundType/// @return The background textfunctionbackgroundForType(IBear3Traits.BackgroundType background) externalpurereturns (stringmemory);
/// Creates the SVG for a Gen 3 TwoBitBear given its IBear3Traits.Traits and Token Id/// @dev Passes rendering on to a specific species' IBearRenderer/// @param traits The Bear's traits structure/// @param tokenId The Bear's Token Id/// @return The raw xml as bytesfunctioncreateSvg(IBear3Traits.Traits memory traits, uint256 tokenId) externalviewreturns (bytesmemory);
/// Returns the family of a Gen 3 TwoBitBear as a string/// @param traits The Bear's traits structure/// @return The family textfunctionfamilyForTraits(IBear3Traits.Traits memory traits) externalviewreturns (stringmemory);
/// @dev Returns the ERC-721 for a Gen 3 TwoBitBear given its IBear3Traits.Traits and Token Id/// @param traits The Bear's traits structure/// @param tokenId The Bear's Token Id/// @return The raw json as bytesfunctionmetadata(IBear3Traits.Traits memory traits, uint256 tokenId) externalviewreturns (bytesmemory);
/// Returns the text of a mood based on the supplied type/// @param mood The MoodType/// @return The mood textfunctionmoodForType(IBear3Traits.MoodType mood) externalpurereturns (stringmemory);
/// Returns the name of a Gen 3 TwoBitBear as a string/// @param traits The Bear's traits structure/// @return The name textfunctionnameForTraits(IBear3Traits.Traits memory traits) externalviewreturns (stringmemory);
/// Returns the scar colors of a bear with the provided traits/// @param traits The Bear's traits structure/// @return The array of scar colorsfunctionscarsForTraits(IBear3Traits.Traits memory traits) externalviewreturns (IBear3Traits.ScarColor[] memory);
/// Returns the text of a scar based on the supplied color/// @param scarColor The ScarColor/// @return The scar color textfunctionscarForType(IBear3Traits.ScarColor scarColor) externalpurereturns (stringmemory);
/// Returns the text of a species based on the supplied type/// @param species The SpeciesType/// @return The species textfunctionspeciesForType(IBear3Traits.SpeciesType species) externalpurereturns (stringmemory);
}
Contract Source Code
File 11 of 31: IBearRenderTechProvider.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./IBear3Traits.sol";
/// @title Bear RenderTech provider/// @dev Provides IBearRenderTech to an IBearRendererinterfaceIBearRenderTechProvider{
/// Represents a point substitutionstructSubstitution {
uint matchingX;
uint matchingY;
uint replacementX;
uint replacementY;
}
/// Generates an SVG <polygon> element based on a points array and fill color/// @param points The encoded points array/// @param fill The fill attribute/// @param substitutions An array of point substitutions/// @return A <polygon> element as bytesfunctiondynamicPolygonElement(bytesmemory points, bytesmemory fill, Substitution[] memory substitutions) externalviewreturns (bytesmemory);
/// Generates an SVG <linearGradient> element based on a points array and stop colors/// @param id The id of the linear gradient/// @param points The encoded points array/// @param stop1 The first stop attribute/// @param stop2 The second stop attribute/// @return A <linearGradient> element as bytesfunctionlinearGradient(bytesmemory id, bytesmemory points, bytesmemory stop1, bytesmemory stop2) externalviewreturns (bytesmemory);
/// Generates an SVG <path> element based on a points array and fill color/// @param path The encoded path array/// @param fill The fill attribute/// @return A <path> segment as bytesfunctionpathElement(bytesmemory path, bytesmemory fill) externalviewreturns (bytesmemory);
/// Generates an SVG <polygon> segment based on a points array and fill colors/// @param points The encoded points array/// @param fill The fill attribute/// @return A <polygon> segment as bytesfunctionpolygonElement(bytesmemory points, bytesmemory fill) externalviewreturns (bytesmemory);
/// Generates an SVG <rect> element based on a points array and fill color/// @param widthPercentage The width expressed as a percentage of its container/// @param heightPercentage The height expressed as a percentage of its container/// @param attributes Additional attributes for the <rect> element/// @return A <rect> element as bytesfunctionrectElement(uint256 widthPercentage, uint256 heightPercentage, bytesmemory attributes) externalviewreturns (bytesmemory);
}
Contract Source Code
File 12 of 31: IBearRenderer.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"@theappstudio/solidity/contracts/interfaces/ISVGTypes.sol";
import"./IBear3Traits.sol";
import"./ICubTraits.sol";
/// @title Gen 3 TwoBitBear Renderer/// @dev Renders a specific species of a Gen 3 TwoBitBearinterfaceIBearRenderer{
/// The eye ratio to apply based on the genes and token id/// @param genes The Bear's genes/// @param eyeColor The Bear's eye color/// @param scars Zero, One, or Two ScarColors/// @param tokenId The Bear's Token Id/// @return The eye ratio as a uint8functioncustomDefs(uint176 genes, ISVGTypes.Color memory eyeColor, IBear3Traits.ScarColor[] memory scars, uint256 tokenId) externalviewreturns (bytesmemory);
/// Influences the eye color given the dominant parent/// @param dominantParent The Dominant parent bear/// @return The eye colorfunctioncustomEyeColor(ICubTraits.TraitsV1 memory dominantParent) externalviewreturns (ISVGTypes.Color memory);
/// The eye ratio to apply based on the genes and token id/// @param genes The Bear's genes/// @param eyeColor The Bear's eye color/// @param tokenId The Bear's Token Id/// @return The eye ratio as a uint8functioncustomSurfaces(uint176 genes, ISVGTypes.Color memory eyeColor, uint256 tokenId) externalviewreturns (bytesmemory);
}
Contract Source Code
File 13 of 31: ICubTraitProvider.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./ICubTraits.sol";
/// @title TwoBitCubs NFT Interface for provided ICubTraitsinterfaceICubTraitProvider{
/// Returns the family of a TwoBitCub as a string/// @param traits The traits of the Cub/// @return The family textfunctionfamilyForTraits(ICubTraits.TraitsV1 memory traits) externalpurereturns (stringmemory);
/// Returns the text of a mood based on the supplied type/// @param moodType The CubMoodType/// @return The mood textfunctionmoodForType(ICubTraits.CubMoodType moodType) externalpurereturns (stringmemory);
/// Returns the mood of a TwoBitCub based on its TwoBitBear parents/// @param firstParentTokenId The ID of the token that represents the first parent/// @param secondParentTokenId The ID of the token that represents the second parent/// @return The mood typefunctionmoodFromParents(uint256 firstParentTokenId, uint256 secondParentTokenId) externalviewreturns (ICubTraits.CubMoodType);
/// Returns the name of a TwoBitCub as a string/// @param traits The traits of the Cub/// @return The name textfunctionnameForTraits(ICubTraits.TraitsV1 memory traits) externalpurereturns (stringmemory);
/// Returns the text of a species based on the supplied type/// @param speciesType The CubSpeciesType/// @return The species textfunctionspeciesForType(ICubTraits.CubSpeciesType speciesType) externalpurereturns (stringmemory);
/// Returns the v1 traits associated with a given token ID./// @dev Throws if the token ID is not valid./// @param tokenId The ID of the token that represents the Cub/// @return traits memoryfunctiontraitsV1(uint256 tokenId) externalviewreturns (ICubTraits.TraitsV1 memory traits);
}
Contract Source Code
File 14 of 31: ICubTraits.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"@theappstudio/solidity/contracts/interfaces/ISVGTypes.sol";
/// @title ICubTraits interfaceinterfaceICubTraits{
/// Represents the species of a TwoBitCubenumCubSpeciesType {
Brown, Black, Polar, Panda
}
/// Represents the mood of a TwoBitCubenumCubMoodType {
Happy, Hungry, Sleepy, Grumpy, Cheerful, Excited, Snuggly, Confused, Ravenous, Ferocious, Hangry, Drowsy, Cranky, Furious
}
/// Represents the DNA for a TwoBitCub/// @dev organized to fit within 256 bits and consume the least amount of resourcesstructDNA {
uint16 firstParentTokenId;
uint16 secondParentTokenId;
uint224 genes;
}
/// Represents the v1 traits of a TwoBitCubstructTraitsV1 {
uint256 age;
ISVGTypes.Color topColor;
ISVGTypes.Color bottomColor;
uint8 nameIndex;
uint8 familyIndex;
CubMoodType mood;
CubSpeciesType species;
}
}
Contract Source Code
File 15 of 31: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 16 of 31: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721isIERC165{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/functionapprove(address to, uint256 tokenId) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) external;
}
Contract Source Code
File 17 of 31: IERC721Enumerable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Enumerable.sol)pragmasolidity ^0.8.0;import"../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/interfaceIERC721EnumerableisIERC721{
/**
* @dev Returns the total amount of tokens stored by the contract.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/functiontokenOfOwnerByIndex(address owner, uint256 index) externalviewreturns (uint256 tokenId);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/functiontokenByIndex(uint256 index) externalviewreturns (uint256);
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)pragmasolidity ^0.8.0;/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/interfaceIERC721Receiver{
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
*/functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 20 of 31: ISVGTypes.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @title ISVG image library types interface/// @dev Allows Solidity files to reference the library's input and return types without referencing the library itselfinterfaceISVGTypes{
/// Represents a color in RGB format with alphastructColor {
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha;
}
/// Represents a color attribute in an SVG image fileenumColorAttribute {
Fill, Stroke, Stop
}
/// Represents the kind of color attribute in an SVG image fileenumColorAttributeKind {
RGB, URL
}
}
Contract Source Code
File 21 of 31: OnChain.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;import"base64-sol/base64.sol";
/// @title OnChain metadata support library/**
* @dev These methods are best suited towards view/pure only function calls (ALL the way through the call stack).
* Do not waste gas using these methods in functions that also update state, unless your need requires it.
*/libraryOnChain{
/// Returns the prefix needed for a base64-encoded on chain svg imagefunctionbaseSvgImageURI() internalpurereturns (bytesmemory) {
return"data:image/svg+xml;base64,";
}
/// Returns the prefix needed for a base64-encoded on chain nft metadatafunctionbaseURI() internalpurereturns (bytesmemory) {
return"data:application/json;base64,";
}
/// Returns the contents joined with a comma between them/// @param contents1 The first content to join/// @param contents2 The second content to join/// @return A collection of bytes that represent all contents joined with a commafunctioncommaSeparated(bytesmemory contents1, bytesmemory contents2) internalpurereturns (bytesmemory) {
returnabi.encodePacked(contents1, continuesWith(contents2));
}
/// Returns the contents joined with commas between them/// @param contents1 The first content to join/// @param contents2 The second content to join/// @param contents3 The third content to join/// @return A collection of bytes that represent all contents joined with commasfunctioncommaSeparated(bytesmemory contents1, bytesmemory contents2, bytesmemory contents3) internalpurereturns (bytesmemory) {
returnabi.encodePacked(commaSeparated(contents1, contents2), continuesWith(contents3));
}
/// Returns the contents joined with commas between them/// @param contents1 The first content to join/// @param contents2 The second content to join/// @param contents3 The third content to join/// @param contents4 The fourth content to join/// @return A collection of bytes that represent all contents joined with commasfunctioncommaSeparated(bytesmemory contents1, bytesmemory contents2, bytesmemory contents3, bytesmemory contents4) internalpurereturns (bytesmemory) {
returnabi.encodePacked(commaSeparated(contents1, contents2, contents3), continuesWith(contents4));
}
/// Returns the contents joined with commas between them/// @param contents1 The first content to join/// @param contents2 The second content to join/// @param contents3 The third content to join/// @param contents4 The fourth content to join/// @param contents5 The fifth content to join/// @return A collection of bytes that represent all contents joined with commasfunctioncommaSeparated(bytesmemory contents1, bytesmemory contents2, bytesmemory contents3, bytesmemory contents4, bytesmemory contents5) internalpurereturns (bytesmemory) {
returnabi.encodePacked(commaSeparated(contents1, contents2, contents3, contents4), continuesWith(contents5));
}
/// Returns the contents joined with commas between them/// @param contents1 The first content to join/// @param contents2 The second content to join/// @param contents3 The third content to join/// @param contents4 The fourth content to join/// @param contents5 The fifth content to join/// @param contents6 The sixth content to join/// @return A collection of bytes that represent all contents joined with commasfunctioncommaSeparated(bytesmemory contents1, bytesmemory contents2, bytesmemory contents3, bytesmemory contents4, bytesmemory contents5, bytesmemory contents6) internalpurereturns (bytesmemory) {
returnabi.encodePacked(commaSeparated(contents1, contents2, contents3, contents4, contents5), continuesWith(contents6));
}
/// Returns the contents prefixed by a comma/// @dev This is used to append multiple attributes into the json/// @param contents The contents with which to prefix/// @return A bytes collection of the contents prefixed with a commafunctioncontinuesWith(bytesmemory contents) internalpurereturns (bytesmemory) {
returnabi.encodePacked(",", contents);
}
/// Returns the contents wrapped in a json dictionary/// @param contents The contents with which to wrap/// @return A bytes collection of the contents wrapped as a json dictionaryfunctiondictionary(bytesmemory contents) internalpurereturns (bytesmemory) {
returnabi.encodePacked("{", contents, "}");
}
/// Returns an unwrapped key/value pair where the value is an array/// @param key The name of the key used in the pair/// @param value The value of pair, as an array/// @return A bytes collection that is suitable for inclusion in a larger dictionaryfunctionkeyValueArray(stringmemory key, bytesmemory value) internalpurereturns (bytesmemory) {
returnabi.encodePacked("\"", key, "\":[", value, "]");
}
/// Returns an unwrapped key/value pair where the value is a string/// @param key The name of the key used in the pair/// @param value The value of pair, as a string/// @return A bytes collection that is suitable for inclusion in a larger dictionaryfunctionkeyValueString(stringmemory key, bytesmemory value) internalpurereturns (bytesmemory) {
returnabi.encodePacked("\"", key, "\":\"", value, "\"");
}
/// Encodes an SVG as base64 and prefixes it with a URI scheme suitable for on-chain data/// @param svg The contents of the svg/// @return A bytes collection that may be added to the "image" key/value pair in ERC-721 or ERC-1155 metadatafunctionsvgImageURI(bytesmemory svg) internalpurereturns (bytesmemory) {
returnabi.encodePacked(baseSvgImageURI(), Base64.encode(svg));
}
/// Encodes json as base64 and prefixes it with a URI scheme suitable for on-chain data/// @param metadata The contents of the metadata/// @return A bytes collection that may be returned as the tokenURI in a ERC-721 or ERC-1155 contractfunctiontokenURI(bytesmemory metadata) internalpurereturns (bytesmemory) {
returnabi.encodePacked(baseURI(), Base64.encode(metadata));
}
/// Returns the json dictionary of a single trait attribute for an ERC-721 or ERC-1155 NFT/// @param name The name of the trait/// @param value The value of the trait/// @return A collection of bytes that can be embedded within a larger array of attributesfunctiontraitAttribute(stringmemory name, bytesmemory value) internalpurereturns (bytesmemory) {
return dictionary(commaSeparated(
keyValueString("trait_type", bytes(name)),
keyValueString("value", value)
));
}
}
Contract Source Code
File 22 of 31: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)pragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 23 of 31: Randomization.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;import"./RandomizationErrors.sol";
/// @title Randomization library/// @dev Lightweight library used for basic randomization capabilities for ERC-721 tokens when an Oracle is not availablelibraryRandomization{
/// Returns a value based on the spread of a random uint8 seed and provided percentages/// @dev The last percentage is assumed if the sum of all elements do not add up to 100, in which case the length of the array is returned/// @param random A uint8 random value/// @param percentages An array of percentages/// @return The index in which the random seed falls, which can be the length of the input array if the values do not add up to 100functionrandomIndex(uint8 random, uint8[] memory percentages) internalpurereturns (uint256) {
uint256 spread = (3921*uint256(random) /10000) %100; // 0-255 needs to be balanced to evenly spread with % 100uint256 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;
}
/// Returns a random seed suitable for ERC-721 attribute generation when an Oracle such as Chainlink VRF is not available to a contract/// @dev Not suitable for mission-critical code. Always be sure to perform an analysis of your randomization before deploying to production/// @param initialSeed A uint256 that seeds the randomization function/// @return A seed that can be used for attribute generation, which may also be used as the `initialSeed` for a future callfunctionrandomSeed(uint256 initialSeed) internalviewreturns (uint256) {
// Unit tests should confirm that this provides a more-or-less even spread of randomnessreturnuint256(keccak256(abi.encodePacked(blockhash(block.number-1), msg.sender, initialSeed >>1)));
}
}
Contract Source Code
File 24 of 31: RandomizationErrors.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;/// @dev When the percentages array sum up to more than 100errorPercentagesGreaterThan100();
Contract Source Code
File 25 of 31: SVG.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;import"@openzeppelin/contracts/utils/Strings.sol";
import"../interfaces/ISVGTypes.sol";
import"./OnChain.sol";
import"./SVGErrors.sol";
/// @title SVG image library/**
* @dev These methods are best suited towards view/pure only function calls (ALL the way through the call stack).
* Do not waste gas using these methods in functions that also update state, unless your need requires it.
*/librarySVG{
usingStringsforuint256;
/// Returns a named element based on the supplied attributes and contents/// @dev attributes and contents is usually generated from abi.encodePacked, attributes is expecting a leading space/// @param name The name of the element/// @param attributes The attributes of the element, as bytes, with a leading space/// @param contents The contents of the element, as bytes/// @return a bytes collection representing the whole elementfunctioncreateElement(stringmemory name, bytesmemory attributes, bytesmemory contents) internalpurereturns (bytesmemory) {
returnabi.encodePacked(
"<", attributes.length==0 ? bytes(name) : abi.encodePacked(name, attributes),
contents.length==0 ? bytes("/>") : abi.encodePacked(">", contents, "</", name, ">")
);
}
/// Returns the root SVG attributes based on the supplied width and height/// @dev includes necessary leading space for createElement's `attributes` parameter/// @param width The width of the SVG view box/// @param height The height of the SVG view box/// @return a bytes collection representing the root SVG attributes, including a leading spacefunctionsvgAttributes(uint256 width, uint256 height) internalpurereturns (bytesmemory) {
returnabi.encodePacked(" viewBox='0 0 ", width.toString(), " ", height.toString(), "' xmlns='http://www.w3.org/2000/svg'");
}
/// Returns an RGB bytes collection suitable as an attribute for SVG elements based on the supplied Color and ColorType/// @dev includes necessary leading space for all types _except_ None/// @param attribute The `ISVGTypes.ColorAttribute` of the desired attribute/// @param value The converted color value as bytes/// @return a bytes collection representing a color attribute in an SVG elementfunctioncolorAttribute(ISVGTypes.ColorAttribute attribute, bytesmemory value) internalpurereturns (bytesmemory) {
if (attribute == ISVGTypes.ColorAttribute.Fill) return _attribute("fill", value);
if (attribute == ISVGTypes.ColorAttribute.Stop) return _attribute("stop-color", value);
return _attribute("stroke", value); // Fallback to Stroke
}
/// Returns an RGB color attribute value/// @param color The `ISVGTypes.Color` of the color/// @return a bytes collection representing the url attribute valuefunctioncolorAttributeRGBValue(ISVGTypes.Color memory color) internalpurereturns (bytesmemory) {
return _colorValue(ISVGTypes.ColorAttributeKind.RGB, OnChain.commaSeparated(
bytes(uint256(color.red).toString()),
bytes(uint256(color.green).toString()),
bytes(uint256(color.blue).toString())
));
}
/// Returns a URL color attribute value/// @param url The url to the color/// @return a bytes collection representing the url attribute valuefunctioncolorAttributeURLValue(bytesmemory url) internalpurereturns (bytesmemory) {
return _colorValue(ISVGTypes.ColorAttributeKind.URL, url);
}
/// Returns an `ISVGTypes.Color` that is brightened by the provided percentage/// @param source The `ISVGTypes.Color` to brighten/// @param percentage The percentage of brightness to apply/// @param minimumBump A minimum increase for each channel to ensure dark Colors also brighten/// @return color the brightened `ISVGTypes.Color`functionbrightenColor(ISVGTypes.Color memory source, uint32 percentage, uint8 minimumBump) internalpurereturns (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;
}
/// Returns an `ISVGTypes.Color` based on a packed representation of r, g, and b/// @notice Useful for code where you want to utilize rgb hex values provided by a designer (e.g. #835525)/// @dev Alpha will be hard-coded to 100% opacity/// @param packedColor The `ISVGTypes.Color` to convert, e.g. 0x835525/// @return color representing the packed inputfunctionfromPackedColor(uint24 packedColor) internalpurereturns (ISVGTypes.Color memory color) {
color.red =uint8(packedColor >>16);
color.green =uint8(packedColor >>8);
color.blue =uint8(packedColor);
color.alpha =0xFF;
}
/// Returns a mixed Color by balancing the ratio of `color1` over `color2`, with a total percentage (for overmixing and undermixing outside the source bounds)/// @dev Reverts with `RatioInvalid()` if `ratioPercentage` is > 100/// @param color1 The first `ISVGTypes.Color` to mix/// @param color2 The second `ISVGTypes.Color` to mix/// @param ratioPercentage The percentage ratio of `color1` over `color2` (e.g. 60 = 60% first, 40% second)/// @param totalPercentage The total percentage after mixing (for overmixing and undermixing outside the input colors)/// @return color representing the result of the mixturefunctionmixColors(ISVGTypes.Color memory color1, ISVGTypes.Color memory color2, uint32 ratioPercentage, uint32 totalPercentage) internalpurereturns (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);
}
/// Returns a proportionally-randomized Color between the start and stop colors using a random Color seed/// @dev Each component (r,g,b) will move proportionally together in the direction from start to stop/// @param start The starting bound of the `ISVGTypes.Color` to randomize/// @param stop The stopping bound of the `ISVGTypes.Color` to randomize/// @param random An `ISVGTypes.Color` to use as a seed for randomization/// @return color representing the result of the randomizationfunctionrandomizeColors(ISVGTypes.Color memory start, ISVGTypes.Color memory stop, ISVGTypes.Color memory random) internalpurereturns (ISVGTypes.Color memory color) {
uint16 percent =uint16((1320* (uint(random.red) +uint(random.green) +uint(random.blue)) /10000) %101); // Range is from 0-100
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(bytesmemory name, bytesmemory contents) privatepurereturns (bytesmemory) {
returnabi.encodePacked(" ", name, "='", contents, "'");
}
function_brightenComponent(uint8 component, uint32 percentage, uint8 minimumBump) privatepurereturns (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; // Clamp to 8 bits
} else {
result =uint8(brightenedComponent);
}
}
function_colorValue(ISVGTypes.ColorAttributeKind attributeKind, bytesmemory contents) privatepurereturns (bytesmemory) {
returnabi.encodePacked(attributeKind == ISVGTypes.ColorAttributeKind.RGB ? "rgb(" : "url(#", contents, ")");
}
function_mixComponents(uint8 component1, uint8 component2, uint32 ratioPercentage, uint32 totalPercentage) privatepurereturns (uint8 component) {
uint32 mixedComponent = (uint32(component1) * ratioPercentage +uint32(component2) * (100- ratioPercentage)) * totalPercentage /10000;
if (mixedComponent >0xFF) {
component =0xFF; // Clamp to 8 bits
} else {
component =uint8(mixedComponent);
}
}
function_randomizeComponent(uint8 start, uint8 stop, uint8 random, uint16 percent) privatepurereturns (uint8 component) {
if (start == stop) {
component = start;
} else { // This is the standard case
(uint8 floor, uint8 ceiling) = start < stop ? (start, stop) : (stop, start);
component = floor +uint8(uint16(ceiling - (random &0x01) - floor) * percent /uint16(100));
}
}
}
Contract Source Code
File 26 of 31: SVGErrors.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;/// @dev When the ratio percentage provided to a function is > 100errorRatioInvalid();
Contract Source Code
File 27 of 31: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)pragmasolidity ^0.8.0;/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant _HEX_SYMBOLS ="0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
// Inspired by OraclizeAPI's implementation - MIT licence// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.solif (value ==0) {
return"0";
}
uint256 temp = value;
uint256 digits;
while (temp !=0) {
digits++;
temp /=10;
}
bytesmemory buffer =newbytes(digits);
while (value !=0) {
digits -=1;
buffer[digits] =bytes1(uint8(48+uint256(value %10)));
value /=10;
}
returnstring(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
if (value ==0) {
return"0x00";
}
uint256 temp = value;
uint256 length =0;
while (temp !=0) {
length++;
temp >>=8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory) {
bytesmemory buffer =newbytes(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");
returnstring(buffer);
}
}
Contract Source Code
File 28 of 31: TwoBitBears3.sol
// SPDX-License-Identifier: MITpragmasolidity ^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";
/// @title TwoBitBears3contractTwoBitBears3isERC721, IBear3TraitProvider, IERC721Enumerable, Ownable{
/// @dev Reference to the BearRenderTech contract
IBearRenderTech privateimmutable _bearRenderTech;
/// @dev Stores the cubs Adult Age so that it doesn't need to be queried for every mintuint256privateimmutable _cubAdultAge;
/// @dev Precalculated eligibility for cubsuint256[] private _cubEligibility;
/// @dev Stores bear token ids that have already minted gen 4mapping(uint256=>bool) private _generation4Claims;
/// @dev The contract for Gen 4addressprivate _gen4Contract;
/// @dev Stores cub token ids that have already matedmapping(uint256=>bool) private _matedCubs;
/// @dev Seed for randomnessuint256private _seed;
/// @dev Array of TokenIds to DNAuint256[] private _tokenIdsToDNA;
/// @dev Reference to the TwoBitCubs contract
TwoBitCubs privateimmutable _twoBitCubs;
/// Look...at these...Bearsconstructor(uint256 seed, address renderTech, address twoBitCubs) ERC721("TwoBitBears3", "TB3") {
_seed = seed;
_bearRenderTech = IBearRenderTech(renderTech);
_twoBitCubs = TwoBitCubs(twoBitCubs);
_cubAdultAge = _twoBitCubs.ADULT_AGE();
}
/// Applies calculated slots of gen 2 eligibility to reduce gasfunctionapplySlots(uint256[] calldata slotIndices, uint256[] calldata slotValues) externalonlyOwner{
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);
} elseif (_cubEligibility[slotIndex] != slotValue) {
_cubEligibility[slotIndex] = slotValue;
}
}
}
/// Assigns the Gen 4 contract address for message caller verificationfunctionassignGen4(address gen4Contract) externalonlyOwner{
if (gen4Contract ==address(0)) revert InvalidAddress();
_gen4Contract = gen4Contract;
}
/// @inheritdoc IBear3TraitProviderfunctionbearTraits(uint256 tokenId) externalviewonlyWhenExists(tokenId) returns (IBear3Traits.Traits memory) {
return _traitsForToken(tokenId);
}
/// Calculates the current values for a slotfunctioncalculateSlot(uint256 slotIndex, uint256 totalTokens) externalviewonlyOwnerreturns (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; // Reset because there's nothing worth writing
}
}
/// Marks the Gen 3 Bear as having minted a Gen 4 BearfunctionclaimGen4(uint256 tokenId) externalonlyWhenExists(tokenId) {
if (_gen4Contract ==address(0) || _msgSender() != _gen4Contract) revert InvalidCaller();
_generation4Claims[tokenId] =true;
}
/// @notice For easy import into MetaMaskfunctiondecimals() externalpurereturns (uint256) {
return0;
}
/// @inheritdoc IBear3TraitProviderfunctionhasGen2Mated(uint256 tokenId) externalviewreturns (bool) {
return _matedCubs[tokenId];
}
/// @inheritdoc IBear3TraitProviderfunctiongeneration4Claimed(uint256 tokenId) externalviewonlyWhenExists(tokenId) returns (bool) {
return _generation4Claims[tokenId];
}
functionslotParameters() externalviewonlyOwnerreturns (uint256 totalSlots, uint256 totalTokens) {
totalTokens = _twoBitCubs.totalSupply();
totalSlots =1+ totalTokens /32;
}
/// Exposes the raw image SVG to the world, for any applications that can take advantagefunctionimageSVG(uint256 tokenId) externalviewreturns (stringmemory) {
returnstring(_imageBytes(tokenId));
}
/// Exposes the image URI to the world, for any applications that can take advantagefunctionimageURI(uint256 tokenId) externalviewreturns (stringmemory) {
returnstring(OnChain.svgImageURI(_imageBytes(tokenId)));
}
/// Mints the provided quantity of TwoBitBear3 tokens/// @param parentOne The first gen 2 bear parent, which also determines the mood/// @param parentTwo The second gen 2 bear parentfunctionmateBears(uint256 parentOne, uint256 parentTwo) external{
// Check eligibilityif (_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);
// Prepare mint
_matedCubs[parentOne] =true;
_matedCubs[parentTwo] =true;
uint seed = Randomization.randomSeed(_seed);
// seed (208) | parent one (16) | parent two (16) | species (8) | mood (8)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, ""); // Reentrancy is possible here
}
/// @notice Returns expected gas usage based on selected parents, with a small buffer for safety/// @dev Does not check for ownership or whether parents have already matedfunctionmatingGas(address minter, uint256 parentOne, uint256 parentTwo) externalviewreturns (uint256 result) {
result =146000; // Lowest gas cost to mintif (_tokenIdsToDNA.length==0) {
result +=16500;
}
if (balanceOf(minter) ==0) {
result +=17500;
}
// Fetching eligibility of parents will cost additional gasuint 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;
}
// There's some overhead for a single fetchif (fetchCount ==1) {
result +=10000;
}
}
/// Prevents a function from executing if the tokenId does not existmodifieronlyWhenExists(uint256 tokenId) {
if (!_exists(tokenId)) revert InvalidTokenId();
_;
}
/// @inheritdoc IBear3TraitProviderfunctionscarColors(uint256 tokenId) externalviewonlyWhenExists(tokenId) returns (IBear3Traits.ScarColor[] memory) {
IBear3Traits.Traits memory traits = _traitsForToken(tokenId);
return _bearRenderTech.scarsForTraits(traits);
}
/// @inheritdoc IERC165functionsupportsInterface(bytes4 interfaceId) publicviewoverride(IERC165, ERC721) returns (bool) {
return interfaceId ==type(IERC721Enumerable).interfaceId||super.supportsInterface(interfaceId);
}
/// @inheritdoc IERC721EnumerablefunctiontokenByIndex(uint256 index) externalviewreturns (uint256) {
require(index <this.totalSupply(), "global index out of bounds");
return index; // Burning is not exposed by this contract so we can simply return the index
}
/// @inheritdoc IERC721Enumerable/// @dev This implementation is for the benefit of web3 sites -- it is extremely expensive for contracts to call on-chainfunctiontokenOfOwnerByIndex(address owner_, uint256 index) externalviewreturns (uint256 tokenId) {
require(index < ERC721.balanceOf(owner_), "owner index out of bounds");
for (uint tokenIndex =0; tokenIndex < _tokenIdsToDNA.length; tokenIndex++) {
// Use _exists() to avoid a possible revert when accessing OpenZeppelin's ownerOf(), despite not exposing _burn()if (_exists(tokenIndex) && ownerOf(tokenIndex) == owner_) {
if (index ==0) {
tokenId = tokenIndex;
break;
}
index--;
}
}
}
/// @inheritdoc IERC721MetadatafunctiontokenURI(uint256 tokenId) publicviewoverrideonlyWhenExists(tokenId) returns (stringmemory) {
IBear3Traits.Traits memory traits = _traitsForToken(tokenId);
returnstring(OnChain.tokenURI(_bearRenderTech.metadata(traits, tokenId)));
}
/// @inheritdoc IERC721EnumerablefunctiontotalSupply() externalviewreturns (uint256) {
return _tokenIdsToDNA.length; // We don't expose _burn() so the .length suffices
}
function_eligibility(uint256 parent) privateviewreturns (uint8 result) {
uint slotIndex = parent /32;
if (slotIndex < _cubEligibility.length) {
result =uint8(_cubEligibility[slotIndex] >> ((parent %32) *8));
}
}
function_getEligibility(uint256 parent) privateviewreturns (uint8 result) {
// Check the precalculated eligibility
result = _eligibility(parent);
if (result <0x80) {
// We need to go get the latest information from the Cubs contract
result = _packedInfo(_twoBitCubs.traitsV1(parent));
}
}
function_imageBytes(uint256 tokenId) privateviewonlyWhenExists(tokenId) returns (bytesmemory) {
IBear3Traits.Traits memory traits = _traitsForToken(tokenId);
return _bearRenderTech.createSvg(traits, tokenId);
}
function_traitsForToken(uint256 tokenId) privateviewreturns (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) privateviewreturns (uint8 info) {
info |=uint8(traits.species);
info |=uint8(traits.mood) <<2;
if (traits.age >= _cubAdultAge) {
info |=0x80;
}
}
}
Contract Source Code
File 29 of 31: TwoBitBears3Errors.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;/// @dev The address passed in is not allowederrorInvalidAddress();
/// @dev The caller of the method is not allowederrorInvalidCaller();
/// @dev When the parent identifiers are not unique or not of the same specieserrorInvalidParentCombination();
/// @dev When the TwoBitBear3 tokenId does not existerrorInvalidTokenId();
/// @dev When the parent has already matederrorParentAlreadyMated(uint256 tokenId);
/// @dev When the parent is not owned by the callererrorParentNotOwned(uint256 tokenId);
/// @dev When the parent is not yet an adulterrorParentTooYoung(uint256 tokenId);
Contract Source Code
File 30 of 31: TwoBitCubs.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import"../interfaces/ICubTraitProvider.sol";
/// @title TwoBitCubsabstractcontractTwoBitCubsisIERC721Enumerable, ICubTraitProvider{
/// @dev The number of blocks until a growing cub becomes an adult (roughly 1 week)uint256publicconstant ADULT_AGE =44000;
}
Contract Source Code
File 31 of 31: base64.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0;/// @title Base64/// @author Brecht Devos - <brecht@loopring.org>/// @notice Provides functions for encoding/decoding base64libraryBase64{
stringinternalconstant TABLE_ENCODE ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
bytesinternalconstant TABLE_DECODE =hex"0000000000000000000000000000000000000000000000000000000000000000"hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";
functionencode(bytesmemory data) internalpurereturns (stringmemory) {
if (data.length==0) return'';
// load the table into memorystringmemory table = TABLE_ENCODE;
// multiply by 4/3 rounded upuint256 encodedLen =4* ((data.length+2) /3);
// add some extra buffer at the end required for the writingstringmemory result =newstring(encodedLen +32);
assembly {
// set the actual output lengthmstore(result, encodedLen)
// prepare the lookup tablelet tablePtr :=add(table, 1)
// input ptrlet dataPtr := data
let endPtr :=add(dataPtr, mload(data))
// result ptr, jump over lengthlet resultPtr :=add(result, 32)
// run over the input, 3 bytes at a timefor {} lt(dataPtr, endPtr) {}
{
// read 3 bytes
dataPtr :=add(dataPtr, 3)
let input :=mload(dataPtr)
// write 4 charactersmstore8(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)
}
// padding with '='switchmod(mload(data), 3)
case1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
case2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
}
return result;
}
functiondecode(stringmemory _data) internalpurereturns (bytesmemory) {
bytesmemory data =bytes(_data);
if (data.length==0) returnnewbytes(0);
require(data.length%4==0, "invalid base64 decoder input");
// load the table into memorybytesmemory table = TABLE_DECODE;
// every 4 characters represent 3 bytesuint256 decodedLen = (data.length/4) *3;
// add some extra buffer at the end required for the writingbytesmemory result =newbytes(decodedLen +32);
assembly {
// padding with '='let lastBytes :=mload(add(data, mload(data)))
ifeq(and(lastBytes, 0xFF), 0x3d) {
decodedLen :=sub(decodedLen, 1)
ifeq(and(lastBytes, 0xFFFF), 0x3d3d) {
decodedLen :=sub(decodedLen, 1)
}
}
// set the actual output lengthmstore(result, decodedLen)
// prepare the lookup tablelet tablePtr :=add(table, 1)
// input ptrlet dataPtr := data
let endPtr :=add(dataPtr, mload(data))
// result ptr, jump over lengthlet resultPtr :=add(result, 32)
// run over the input, 4 characters at a timefor {} lt(dataPtr, endPtr) {}
{
// read 4 characters
dataPtr :=add(dataPtr, 4)
let input :=mload(dataPtr)
// write 3 byteslet 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;
}
}