Skip to content
 
 

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NFT Public Mint Sniper

A command-line tool for sniping public NFT mints on OpenSea's SeaDrop, across Ethereum, Base, Ink and Robinhood Chain mainnets, or Sepolia and Amoy testnets for rehearsing a mint before it counts.

It builds the mint transaction from on-chain data only - price, fee recipient and per-wallet limit all come straight from the SeaDrop contract. That means:

  • No OpenSea account, login, or access token.
  • No API rate limits to lose a mint to.
  • Faster. Every transaction is signed and serialised before the stage opens, so at the exact start time the only work left is writing bytes to the network.

Multi-wallet: paste as many keys as you like, or have the tool generate and save a set for you — hundreds of wallets fire in parallel with the same timing precision as one.


Requirements

  • Node.js 18 or newer — check with node --version. Get it from nodejs.org if you don't have it.
  • A wallet with some ETH on the chain you're minting on.

Step 1 — Install

Run these one line at a time, pressing Enter after each:

git clone https://github.com/morsyxbt/nft-public-mint.git
cd nft-public-mint
npm install
npm run build

Before running npm install, check your prompt ends in nft-public-mint — if the cd didn't take, everything after it fails.

Then confirm the build worked:

npm start -- --help
Install errors

Set-Location : A positional parameter cannot be found (Windows PowerShell) Two commands got pasted onto one line — you'll see something like cd nft-public-mintnpm install. Run each line separately.

Could not read package.json / Missing script: build You're in the wrong folder. Run cd nft-public-mint first.

npm or git is not recognised Install Node.js 18+ and Git, then reopen your terminal.

Step 2 — Configure (optional but recommended)

cp .env.example .env

Open .env and add a private RPC URL for the chain you'll mint on, e.g.:

RPC_URL_BASE=https://base-mainnet.g.alchemy.com/v2/YOUR_KEY

A free Alchemy key takes two minutes and is the single biggest factor in whether you win a contested mint. You can also paste it at the prompt instead — the tool works without any .env at all, falling back to public nodes.

Never put private keys in .env. You paste them into the CLI at run time. They're held in memory for that run only and never written to disk.

Step 3 — Run it

npm start

The wizard asks you eight things:

Step What it wants
1. Wallets Paste existing private keys, generate fresh wallets, or load a saved set. See Wallets at scale below.
2. Network + chain Mainnet or Testnet first, then only that network's chains — Ethereum/Base/Ink/Robinhood on mainnet, Sepolia/Amoy on testnet. Rehearse a mint on testnet before it counts for real.
3. Quantity How many NFTs per wallet.
4. NFT link An OpenSea collection link, an item link, a slug, or the raw 0x contract address. A contract address or item link always works with no API key; a collection slug needs a lookup that usually works unauthenticated.
5. RPC Paste a full URL, or just your Alchemy key and it expands automatically. Blank uses .env, or public nodes.
6. Gas Ceiling and tip. The live base fee is shown right above the prompt.
7. Timing Wait for the stage to open, or fire now if it's already live.

Then it shows a summary and asks Fire?. Nothing is sent until you type y.

Step 4 — Set it and walk away

If the drop opens later, choose "Wait for the stage". It pre-signs everything, holds, and fires at the exact start time — no supervision needed. The Fire? confirmation comes before the wait, so there's no second prompt at mint time.

Two things to get right if you're leaving it running:

  • Stop your computer from sleeping. A sleeping machine suspends the process and the countdown freezes.
  • Leave the terminal window open. Closing it kills the run.

Wallets at scale

At the "Wallets" step you get three options:

Option What happens
Paste private keys The original flow — one key per line, hidden as you type, kept in memory only.
Generate new wallets Pick a count (1 to a few thousand). One fresh seed phrase is created and every wallet is derived from it at m/44'/60'/0'/0/i. The phrase is shown once — write it down — then only its AES-256-GCM ciphertext (password-derived key via scrypt) is saved to wallets/<name>.json. The plaintext phrase is never written to disk.
Load saved wallets Pick a saved set, enter its password, and choose how many of the saved wallets to use this run — e.g. generate 300 once, then fire only 50 of them on a given drop. Deriving the same index from the same phrase always reproduces the same address, so this is exact and repeatable.

Generated wallets start empty — fund each address before firing (the tool tells you the shortfall per wallet before you confirm). Run npm start -- --fund to distribute native currency from one funder wallet to many mint wallets at once: pick a saved set (or paste addresses), an amount per wallet, and it sends the batch. The suggested default amount is a gas-only cushion — enough for the transaction fee alone, since not every mint has a price. Add more if the drop you're targeting does.

Funding transfers all come from one sender, so unlike the mint blast they can't all be independent — a node will only hold so many pending transactions per account at once. The funding tool sends in batches (25 at a time by default, FUNDING_BATCH_SIZE in .env) and waits for each batch before moving to the next nonce range, rather than trying to queue all of them at once and having the excess rejected.

Everything downstream treats every wallet identically regardless of count: nonce and balance lookups are throttled and retried per-wallet (a rate-limited or failed lookup for one wallet excludes only that wallet, it doesn't abort the run for the rest), sockets get re-warmed a few seconds before fire time rather than once at the start of a possibly hours-long wait, and receipts are polled in a single shared batch instead of one independent poller per wallet. Two env vars tune this for very large batches — see .env.example: RPC_CONCURRENCY (in-flight RPC reads at once) and RPC_MAX_CONNECTIONS (HTTP connection pool size per RPC host).


Comparing RPC speed

npm start -- --rpc-check times every candidate endpoint for a chain (your .env entries, the public fallbacks in src/chains.ts, plus anything you paste in) and ranks them fastest-first:

  #   median   min      max      status        endpoint
  1   192      188      684      read+send     PUBLICNODE
  2   263      256      898      send-only     mainnet-sequencer.base.org
  3   286      273      1557     read+send     mainnet.base.org

Each endpoint is hit 5 times with eth_chainId; median latency is what's ranked on, since a single fast/slow sample can be noise. "send-only" means the node rejected the read call but is still fine to blast a signed tx at (e.g. a sequencer). Anything that answers with the wrong chain id is flagged, not ranked. Run it before a drop to decide which URL to paste at the RPC prompt — it doesn't change any config itself.


Understanding gas

Three different numbers, and mixing them up is the most common way to lose a mint:

Term What it is Who sets it
Base fee The network's price. Burned. The chain
Priority fee (tip) Paid on top, to the block producer You
Max fee The ceiling you'll tolerate You

You pay base fee + tip. The max fee is only a cap — if the base fee is 0.006 gwei and your tip is 0.05, you pay 0.056 gwei no matter whether your ceiling is 2 or 200.

But the ceiling is not free. Before a node will even accept your transaction, it checks that your wallet holds gasLimit × maxFee + mint price. So a high ceiling with a thin wallet gets rejected outright, even though the real cost is tiny. The tool checks this before firing and tells you the highest ceiling your balance can support.

A SeaDrop mint uses roughly 135,000 gas for quantity 1.


What it protects you from

Each of these is checked before anything is broadcast:

  • Ceiling below the base fee — rejected by every node. Can't be entered.
  • Tip above the ceiling — invalid under EIP-1559. Can't be entered.
  • Wallet can't cover the upfront reservation — refuses to fire and tells you the ceiling you can afford.
  • Firing before the stage opens — SeaDrop reverts with NotActive and burns gas. "Fire now" isn't offered when the stage opens later.
  • Wrong network — every RPC is checked for its chain ID; any on the wrong chain is dropped rather than blasted at.
  • Quantity above the per-wallet cap — warned before you fire.

If a transaction is rejected by every endpoint, it says so plainly instead of waiting for a receipt that will never exist.


Supported chains

Chain Chain ID Network Explorer
Ethereum 1 mainnet etherscan.io
Base 8453 mainnet basescan.org
Ink 57073 mainnet explorer.inkonchain.com
Robinhood Chain 4663 mainnet robinhoodchain.blockscout.com
Sepolia 11155111 testnet sepolia.etherscan.io
Amoy 80002 testnet amoy.polygonscan.com

The wizard's first prompt is Network (Mainnet / Testnet); picking one filters the chain menu to just that network's entries, so a live-operations run can't accidentally land on a chain whose currency is worthless (or the reverse — firing a real mint at a testnet contract). NETWORK in .env sets which one is pre-selected.

To add another chain, append one entry to src/chains.ts — set testnet: true for a test network — no other code changes needed.


Security

  • Pasted private keys are kept in memory and never written to disk or transmitted anywhere except as a locally-signed transaction.
  • Generated wallet sets are the one thing that does touch disk: their seed phrase is encrypted (AES-256-GCM, scrypt-derived key from a password you set) before being saved to wallets/. Nobody without that password and file can recover it — but if you'd rather nothing ever touches disk, use "Paste private keys" instead.
  • .env, wallets/ and *.key are all git-ignored.
  • Use dedicated hot wallets funded with only what you intend to spend.
  • Read src/local-mint.ts and src/keystore.ts if you want to verify exactly what gets signed, sent, and encrypted.

Allowlist / FCFS mints

Not supported here, and it isn't an oversight. An allowlist stage uses SeaDrop's mintSigned(), which needs a signature that OpenSea generates per wallet — that genuinely requires an authenticated OpenSea session. There's no way to build it from on-chain data, which is the whole premise of this tool.

License

MIT

About

CLI sniper for public SeaDrop NFT mints - builds calldata on-chain, no OpenSea token required

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages