documentation

The contract

PonsLaunchpad.sol is a self-contained ERC-721: it tracks collections, mints tokens, and holds creator earnings until they choose to withdraw them. No external dependencies, no upgradability.

Collections live on-chain too

createCollection(collectionId, maxSupply, priceWei) records the caller as the collection's creator and reverts if that id is already taken or if maxSupply is zero. The collectionId is derived deterministically from the database row's uuid (dashes stripped, right-padded with zero bytes to 32), so the on-chain struct and the off-chain record for the same collection always agree without needing an oracle.

The creator alone can call setPrice and setPaused on their own collection; anyone else gets NotAuthorized.

mint()

solidity, abridged
function mint(bytes32 collectionId) external payable returns (uint256 tokenId) {
  Collection storage c = collections[collectionId];
  if (c.creator == address(0)) revert UnknownCollection();
  if (c.paused) revert CollectionIsPaused();
  if (c.minted >= c.maxSupply) revert SoldOut();
  if (msg.value != c.priceWei) revert WrongPayment();

  c.minted += 1;
  tokenId = nextTokenId++;
  tokenCollection[tokenId] = collectionId;
  tokenNumber[tokenId] = c.minted;
  // ... assign ownership, credit the creator's balance, emit Minted
}

Two different numbers come out of a mint: tokenNumber is per-collection and sequential (1, 2, 3...), and it's what feeds the seed derivation. tokenId is global across the whole contract and is the token's actual ERC-721 identity. Payment must match the collection's price exactly, or the call reverts. mint() makes no external calls, so it cannot be reentered through a receiver callback.

Payments are pulled, not pushed

mint()
msg.value == priceWei
balances[creator] +=
accrues, no ETH sent yet
withdraw()
creator pulls it, any time

mint() never calls out to the creator. A reverting or malicious creator address can't block anyone else's mint.

mint() never sends ETH anywhere. It only credits balances[creator]. The creator calls withdraw() whenever they want, which zeroes their balance before making the external call out (checks, then effects, then the interaction), and reverts the whole withdrawal if that call fails. This is a deliberate design choice from the contract itself: pull over push, so a reverting or otherwise broken creator address can never brick minting for anyone else.

tokenURI and metadata

tokenURI(tokenId) returns baseURI concatenated with the token id as a string. baseURI is set once at deploy time, typically https://<domain>/api/metadata/, and can be repointed later by the contract owner with setBaseURI. That route resolves the global token id back to a collection and token number and redirects to the canonical JSON described on the metadata page.

A minimal ERC-721

The contract implements ownerOf, balanceOf, approve, setApprovalForAll, transferFrom, safeTransferFrom, and supportsInterface by hand, with no external library dependency. safeTransferFrom updates ownership state before calling the recipient's onERC721Received hook, the same checks-effects-interactions order used in withdraw().

Admin and deploying it

The contract owner can call setBaseURI and transferOwnership. There is no global pause and no upgrade path; each collection's creator controls only their own price and pause flag.

deploy with Foundryshell
forge create contracts/PonsLaunchpad.sol:PonsLaunchpad \
  --rpc-url https://rpc.mainnet.chain.robinhood.com \
  --constructor-args "https://<your-domain>/api/metadata/"

Once deployed, setting the contract address in the app's environment switches minting from the off-chain fallback to real on-chain transactions. Off-chain allocations made before that point stay clearly labeled as such in their metadata and are never presented as real transactions.