Gas-efficient on-chain batched shuffling for NFTs

Overview

Batch NFT reveal

This repository contains a gas-efficient implementation of an on-chain shuffling algorithm used to reveal NFTs in batches. The main benefits of this over other NFT randomization methods are:

  • Makes the loop between buying and seeing your NFT revealed much faster, which improves experience
  • Keeps attention up through the sale, as new NFTs keep being revealed, instead of just having a single peak of attention at start/reveal
  • Reduces the need to have unrevealed NFTs up for sale, thus making it harder for people to get rarity sniped

For a survey of other ways to randomize NFTs, an analysis on them and an explanation of the algorithm used here, please read randomness.md.

Usage

  1. Copy contracts/BatchReveal.sol into your project
  2. Change TOKEN_LIMIT (maximum amount of tokens to be minted in your sale) and REVEAL_BATCH_SIZE (amount of tokens that to be revealed in each reveal)
  3. Import BatchReveal into your contract, call setBatchSeed(randomNumber) to provide randomness for each batch, and modify tokenURI(id) to use getShuffledTokenId(id)

Please make sure that the following constraints are met:

  • REVEAL_BATCH_SIZE can divide TOKEN_LIMIT (TOKEN_LIMIT % REVEAL_BATCH_SIZE = 0)
  • Total amount of batches (calculated as TOKEN_LIMIT / REVEAL_BATCH_SIZE) should be equal or lower than 117, otherwise you might run into the gas limit

Examples

There are two production ready examples in the contracts/examples folder:

Apart from those, here's the most basic example (not suitable for production):

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "../BatchReveal.sol";

contract Example is ERC721, BatchReveal {
    using Strings for uint256;

    string public baseURI;
    string public unrevealedURI;

    constructor(string memory _baseURI, string memory _unrevealedURI)
        ERC721("Mock NFT", "MNFT")
    {
        unrevealedURI = _unrevealedURI;
        baseURI = _baseURI;
    }

    function provideRandomness(uint randomNumber) public {
        setBatchSeed(randomNumber);
    }

    function tokenURI(uint256 id) public view override returns (string memory) {
        if(id >= lastTokenRevealed){
            return unrevealedURI;
        } else {
            return string(abi.encodePacked(baseURI, getShuffledTokenId(id).toString()));
        }
    }
}

License

All code has been licensed under CC0, just like tubby cats themselves.

You might also like...

A personal semantic search engine capable of surfacing relevant bookmarks, journal entries, notes, blogs, contacts, and more, built on an efficient document embedding algorithm and Monocle's personal search index.

A personal semantic search engine capable of surfacing relevant bookmarks, journal entries, notes, blogs, contacts, and more, built on an efficient document embedding algorithm and Monocle's personal search index.

Revery 🦅 Revery is a semantic search engine that operates on my Monocle search index. While Revery lets me search through the same database of tens o

Dec 30, 2022

A set of tools, helping you building efficient apps in a fast way. SvelteKit & GraphQL

A set of tools, helping you building efficient apps in a fast way. >> SvelteKit & GraphQL <<

KitQL KitQL, A set of tools, helping you building efficient apps in a fast way. 🌐 Infos Documentation: https://kitql.vercel.app/ Day by day progress,

Dec 27, 2022

An efficient (and the fastest!) way to search the web privately using Brave Search Engine

Brave Search An efficient (and the fastest) way to search the web privately using Brave Search Engine. Not affiliated with Brave Search. Tested on Chr

Jun 2, 2022

This project entails a To-do-List whereby a user can input the tasks they want to do, check the tasks done and also clear all tasks when all of them are completed. It is efficient for a user who want to manage their time and keep track of their day.

This project entails a To-do-List whereby a user can input the tasks they want to do, check the tasks done and also clear all tasks when all of them are completed. It is efficient for a user who want to manage their time and keep track of their day.

Screenshot Here is a screenshot for the project. To-Do-List Project This is a Microverse project that entails a to-do-list which one is able to add an

Jun 16, 2022

A minimalistic yet efficient way to stringify and revive instances via JSON.

json-instances Social Media Photo by Francisco J. Villena on Unsplash A minimalistic yet efficient way to stringify and revive instances via JSON. If

Jun 23, 2022

An efficient drop-in replacement for JSON.

An efficient drop-in replacement for JSON.

JCOF: JSON-like Compact Object Format A more efficient way to represent JSON-style objects. Status This format isn't nailed down yet. Most changes wil

Nov 26, 2022

🔖 lightweight, efficient Tags input component in Vanilla JS / React / Angular / Vue

🔖 lightweight, efficient Tags input component in Vanilla JS / React / Angular / Vue

Tagify - tags input component Transforms an input field or a textarea into a Tags component, in an easy, customizable way, with great performance and

Jan 2, 2023

EggyJS is a Javascript micro Library for simple, lightweight toast popups focused on being dependency-less, lightweight, quick and efficient.

EggyJS EggyJS is a Javascript micro Library for simple, lightweight toast popups. The goal of this library was to create something that meets the foll

Jan 8, 2023

radiQL, your one-stop-shop for migrating from a legacy REST backend to an efficient and modern GraphQL API

radiQL, your one-stop-shop for migrating from a legacy REST backend to an efficient and modern GraphQL API

Welcome to radiQL, the one-stop solution for setting up GraphQL on a PostgreSQL database. Check out our Medium article here. At A Glance: Give us your

Nov 14, 2022
Comments
  • BlockhashExample - blockhash

    BlockhashExample - blockhash

    blockhash(block.number) is always 0. Last block's blockhash will be valid data https://github.com/ethereum/go-ethereum/blob/b1e72f7ea998ad662166bcf23705ca59cf81e925/core/vm/instructions.go#L449

    opened by RagePit 0
  • Question: should calling reveal but public or onlyOwner?

    Question: should calling reveal but public or onlyOwner?

    I'm using v2 of the chainlink VRF and planning on funding the subscription manager with enough link to reveal the entire collection (a 10k collection being revealed in batches of 200). I'm curious if revealNextBatch should be public or public onlyOwner. My concern is that if the sub manager has enough link, then someone could just reveal the entire collection. Is it considered bad form to prevent anyone from calling reveal?

        function revealNextBatch() public {
            require(
                maxKiftables >= (lastTokenRevealed + REVEAL_BATCH_SIZE),
                "maxKiftables too low"
            );
    
            // requesting randomness
            COORDINATOR.requestRandomWords(
                s_keyHash,
                s_subscriptionId,
                3, // requestConfirmations
                100000, // callbackGasLimit         
                1 // numWords
            );
        }
        ```
    opened by skotturi 0
Owner
Tubby Cats
Tubby Cats
NFTKastle is an NFT marketplace where users can mint their pictures as NFTs, list their NFTs for sale, and buy NFTs from other users.

NFTKastle NFTKastle is an NFT marketplace where users can mint their pictures as NFTs, list their NFTs for sale, and buy NFTs from other users. NFTKas

Paschal 2 Oct 31, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Hardhat plugin to track gas on the transaction level

hardhat-gas-trackooor Hardhat plugin to track gas on the transaction level. Example report Installation npm install hardhat-gas-trackooor --save-dev A

null 16 Jan 3, 2023
Ethereum smart contract gas cost waste pattern detection and patching tool

Ethereum smart contract gas cost waste pattern detection and patching tool

ibelab 4 Mar 23, 2022
An implementation of ERC1155D, a record setter for minting and transfer gas efficiency.

ERC1155D An implementation of ERC1155D, a record setter for minting and transfer gas efficiency. This contract is in alpha stage and has not been audi

null 72 Dec 26, 2022
A prototype snap for injecting gas fee prices into a confirmation window that also serves as the basis for a 5-minute Snaps tutorial

@Montoya/gas-fee-snap A simple Snap example based on @MetaMask/template-snap. Read below for a tutorial! Prerequisites Before you begin, make sure you

Christian Montoya 18 Dec 8, 2022
Eigen ZK-ZKRollup, Low gas-fee, better privacy-enhancement, high composable

ZKZRU: Eigen ZK-ZKRollup Eigen ZK-ZKRollup provides confidential transaction for users with low gas cost. The ZK-Rollup is an extention of RollupNC an

Eigen Labs 25 Dec 22, 2022
🛠️ Easily track & compare gas costs estimated by Foundry on each of your Pull Requests!

?? ??️ Foundry Gas Diff Reporter Easily compare gas reports generated by Foundry automatically on each of your Pull Requests! How it works Everytime s

Romain Milon 133 Dec 28, 2022