// SPDX-License-Identifier: MITpragmasolidity ^0.8.13;import {OperatorFilterer} from"./OperatorFilterer.sol";
/**
* @title DefaultOperatorFilterer
* @notice Inherits from OperatorFilterer and automatically subscribes to the default OpenSea subscription.
*/abstractcontractDefaultOperatorFiltererisOperatorFilterer{
addressconstant DEFAULT_SUBSCRIPTION =address(0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6);
constructor() OperatorFilterer(DEFAULT_SUBSCRIPTION, true) {}
}
Contract Source Code
File 2 of 14: 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 3 of 14: ERC2981.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)pragmasolidity ^0.8.0;import"../../interfaces/IERC2981.sol";
import"../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*
* _Available since v4.5._
*/abstractcontractERC2981isIERC2981, ERC165{
structRoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256=> RoyaltyInfo) private _tokenRoyaltyInfo;
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(IERC165, ERC165) returns (bool) {
return interfaceId ==type(IERC2981).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IERC2981
*/functionroyaltyInfo(uint256 _tokenId, uint256 _salePrice) publicviewvirtualoverridereturns (address, uint256) {
RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];
if (royalty.receiver ==address(0)) {
royalty = _defaultRoyaltyInfo;
}
uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/function_feeDenominator() internalpurevirtualreturns (uint96) {
return10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/function_setDefaultRoyalty(address receiver, uint96 feeNumerator) internalvirtual{
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver !=address(0), "ERC2981: invalid receiver");
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Removes default royalty information.
*/function_deleteDefaultRoyalty() internalvirtual{
delete _defaultRoyaltyInfo;
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/function_setTokenRoyalty(uint256 tokenId,
address receiver,
uint96 feeNumerator
) internalvirtual{
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver !=address(0), "ERC2981: Invalid parameters");
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/function_resetTokenRoyalty(uint256 tokenId) internalvirtual{
delete _tokenRoyaltyInfo[tokenId];
}
}
Contract Source Code
File 4 of 14: 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 5 of 14: IERC2981.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)pragmasolidity ^0.8.0;import"../utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/interfaceIERC2981isIERC165{
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
*/functionroyaltyInfo(uint256 tokenId, uint256 salePrice)
externalviewreturns (address receiver, uint256 royaltyAmount);
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.19;import"@openzeppelin/contracts/token/common/ERC2981.sol";
structToken {
address owner;
uint16 linkedNext;
uint16 linkedPrev;
uint32 stakeTimestamp;
uint8 generation;
uint8 incubationPhase;
uint16 bit;
}
structWallet {
uint16 balance;
uint16 stakes;
uint16 linkedMints;
uint16 batchedMints;
uint16 allowlistMints;
uint16 privateMints;
uint16 holderMints;
uint16 redeems;
}
structMintCounters {
uint16 linked;
uint16 batched;
uint16 redeems;
uint16 stakes;
}
interfaceIIncubator{
functionadd(address owner, uint256[] calldata tokenIds) external;
functionadd(address owner, uint256 start, uint256 count) external;
functionremove(address owner, uint256[] calldata tokenIds) external;
functionremove(address owner, uint256 start, uint256 count) external;
}
interfaceIERC721Receiver{
functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
abstractcontractKillaCubsERC721isERC2981{
stringpublic name;
stringpublic symbol;
IIncubator public incubator;
MintCounters public counters;
mapping(address=> Wallet) public wallets;
mapping(uint256=> Token) public tokens;
mapping(uint256=>address) private tokenApprovals;
mapping(address=>mapping(address=>bool)) private operatorApprovals;
errorTransferToNonERC721ReceiverImplementer();
errorNonExistentToken();
errorNotAllowed();
errorOverflow();
eventTransfer(addressindexedfrom,
addressindexed to,
uint256indexed tokenId
);
eventApproval(addressindexed owner,
addressindexed approved,
uint256indexed tokenId
);
eventApprovalForAll(addressindexed owner,
addressindexed operator,
bool approved
);
constructor() {
name ="KillaCubs";
symbol ="KillaCubs";
_setDefaultRoyalty(msg.sender, 500);
}
function_mint(address to, uint256 n, bool staked) internal{
uint256 tokenId =3334+ counters.batched;
uint256 end = tokenId + n -1;
if (end >8888) revert NotAllowed();
Token storage token = tokens[tokenId];
token.owner = to;
counters.batched +=uint16(n);
wallets[to].batchedMints +=uint16(n);
if (staked) {
incubator.add(to, tokenId, n);
token.stakeTimestamp =uint32(block.timestamp);
counters.stakes +=uint16(n);
wallets[to].stakes +=uint16(n);
while (tokenId <= end) {
emit Transfer(address(0), to, tokenId);
emit Transfer(to, address(this), tokenId);
tokenId++;
}
} else {
wallets[to].balance+=uint16(n);
while (tokenId <= end) {
emit Transfer(address(0), to, tokenId);
tokenId++;
}
}
}
function_mint(address to,
uint256[] calldata tokenIds,
bool staked
) internal{
for (uint256 i =0; i < tokenIds.length; i++) {
uint256 id = tokenIds[i];
Token storage token = tokens[id];
if (id ==0) revert NotAllowed();
if (token.owner !=address(0)) revert NotAllowed();
if (token.linkedPrev !=0) revert NotAllowed();
token.owner = to;
emit Transfer(address(0), to, id);
if (staked) {
emit Transfer(to, address(this), id);
token.stakeTimestamp =uint32(block.timestamp);
}
if (i ==0) {
token.owner = to;
} else {
token.linkedPrev =uint16(tokenIds[i -1]);
tokens[tokenIds[i -1]].linkedNext =uint16(id);
}
}
counters.linked +=uint16(tokenIds.length);
if (staked) {
counters.stakes +=uint16(tokenIds.length);
wallets[to].stakes +=uint16(tokenIds.length);
incubator.add(to, tokenIds);
} else {
wallets[to].balance+=uint16(tokenIds.length);
}
wallets[to].linkedMints +=uint16(tokenIds.length);
}
functiontotalSupply() publicviewvirtualreturns (uint256) {
return counters.linked + counters.batched;
}
functionbalanceOf(address owner
) externalviewvirtualreturns (uint256 balance) {
if (owner ==address(this)) return counters.stakes;
return wallets[owner].balance;
}
functionownerOf(uint256 id) publicviewvirtualreturns (address) {
Token memory token = resolveToken(id);
if (token.stakeTimestamp !=0) returnaddress(this);
return token.owner;
}
functionrightfulOwnerOf(uint256 tokenId
) publicviewvirtualreturns (address) {
return resolveToken(tokenId).owner;
}
functionresolveToken(uint256 id) publicviewreturns (Token memory) {
Token memory token = tokens[id];
if (token.owner ==address(0)) {
Token memory temp = token;
if (token.linkedPrev !=0) {
do token = tokens[token.linkedPrev]; while (
token.owner ==address(0)
);
} elseif (id >3333&& id <=3333+ counters.batched) {
do token = tokens[--id]; while (token.owner ==address(0));
} else {
revert NonExistentToken();
}
token.bit = temp.bit;
token.linkedNext = temp.linkedNext;
token.linkedPrev = temp.linkedPrev;
}
return token;
}
functionresolveTokens(uint256[] calldata ids
) publicviewreturns (Token[] memory) {
Token[] memory ret =new Token[](ids.length);
bool skip =false;
Token memory token;
for (uint256 i =0; i < ids.length; i++) {
uint256 id = ids[i];
if (skip) skip =false;
else token = resolveToken(id);
ret[i] = token;
uint256 nextId;
if (token.linkedNext !=0) {
nextId = token.linkedNext;
} elseif (id >3333&& id <3333+ counters.batched) {
nextId = id +1;
} else {
continue;
}
if (tokens[nextId].owner !=address(0)) continue;
if (i +1< ids.length&& ids[i +1] == nextId) {
skip =true;
token.bit = tokens[nextId].bit;
token.linkedNext = tokens[nextId].linkedNext;
token.linkedPrev = tokens[nextId].linkedPrev;
continue;
}
}
return ret;
}
functionsafeTransferFrom(addressfrom,
address to,
uint256 id,
bytesmemory data
) publicvirtual{
transferFrom(from, to, id);
if (!_checkOnERC721Received(from, to, id, data))
revert TransferToNonERC721ReceiverImplementer();
}
functionsafeTransferFrom(addressfrom,
address to,
uint256 id
) publicvirtual{
safeTransferFrom(from, to, id, "");
}
functiontransferFrom(addressfrom, address to, uint256 id) publicvirtual{
if (to ==from) revert NotAllowed();
if (to ==address(0)) revert NotAllowed();
Token memory token = resolveToken(id);
if (token.stakeTimestamp >0|| token.owner !=from)
revert NotAllowed();
if (msg.sender!= token.owner) {
if (
!operatorApprovals[token.owner][msg.sender] &&
tokenApprovals[id] !=msg.sender
) revert NotAllowed();
}
if (tokenApprovals[id] !=address(0)) {
delete tokenApprovals[id];
emit Approval(from, address(0), id);
}
emit Transfer(token.owner, to, id);
_bakeNextToken(token, id);
token.owner = to;
wallets[from].balance--;
wallets[to].balance++;
tokens[id] = token;
}
function_bakeNextToken(Token memory current, uint256 id) internal{
uint256 nextId;
if (current.linkedNext !=0) {
nextId = current.linkedNext;
} elseif (id >3333) {
nextId = id +1;
if (nextId >3333+ counters.batched) return;
} else {
return;
}
Token memory temp = tokens[nextId];
if (temp.owner !=address(0)) return;
tokens[nextId] = current;
tokens[nextId].linkedNext = temp.linkedNext;
tokens[nextId].linkedPrev = temp.linkedPrev;
tokens[nextId].bit = temp.bit;
}
functionapprove(address to, uint256 id) publicvirtual{
tokenApprovals[id] = to;
emit Approval(msg.sender, to, id);
}
functionsetApprovalForAll(address operator, bool approved) publicvirtual{
operatorApprovals[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
functiongetApproved(uint256 id
) externalviewvirtualreturns (address operator) {
return tokenApprovals[id];
}
functionisApprovedForAll(address owner,
address operator
) externalviewvirtualreturns (bool) {
return operatorApprovals[owner][operator];
}
functionsupportsInterface(bytes4 interfaceId
) publicviewvirtualoverridereturns (bool) {
return
interfaceId ==0x01ffc9a7||// ERC165
interfaceId ==0x80ac58cd||// ERC721
interfaceId ==0x5b5e139f||// ERC721Metadata;
interfaceId ==0x4e2312e0||// ERC1155Receiver
interfaceId ==0x2a55205a; // ERC2981
}
function_checkOnERC721Received(addressfrom,
address to,
uint256 id,
bytesmemory data
) privatereturns (bool) {
try
IERC721Receiver(to).onERC721Received(msg.sender, from, id, 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))
}
}
}
}
functiononERC1155Received(address,
address,
uint256,
uint256,
bytescalldata) externalpurereturns (bytes4) {
returnbytes4(
keccak256(
"onERC1155Received(address,address,uint256,uint256,bytes)"
)
);
}
}
Contract Source Code
File 9 of 14: KillaCubsRestrictor.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.19;import"./KillaCubsStaking.sol";
import"operator-filter-registry/src/DefaultOperatorFilterer.sol";
contractKillaCubsRestrictorisKillaCubsStaking, DefaultOperatorFilterer{
constructor(address bitsAddress,
address gearAddress,
address superOwner
) KillaCubsStaking(bitsAddress, gearAddress, superOwner) {}
boolpublic restricted =true;
functionsetApprovalForAll(address operator,
bool approved
) publicoverride{
if (restricted) {
setApprovalForAllRestricted(operator, approved);
} else {
super.setApprovalForAll(operator, approved);
}
}
functionapprove(address operator, uint256 tokenId) publicoverride{
if (restricted) {
approveRestricted(operator, tokenId);
} else {
super.approve(operator, tokenId);
}
}
functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) publicoverride{
if (restricted) {
transferFromRestricted(from, to, tokenId);
} else {
super.transferFrom(from, to, tokenId);
}
}
functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) publicoverride{
if (restricted) {
safeTransferFromRestricted(from, to, tokenId);
} else {
super.safeTransferFrom(from, to, tokenId);
}
}
functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytesmemory data
) publicoverride{
if (restricted) {
safeTransferFromRestricted(from, to, tokenId);
} else {
super.safeTransferFrom(from, to, tokenId, data);
}
}
functionsetApprovalForAllRestricted(address operator,
bool approved
) publiconlyAllowedOperatorApproval(operator) {
super.setApprovalForAll(operator, approved);
}
functionapproveRestricted(address operator,
uint256 tokenId
) publiconlyAllowedOperatorApproval(operator) {
super.approve(operator, tokenId);
}
functiontransferFromRestricted(addressfrom,
address to,
uint256 tokenId
) publiconlyAllowedOperator(from) {
super.transferFrom(from, to, tokenId);
}
functionsafeTransferFromRestricted(addressfrom,
address to,
uint256 tokenId
) publiconlyAllowedOperator(from) {
super.safeTransferFrom(from, to, tokenId);
}
functionsafeTransferFromRestricted(addressfrom,
address to,
uint256 tokenId,
bytesmemory data
) publiconlyAllowedOperator(from) {
super.safeTransferFrom(from, to, tokenId, data);
}
}
Contract Source Code
File 10 of 14: KillaCubsStaking.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.19;import"./KillaCubsERC721.sol";
import"../SuperOwnable.sol";
interfaceIKILLABITS{
functiondetachUpgrade(uint256 token) external;
functiontokenUpgrade(uint256 token) externalviewreturns (uint64);
functiontransferFrom(addressfrom, address to, uint256 tokenId) external;
}
interfaceIKILLAGEAR{
functiondetokenize(address addr,
uint256[] calldata types,
uint256[] calldata amounts
) external;
}
abstractcontractKillaCubsStakingisKillaCubsERC721, SuperOwnable{
IKILLABITS publicimmutable bitsContract;
IKILLAGEAR publicimmutable gearContract;
eventBitsAdded(uint256[] indexed tokens, uint16[] indexed bits);
eventBitRemoved(uint256indexed token, uint16indexed bit);
eventFastForwarded(uint256[] indexed tokens, uint256indexed numberOfDays);
mapping(uint256=>bool) public bitsUsed;
uint256public activeGeneration =1;
uint256public initialIncubationLength =8;
uint256public remixIncubationLength =4;
mapping(uint256=>uint256) public laterGenerations;
constructor(address bitsAddress,
address gearAddress,
address superOwner
) KillaCubsERC721() SuperOwnable(superOwner) {
bitsContract = IKILLABITS(bitsAddress);
gearContract = IKILLAGEAR(gearAddress);
}
functionstake(uint256[] calldata tokenIds) external{
if (tokenIds.length==0) return;
Token memory token;
bool skip;
for (uint256 i =0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
if (!skip) {
token = resolveToken(tokenId);
if (token.owner !=msg.sender) revert NotAllowed();
if (token.stakeTimestamp >0) revert NotAllowed();
tokens[tokenId] = token;
tokens[tokenId].stakeTimestamp =uint32(block.timestamp);
}
emit Transfer(msg.sender, address(this), tokenId);
skip = _lookAhead(tokenIds, i, token, true);
}
wallets[msg.sender].stakes +=uint16(tokenIds.length);
wallets[msg.sender].balance-=uint16(tokenIds.length);
counters.stakes +=uint16(tokenIds.length);
incubator.add(msg.sender, tokenIds);
}
functionunstake(uint256[] calldata tokenIds, bool finalized) external{
if (tokenIds.length==0) return;
Token memory token;
bool skip;
bool setLaterGeneration;
for (uint256 i =0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
if (tokens[tokenId].bit >0) {
bitsContract.transferFrom(
address(this),
msg.sender,
tokens[tokenId].bit
);
if (finalized) bitsUsed[tokens[tokenId].bit] =true;
emit BitRemoved(tokenId, tokens[tokenId].bit);
tokens[tokenId].bit =0;
}
if (!skip) {
token = resolveToken(tokenId);
setLaterGeneration =false;
if (token.owner !=msg.sender) revert NotAllowed();
if (token.stakeTimestamp ==0) revert NotAllowed();
uint256 phase = _getIncubationPhase(token);
tokens[tokenId] = token;
tokens[tokenId].stakeTimestamp =0;
uint256 max = token.generation ==0
? initialIncubationLength
: remixIncubationLength;
if (phase >= max) {
if (!finalized) revert NotAllowed();
tokens[tokenId].incubationPhase =0;
if (activeGeneration >255) {
tokens[tokenId].generation =255;
setLaterGeneration =true;
} else {
tokens[tokenId].generation =uint8(activeGeneration);
}
} else {
if (finalized) revert NotAllowed();
tokens[tokenId].incubationPhase =uint8(phase);
}
}
if (setLaterGeneration) {
laterGenerations[tokenId] = activeGeneration;
}
emit Transfer(address(this), msg.sender, tokenId);
skip = _lookAhead(tokenIds, i, token, true);
}
wallets[msg.sender].stakes -=uint16(tokenIds.length);
wallets[msg.sender].balance+=uint16(tokenIds.length);
counters.stakes -=uint16(tokenIds.length);
incubator.remove(msg.sender, tokenIds);
}
functionaddBits(uint256[] calldata tokenIds,
uint16[] calldata bits
) external{
if (tokenIds.length==0) return;
Token memory token;
bool skip;
bool modified;
for (uint256 i =0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
if (tokens[tokenId].bit >0) revert NotAllowed();
if (bitsUsed[bits[i]]) revert NotAllowed();
tokens[tokenId].bit = bits[i];
bitsContract.transferFrom(msg.sender, address(this), bits[i]);
if (!skip) {
modified =false;
token = resolveToken(tokenId);
if (token.generation >0) revert NotAllowed();
if (token.owner !=msg.sender) revert NotAllowed();
if (token.stakeTimestamp ==0) revert NotAllowed();
uint256 phase = _getIncubationPhase(token);
if (phase >= initialIncubationLength) revert NotAllowed();
if (phase >1) {
tokens[tokenId] = token;
tokens[tokenId].stakeTimestamp =0;
tokens[tokenId].incubationPhase =0;
modified =true;
}
}
skip = _lookAhead(tokenIds, i, token, modified);
}
emit BitsAdded(tokenIds, bits);
}
functionremoveBits(uint256[] calldata tokenIds) external{
uint16 n =uint16(tokenIds.length);
for (uint256 i =0; i < n; i++) {
uint256 tokenId = tokenIds[i];
if (rightfulOwnerOf(tokenId) !=msg.sender) revert NotAllowed();
bitsContract.transferFrom(
address(this),
msg.sender,
tokens[tokenId].bit
);
emit BitRemoved(tokenId, tokens[tokenId].bit);
tokens[tokenId].bit =0;
}
}
functionextractGear(uint256[] calldata cubs) external{
if (cubs.length==0) revert NotAllowed();
uint256[] memory weapons =newuint256[](1);
uint256[] memory amounts =newuint256[](1);
amounts[0] =1;
for (uint256 i =0; i < cubs.length; i++) {
uint256 id = cubs[i];
Token memory token = resolveToken(id);
if (token.owner !=msg.sender) revert NotAllowed();
if (token.bit ==0) revert NotAllowed();
uint256 phase = _getIncubationPhase(token);
if (phase !=8) revert NotAllowed();
uint256 weapon = bitsContract.tokenUpgrade(token.bit);
bitsContract.detachUpgrade(token.bit);
weapons[0] = weapon;
gearContract.detokenize(address(this), weapons, amounts);
}
}
functionfastForward(address owner,
uint256[] calldata tokenIds,
uint256 numberOfDays
) externalonlyAuthority{
if (tokenIds.length==0) return;
if (numberOfDays ==0) return;
Token memory token;
bool skip;
bool modified;
for (uint256 i =0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
if (!skip) {
token = resolveToken(tokenId);
if (token.owner != owner) revert NotAllowed();
if (token.stakeTimestamp ==0) revert NotAllowed();
uint256 phase = _getIncubationPhase(token);
uint256 max = token.generation ==0
? initialIncubationLength
: remixIncubationLength;
if (phase >= max) revert NotAllowed();
tokens[tokenId] = token;
tokens[tokenId].stakeTimestamp -=uint32(
numberOfDays *24*3600
);
modified =true;
}
skip = _lookAhead(tokenIds, i, token, modified);
}
emit FastForwarded(tokenIds, numberOfDays);
}
function_lookAhead(uint256[] calldata tokenIds,
uint256 index,
Token memory current,
bool modified
) internalreturns (bool sequential) {
uint256 id = tokenIds[index];
uint256 nextId;
if (current.linkedNext !=0) {
nextId = current.linkedNext;
} elseif (id >3333&& id <3333+ counters.batched) {
nextId = id +1;
} else {
returnfalse;
}
if (tokens[nextId].owner !=address(0)) returnfalse;
if (index +1< tokenIds.length&& tokenIds[index +1] == nextId)
returntrue;
if (modified) {
Token memory temp = tokens[nextId];
tokens[nextId] = current;
tokens[nextId].bit = temp.bit;
tokens[nextId].linkedNext = temp.linkedNext;
tokens[nextId].linkedPrev = temp.linkedPrev;
}
returnfalse;
}
function_getIncubationPhase(
Token memory token
) internalviewreturns (uint256) {
uint256 phase = token.incubationPhase;
if (token.stakeTimestamp !=0) {
phase += (block.timestamp- token.stakeTimestamp) /1weeks;
}
uint256 max = token.generation ==0
? initialIncubationLength
: remixIncubationLength;
if (phase > max) return max;
return phase;
}
functiongetIncubationPhase(uint256 id) publicviewreturns (uint256) {
Token memory token = resolveToken(id);
return _getIncubationPhase(token);
}
functiongetGeneration(uint256 id) publicviewreturns (uint256) {
if (laterGenerations[id] !=0) return laterGenerations[id];
Token memory token = resolveToken(id);
return token.generation;
}
}
Contract Source Code
File 11 of 14: Math.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)pragmasolidity ^0.8.0;/**
* @dev Standard math utilities missing in the Solidity language.
*/libraryMath{
enumRounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/functionmax(uint256 a, uint256 b) internalpurereturns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/functionmin(uint256 a, uint256 b) internalpurereturns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/functionaverage(uint256 a, uint256 b) internalpurereturns (uint256) {
// (a + b) / 2 can overflow.return (a & b) + (a ^ b) /2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/functionceilDiv(uint256 a, uint256 b) internalpurereturns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.return a ==0 ? 0 : (a -1) / b +1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/functionmulDiv(uint256 x,
uint256 y,
uint256 denominator
) internalpurereturns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256// variables such that product = prod1 * 2^256 + prod0.uint256 prod0; // Least significant 256 bits of the productuint256 prod1; // Most significant 256 bits of the productassembly {
let mm :=mulmod(x, y, not(0))
prod0 :=mul(x, y)
prod1 :=sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.if (prod1 ==0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.require(denominator > prod1);
///////////////////////////////////////////////// 512 by 256 division.///////////////////////////////////////////////// Make division exact by subtracting the remainder from [prod1 prod0].uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder :=mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 :=sub(prod1, gt(remainder, prod0))
prod0 :=sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.// See https://cs.stackexchange.com/q/138556/92363.// Does not overflow because the denominator cannot be zero at this stage in the function.uint256 twos = denominator & (~denominator +1);
assembly {
// Divide denominator by twos.
denominator :=div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 :=div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos :=add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for// four bits. That is, denominator * inv = 1 mod 2^4.uint256 inverse = (3* denominator) ^2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works// in modular arithmetic, doubling the correct bits in each step.
inverse *=2- denominator * inverse; // inverse mod 2^8
inverse *=2- denominator * inverse; // inverse mod 2^16
inverse *=2- denominator * inverse; // inverse mod 2^32
inverse *=2- denominator * inverse; // inverse mod 2^64
inverse *=2- denominator * inverse; // inverse mod 2^128
inverse *=2- denominator * inverse; // inverse mod 2^256// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/functionmulDiv(uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internalpurereturns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up &&mulmod(x, y, denominator) >0) {
result +=1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/functionsqrt(uint256 a) internalpurereturns (uint256) {
if (a ==0) {
return0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.//// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.//// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`//// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.uint256 result =1<< (log2(a) >>1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision// into the expected uint128 result.unchecked {
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/functionsqrt(uint256 a, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/functionlog2(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=128;
}
if (value >>64>0) {
value >>=64;
result +=64;
}
if (value >>32>0) {
value >>=32;
result +=32;
}
if (value >>16>0) {
value >>=16;
result +=16;
}
if (value >>8>0) {
value >>=8;
result +=8;
}
if (value >>4>0) {
value >>=4;
result +=4;
}
if (value >>2>0) {
value >>=2;
result +=2;
}
if (value >>1>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog2(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result =log2(value);
return result + (rounding == Rounding.Up &&1<< result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/functionlog10(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >=10**64) {
value /=10**64;
result +=64;
}
if (value >=10**32) {
value /=10**32;
result +=32;
}
if (value >=10**16) {
value /=10**16;
result +=16;
}
if (value >=10**8) {
value /=10**8;
result +=8;
}
if (value >=10**4) {
value /=10**4;
result +=4;
}
if (value >=10**2) {
value /=10**2;
result +=2;
}
if (value >=10**1) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog10(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up &&10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/functionlog256(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=16;
}
if (value >>64>0) {
value >>=64;
result +=8;
}
if (value >>32>0) {
value >>=32;
result +=4;
}
if (value >>16>0) {
value >>=16;
result +=2;
}
if (value >>8>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog256(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up &&1<< (result *8) < value ? 1 : 0);
}
}
}
Contract Source Code
File 12 of 14: OperatorFilterer.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.13;import {IOperatorFilterRegistry} from"./IOperatorFilterRegistry.sol";
/**
* @title OperatorFilterer
* @notice Abstract contract whose constructor automatically registers and optionally subscribes to or copies another
* registrant's entries in the OperatorFilterRegistry.
* @dev This smart contract is meant to be inherited by token contracts so they can use the following:
* - `onlyAllowedOperator` modifier for `transferFrom` and `safeTransferFrom` methods.
* - `onlyAllowedOperatorApproval` modifier for `approve` and `setApprovalForAll` methods.
*/abstractcontractOperatorFilterer{
errorOperatorNotAllowed(address operator);
IOperatorFilterRegistry publicconstant OPERATOR_FILTER_REGISTRY =
IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E);
constructor(address subscriptionOrRegistrantToCopy, bool subscribe) {
// If an inheriting token contract is deployed to a network without the registry deployed, the modifier// will not revert, but the contract will need to be registered with the registry once it is deployed in// order for the modifier to filter addresses.if (address(OPERATOR_FILTER_REGISTRY).code.length>0) {
if (subscribe) {
OPERATOR_FILTER_REGISTRY.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy);
} else {
if (subscriptionOrRegistrantToCopy !=address(0)) {
OPERATOR_FILTER_REGISTRY.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy);
} else {
OPERATOR_FILTER_REGISTRY.register(address(this));
}
}
}
}
modifieronlyAllowedOperator(addressfrom) virtual{
// Allow spending tokens from addresses with balance// Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred// from an EOA.if (from!=msg.sender) {
_checkFilterOperator(msg.sender);
}
_;
}
modifieronlyAllowedOperatorApproval(address operator) virtual{
_checkFilterOperator(operator);
_;
}
function_checkFilterOperator(address operator) internalviewvirtual{
// Check registry code length to facilitate testing in environments without a deployed registry.if (address(OPERATOR_FILTER_REGISTRY).code.length>0) {
if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), operator)) {
revert OperatorNotAllowed(operator);
}
}
}
}
Contract Source Code
File 13 of 14: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)pragmasolidity ^0.8.0;import"./math/Math.sol";
/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant _SYMBOLS ="0123456789abcdef";
uint8privateconstant _ADDRESS_LENGTH =20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
uint256 length = Math.log10(value) +1;
stringmemory buffer =newstring(length);
uint256 ptr;
/// @solidity memory-safe-assemblyassembly {
ptr :=add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assemblyassembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /=10;
if (value ==0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
return toHexString(value, Math.log256(value) +1);
}
}
/**
* @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] = _SYMBOLS[value &0xf];
value >>=4;
}
require(value ==0, "Strings: hex length insufficient");
returnstring(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/functiontoHexString(address addr) internalpurereturns (stringmemory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}