Skip to content

Instantly share code, notes, and snippets.

@Daltonic
Created July 18, 2023 10:47
Show Gist options
  • Save Daltonic/91b4af6cd202eb84bcfc06d77035d81d to your computer and use it in GitHub Desktop.
Save Daltonic/91b4af6cd202eb84bcfc06d77035d81d to your computer and use it in GitHub Desktop.
Dapp Breeds
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Base64
/// @author Brecht Devos - <brecht@loopring.org>
/// @notice Provides a function for encoding some bytes in base64
library Base64 {
string internal constant TABLE =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function encode(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return "";
// load the table into memory
string memory table = TABLE;
// multiply by 4/3 rounded up
uint256 encodedLen = 4 * ((data.length + 2) / 3);
// add some extra buffer at the end required for the writing
string memory result = new string(encodedLen + 32);
assembly {
// set the actual output length
mstore(result, encodedLen)
// prepare the lookup table
let tablePtr := add(table, 1)
// input ptr
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
// result ptr, jump over length
let resultPtr := add(result, 32)
// run over the input, 3 bytes at a time
for {
} lt(dataPtr, endPtr) {
} {
dataPtr := add(dataPtr, 3)
// read 3 bytes
let input := mload(dataPtr)
// write 4 characters
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(shr(18, input), 0x3F))))
)
resultPtr := add(resultPtr, 1)
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(shr(12, input), 0x3F))))
)
resultPtr := add(resultPtr, 1)
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(shr(6, input), 0x3F))))
)
resultPtr := add(resultPtr, 1)
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(input, 0x3F))))
)
resultPtr := add(resultPtr, 1)
}
// padding with '='
switch mod(mload(data), 3)
case 1 {
mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
}
case 2 {
mstore(sub(resultPtr, 1), shl(248, 0x3d))
}
}
return result;
}
}
//SPDX-License-Identifier:MIT
pragma solidity >=0.7.0 <0.9.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "./Base64.sol";
contract DappBreed is ERC721, ERC721URIStorage, Ownable, ReentrancyGuard {
using Strings for uint256;
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
struct TraitStruct {
string name;
string description;
string weapon;
string image;
string environment;
uint256 rarity;
bool breeded;
uint256[] parents;
}
struct MintStruct {
uint256 id;
address owner;
uint256 mintCost;
uint256 timestamp;
TraitStruct traits;
}
string public baseURI;
uint256 public maxSupply;
string public baseExtension = ".json";
string public imageExtension = ".webp";
uint256 public mintCost = 0.005 ether;
uint256 public totalBalance;
mapping(uint256 => MintStruct) minted;
mapping(uint256 => bool) tokenIdExist;
string[] weapons = [
"Stick",
"Knife",
"Blade",
"Club",
"Ax",
"Sword",
"Spear",
"Halberd"
];
string[] environments = [
"Space",
"Sky",
"Deserts",
"Forests",
"Grasslands",
"Mountains",
"Oceans",
"Rainforests"
];
uint256[] rarities = new uint256[](5);
constructor(
string memory _name,
string memory _symbol,
string memory _BaseURI,
uint256 _maxSupply
) ERC721(_name, _symbol) {
baseURI = _BaseURI;
maxSupply = _maxSupply;
}
function _baseURI() internal view virtual override returns (string memory) {
return baseURI;
}
function mintNft() public payable nonReentrant {
require(
_tokenIdCounter.current() <= maxSupply,
"Out of tokens, check back later"
);
require(
msg.value > 0 ether && msg.value >= mintCost,
"Insufficient fund for minting"
);
_tokenIdCounter.increment();
uint256 _tokenId = _tokenIdCounter.current();
require(_performMinting(_tokenId), "minting unsuccessful");
TraitStruct memory nft;
nft.name = string(
abi.encodePacked(symbol(), " #", _tokenId.toString())
);
nft
.description = "This is a minted AI generated artworks available for your use.";
nft.weapon = weapons[randomNum(weapons.length, currentTime(), 0)];
nft.environment = environments[
randomNum(environments.length, currentTime(), 0)
];
nft.rarity = randomNum(rarities.length, currentTime(), 0);
nft.image = string(
abi.encodePacked(baseURI, _tokenId.toString(), imageExtension)
);
minted[_tokenId].traits = nft;
payTo(owner(), msg.value);
}
function breedNft(
uint256 _fatherTokenId,
uint256 _motherTokenId
) public payable nonReentrant {
require(tokenIdExist[_fatherTokenId], "Father does not exist");
require(tokenIdExist[_motherTokenId], "Mother does not exist");
require(
_tokenIdCounter.current() <= maxSupply,
"Out of tokens, check back later"
);
require(
msg.value > 0 ether && msg.value >= mintCost,
"Insufficient fund for minting"
);
_tokenIdCounter.increment();
uint256 _tokenId = _tokenIdCounter.current();
require(_performMinting(_tokenId), "minting unsuccessful");
TraitStruct memory nft;
nft.name = string(
abi.encodePacked(symbol(), " #", _tokenId.toString())
);
nft
.description = "This is an inherited AI generated artworks available for your use.";
nft.weapon = minted[_fatherTokenId].traits.weapon;
nft.environment = minted[_motherTokenId].traits.environment;
nft.rarity = randomNum(rarities.length, block.timestamp, 0);
nft.breeded = true;
nft.parents = new uint256[](2);
nft.parents[0] = _fatherTokenId;
nft.parents[1] = _motherTokenId;
nft.image = string(
abi.encodePacked(baseURI, _tokenId.toString(), imageExtension)
);
minted[_tokenId].traits = nft;
payTo(owner(), msg.value);
}
function getAllNfts() public view returns (MintStruct[] memory Minted) {
Minted = new MintStruct[](_tokenIdCounter.current());
for (uint256 i = 0; i < _tokenIdCounter.current(); i++) {
Minted[i] = minted[i + 1];
}
}
function getMintedNfts() public view returns (MintStruct[] memory Minted) {
uint256 available;
for (uint256 i = 0; i < _tokenIdCounter.current(); i++) {
if (!minted[i + 1].traits.breeded) available++;
}
Minted = new MintStruct[](available);
uint256 index;
for (uint256 i = 0; i < _tokenIdCounter.current(); i++) {
if (!minted[i + 1].traits.breeded) Minted[index++] = minted[i + 1];
}
}
function getBreededNfts() public view returns (MintStruct[] memory Minted) {
uint256 available;
for (uint256 i = 0; i < _tokenIdCounter.current(); i++) {
if (minted[i + 1].traits.breeded) available++;
}
Minted = new MintStruct[](available);
uint256 index;
for (uint256 i = 0; i < _tokenIdCounter.current(); i++) {
if (minted[i + 1].traits.breeded) Minted[index++] = minted[i + 1];
}
}
function getMyNfts() public view returns (MintStruct[] memory Minted) {
uint256 available;
for (uint256 i = 0; i < _tokenIdCounter.current(); i++) {
if (minted[i + 1].owner == msg.sender) available++;
}
Minted = new MintStruct[](available);
uint256 index;
for (uint256 i = 0; i < _tokenIdCounter.current(); i++) {
if (minted[i + 1].owner == msg.sender)
Minted[index++] = minted[i + 1];
}
}
function getParentsOf(
uint256 _tokenId
) public view returns (MintStruct[] memory Minted) {
if (!minted[_tokenId].traits.breeded) {
Minted = new MintStruct[](0);
return Minted;
}
Minted = new MintStruct[](minted[_tokenId].traits.parents.length);
uint256 index;
for (uint256 i = 0; i < _tokenIdCounter.current(); i++) {
if (
minted[i + 1].id == minted[_tokenId].traits.parents[0] ||
minted[i + 1].id == minted[_tokenId].traits.parents[1]
) {
Minted[index++] = minted[i + 1];
}
}
}
function getNft(uint256 _tokenId) public view returns (MintStruct memory) {
return minted[_tokenId];
}
function setBaseURI(string memory _newBaseURI) public onlyOwner {
baseURI = _newBaseURI;
}
function _performMinting(uint256 _tokenId) internal returns (bool) {
_safeMint(msg.sender, _tokenId);
_setTokenURI(_tokenId, tokenURI(_tokenId));
MintStruct memory mint;
mint.id = _tokenId;
mint.owner = msg.sender;
mint.mintCost = msg.value;
mint.timestamp = currentTime();
minted[_tokenId] = mint;
tokenIdExist[_tokenId] = true;
return true;
}
function _burn(
uint256 _tokenId
) internal override(ERC721, ERC721URIStorage) {
super._burn(_tokenId);
}
function tokenURI(
uint256 _tokenId
) public view override(ERC721, ERC721URIStorage) returns (string memory) {
require(
_exists(_tokenId),
"ERC721Metadata: URI query for nonexistent token"
);
return buildMetadata(_tokenId);
}
function buildMetadata(
uint256 _tokenId
) internal view returns (string memory) {
TraitStruct memory traits = minted[_tokenId].traits;
uint256 timestamp = currentTime();
bytes memory attributesJson = buildAttributesJson(
traits.environment,
traits.weapon,
traits.rarity,
timestamp
);
return
string(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(
bytes(
abi.encodePacked(
'{"id":"',
_tokenId.toString(),
'","name":"',
traits.name,
'","description":"',
traits.description,
'","price":"',
mintCost.toString(),
'","image":"',
traits.image,
'","attributes":',
attributesJson,
"}"
)
)
)
)
);
}
function buildAttributesJson(
string memory _environment,
string memory _weapon,
uint256 _rarity,
uint256 _timestamp
) internal pure returns (bytes memory) {
return
abi.encodePacked(
'[{"trait_type":"Environment","value":"',
_environment,
'"},',
'{"trait_type":"Weapon","value":"',
_weapon,
'"},',
'{"trait_type":"Rarity","value":"',
_rarity.toString(),
'"},',
'{"display_type":"date","trait_type":"Created","value":"',
_timestamp.toString(),
'"}]'
);
}
function randomNum(
uint256 _mod,
uint256 _seed,
uint256 _salt
) internal view returns (uint256) {
uint256 num = uint256(
keccak256(
abi.encodePacked(block.timestamp, msg.sender, _seed, _salt)
)
) % _mod;
return num;
}
function currentTime() internal view returns (uint256) {
uint256 newNum = (block.timestamp * 1000) + 1000;
return newNum;
}
function payTo(address to, uint256 amount) internal {
(bool success, ) = payable(to).call{value: amount}("");
require(success);
}
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC721, ERC721URIStorage) returns (bool) {
return super.supportsInterface(interfaceId);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment