In my upcoming project we'll be using VRF to generate a random id to mint! I'll keep you posted
On the three ideas:
- I like this idea but there is something so tangible about it being in the JSON that I would opt out for this
- This entails (through no fault of your own - it comes from my own faulty example) that we know a priori all
device_ids
, which unfortunately for my use case, we don't.
- I found this approach to be very interesting. It does entail holding all metadata on chain (besides, theoretically, the image/media itself, which could still be held on Arweave and just the id held on chain). I wonder about the price of this.
Let's say we had metadata of something like:
metadata = [
{ value: nftA, frequency: 2, arweaveLink: 0xA },
{ value: nftB, frequency: 3, arweaveLink: 0xB },
{ value: nftC, frequency: 5, arweaveLink: 0xC },
]
I'm thinking we then could do something (off chain) like:
distribution = []
for (int i = 0; i < metadata.length; i++) {
metadata[i].id = i;
for (int j = 0; j < metadata[i].frequency; j++) {
distribution.push({ id: i, customValue : 0});
}
}
We then can have a contract like:
contract My721 is ERC721 {
/* STRUCTS */
struct TokenStruct {
uint256 id;
uint256 customValue;
}
struct FamilyNFT {
uint256 id;
uint256 frequency;
bytes32 value;
bytes32 arweaveLink;
}
/* STATE VARIABLES */
TokenStruct[] public tokens;
mapping(uint256 => bool) public minted;
// NOTE: I suppose this could be a mapping,
// but I didn't want to loop through the `_differentNfts` on-chain.
// The correct data structure I suppose depends on the size, i.e. number
// of "uniqueNfts" we have?
FamilyNFT[] public differentNfts;
// these probably are memory/calldata or something :)
constructor(TokenStruct[] _tokens, FamilyNFT[] _differentNfts) ERC721("NFT", "My721") {
tokens = _tokens;
differentNfts = _differentNfts;
}
// Of course we wouldn't use an unbounded loop or this naive of an implementation,
// but just to get the point across...
function mint(uint256 _customValue) public {
// this represents something that theoretically is only known at mint time
// but we want in the metadata
require(_customValue != 0, "mint:: customValue must be non zero!");
while (false) {
uint256 randomNumber = getRandomNumber() % tokens.length;
// indicates not yet minted
if (minted[randomNumber].customValue != 0) {
minted[randomNumber].customValue = _customValue;
_mint(randomNumber, msg.sender);
break;
}
}
}
function tokenURI(uint256 tokenId) public returns (string) {
// First get this token
TokenStruct token = tokens[tokenId];
// Then get the family it belongs to
FamilyNFT nftData = differentNfts[token.id];
return
string(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(
bytes(
abi.encodePacked(
'{"value":"',
nftData.value,
'", "tokenId":"',
tokenId,
'", "customValue":"',
customValue,
'", "imageLink": "',
nftData.arweaveLink,
'"}'
)
)
)
)
);
}
}
Thoughts?