π΅π» Purrnelope's Grandmas
π΅π» Contract Β· OpenSea Β· LooksRare π΅π»
What are Grandmasβ
Purrnelope's Grandmas are the 2nd companion to the Cats in PCC Universe with 10,000 randomly generated NFTs on the Ethereum Blockchain. Grandmas are Tier 3 NFTs.
Mint / Claimβ
Grandmas are claimed with Grandma's Nightstand, 1 Nightstand for 1 Grandma. Public Grandmas Claim window: May 16 to Jun 13, 2022, and was extended to Jun 23.
Public Claim Link purrnelopescountryclub.com/claim/grandma.
Grandmas #1 - #20
are not revealed. They are reserved for The Team for mysterious plan? Maybe.
All unclaimed Grandmas will be minted by the team.
Clubhouse Accessβ
Grandmas owners can access Clubhouse channel in PCC Discord.
Earn $YARNβ
Grandmas are Tier 3 NFTs, will earn 1 $YARN per day per Grandma.
Redeem for KittyVault Fractionsβ
Once the KittyVault is fractionalized, Grandmas can be redeemed(burned) for KittyBank Token.
Cats & Grandmasβ
If you reunite the Grandma and the Cat with the same ID by having them in the same wallet, the image of the Grandma will change, the Grandma will hold a photo frame of the Cat! And if they got seperated by not in the same wallet, the image of the Grandma will change back to not holding the photo frame.
PCC community member jack.pcc.eth built a tool for finding your grandma match, check it out: https://nftbagcheck.com/find-my-grandma
If the KittyVault owns the Grandma with the matching number of the Cat you own, you can use Grandma Swap Shop to get that Grandma.
Learn Moreβ
Grandma Swap Shopβ
If the KittyVault(kittyvault.pcc.eth) owns the Grandma with the matching number of your Cat, you can send it to the vault and open a ticket in PCC Discord to get the Grandma with the matching number of the Cat you own.
See all Grandmas in the KittyVault on OpenSea
Eventsβ
- 2022-05-13: PCC Team minted Grandmas #1 - #20 @ 07:34:26 PM +UTC
- 2022-05-16: Public Grandmas mint/claim started
- 2022-06-06: Grandma Swap Service vote passed on Snapshot
- 2022-06-23: Unredeemed Grandma's Nightstands were pulled back to purrnelope.pcc.eth Etherscan
The Grandmas Contractβ
Grandmas are ERC-721 NFTs (Etherscan). And the contract itself is named PurrnelopesGrandmas. And here are some unique features in the Grandmas contract:
Mint Relatedβ
devMint
Function privateβ
This is a private function and can not be used by anyone after the contract is deployed. Using this function can mint Grandmas with sequential ID.
This was used during the contract deployment, Grandmas #1 - #20 were minted for the team. (Etherscan)
This function is the same as the Kittens Contract
See Code
function devMint(uint256 _quantity, address _to) private {
uint256 remaining = MaxSupplyCount - CurrentTokenId.current();
for(uint256 i; i < _quantity; i++){
CurrentTokenId.increment();
remaining--;
_safeMint(_to, CurrentTokenId.current());
Ids[i] = Ids[remaining] == 0 ? remaining : Ids[remaining];
}
}
constructor() ERC721("Purrnelopes Grandmas", "PG"){
devMint(20, 0x112E62d5906F9239D9fabAb7D0237A328F128e22);
}
internalMint
Function privateβ
This is a private function for minting Grandmas using other functions in this contract.
This function makes public Grandmas minting have non-sequential token IDs. And it used getRandomNumber
function defined in this contract to arhieve that.
This function is the same as the Kittens Contract
See Code
function internalMint(address _to, uint256 _quantity) private {
require(_quantity <= MaxMintCount && _quantity > 0, "Incorrect mint quantity");
require(_quantity.add(CurrentTokenId.current()) <= MaxSupplyCount, "Cannot exceed max supply");
uint256 remaining = MaxSupplyCount - CurrentTokenId.current();
for(uint256 i; i < _quantity; i++){
remaining--;
uint256 tokenId = CurrentTokenId.current();
uint256 index = getRandomNumber(remaining, i * tokenId);
_safeMint(_to, ((Ids[index] == 0) ? index : Ids[index]) + 1);
Ids[index] = Ids[remaining] == 0 ? remaining : Ids[remaining];
CurrentTokenId.increment();
}
}
//"random" number.... using chainlink for VRF seems overkill
function getRandomNumber(uint256 maxValue, uint256 salt) private view returns(uint256) {
if (maxValue == 0)
return 0;
uint256 seed =
uint256(
keccak256(
abi.encodePacked(
block.difficulty +
((uint256(keccak256(abi.encodePacked(tx.origin, msg.sig)))) / (block.timestamp)) +
block.number +
salt
)
)
);
return seed.mod(maxValue);
}
mint
Functionβ
This function only accepts Grandmas mint by the KittyVault Purrks contract, the Purrks contract uses this function to mint Grandmas to whom redeemed their Grandma's Nightstand Purrks.
This was used for mint Grandmas using the Grandma's Nightstand Purrks.
This function is the same as the Kittens Contract
See Code
function mint(address _to, uint256 _quantity) override public {
require(msg.sender == AllowedAddress || msg.sender == owner(), "Not allowed minting address");
internalMint(_to, _quantity);
}
mintGrandmas
Functionβ
This is for minting Grandmas by paying with Ether(ETH).
To use this, the PublicMintingOpen
toggle needs to be opened. But it is never used since the Grandmas now are redeemed with Grandma's Nightstand. But this function leaves possiblities to make that happen. And a price for minting a Grandmas was set to 0.1 ETH during the contract deployment, which can be changed later.
This function is the same as the Kittens Contract
See Code
function mintGrandmas(uint256 _quantity) payable public nonReentrant {
require(msg.value == _quantity.mul(UnitPrice), "Incorrect ETH amount");
require(PublicMintingOpen, "Public minting is not currently open");
internalMint(msg.sender, _quantity);
}
Token Metadata Relatedβ
tokenURI
Functionβ
This is very unique function in PCC. The tokenURI will change based on the owner of the Grandma. Kittens have 2 sets of tokenURIs, but Grandmas have 3 sets:
- If the Grandma is in the burn(blackhole) address
0x0000Β·Β·Β·Β·dEaD
, this function will returnBurnUri
- If the Grandma is held by an address has the Cat of the same tokenID, this function will return
oBaseURI + tokenID
- If the Grandma id held by an address doesn't has the Cat of the same tokenID, this function will return
BaseURI + tokenID
See Code
function tokenURI(uint256 _tokenId) public view override returns (string memory) {
require(_exists(_tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory baseURI = _baseURI();
string memory uri = bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, _tokenId.toString())) : "";
string memory alternate_uri = bytes(baseURI).length > 0 ? string(abi.encodePacked(oBaseURI, _tokenId.toString())) : "";
return (ownerOf(_tokenId) == BurnAddress) ? BurnUri : isOwnerOfCat(_tokenId) ? alternate_uri : uri;
}
function isOwnerOfCat(uint256 _tokenId) private view returns (bool){
address catOwner;
try CatContractAddress.ownerOf(_tokenId) {
catOwner = CatContractAddress.ownerOf(_tokenId);
}
catch {
catOwner = address(69420);
}
return catOwner == ownerOf(_tokenId);
}
setBaseURI
Functionβ
This is for updating metadata for Grandmas not in the burn(blackhole) address.
This function sets BaseURI
and oBaseURI
, those 2 URIs are used in tokenURI Function.
See Code
function setBaseURI(string calldata _uri, string calldata _uri2) public onlyOwner{
BaseURI = _uri;
oBaseURI = _uri2;
}
updateBurnUri
Functionβ
This is for updating metadata for "*burned(redeemed)" Grandmas.
Grandmas contract does not have a function to actually burn the Grandmas, the Grandmas NFT will always exist on blockchain. But "*burned" Grandmas are transferred to the burn(blackhole) address 0x0000Β·Β·Β·Β·dEaD
. When querying token uri of a Grandma in the burn(blackhole) address, the contract will return to a unique token uri set by this function.
This function is the same as the Kittens Contract
See Code
function updateBurnUri(string memory _uri) public onlyOwner{
BurnUri = _uri;
}
KittyVault Fractions Relatedβ
redeemKittyBankFractions
Functionβ
This is likely to be used for redeem Grandmas for KittyVault Fractions. But it is also possible to create another contract to archive that.
Using this function will transferred the Grandmas to the burn(blackhole) address 0x0000Β·Β·Β·Β·dEaD
, and give back the KittyVault Fractions Token back to the owner that gave up his Grandma. And the Grandmas transferred to the burn(blackhole) address will never get their image back, which explained in updateBurnUri
function.
And this function even supports redeeming multiple Grandmas at once! What a cruel function!
This function is the same as the Kittens Contract
See Code
function redeemKittyBankFractions(uint256[] calldata ids) public {
require(RedeemOpen, "ERC-20 redeem is not currently open");
require(FractionsPerNFT > 0, "Fractions per NFT currently not set");
uint256 amount = FractionsPerNFT.mul(ids.length);
require(FractionsContract.balanceOf(address(this)) >= amount, "Not enough balance of tokens to redeem");
for(uint256 i; i < ids.length; i++){
//we don't need to check the owner of the tokens because this is checked in transferFrom method
this.transferFrom(msg.sender, BurnAddress, ids[i]);
}
FractionsContract.transfer(msg.sender, amount);
}