Deploy a Token

Step-by-step guide to deploying a token + bonding curve pair through the Factory contract using ethers.js.

Prerequisites

  • A wallet with ETH/BNB for the deployment fee (0.0006 ETH on Base, 0.0012 BNB on BSC)
  • An Ethereum provider (MetaMask, ethers.js JsonRpcProvider, etc.)
  • Access to a recent block's hash for vanity salt mining

Step 1: Mine a Vanity Salt

The salt must commit to a recent blockhash and produce a token address starting with 0x24. Here's the process:

const { ethers } = require("ethers");

// Get the current block number as anchor
const anchorBlock = await provider.getBlockNumber();
const block = await provider.getBlock(anchorBlock);
const blockHash = block.hash;

// Extract first 8 bytes of blockhash
const hashPrefix = blockHash.slice(0, 18); // "0x" + 16 hex chars = 8 bytes

// Pack anchor block (8 bytes, big-endian)
const anchorBytes = ethers.utils.hexZeroPad(
    ethers.utils.hexlify(anchorBlock), 8
);

// Mine nonce until CREATE2 address starts with 0x24
const factoryAddr = "0x8A96...";  // Factory address
const tokenMaster = "0xf07a..."; // Token master address
const initCodeHash = ethers.utils.keccak256(
    /* minimal proxy initcode for token_master */
);

let nonce = 0;
while (true) {
    const nonceHex = ethers.utils.hexZeroPad(
        ethers.utils.hexlify(nonce), 16
    );
    const salt = anchorBytes + hashPrefix.slice(2) + nonceHex.slice(2);
    
    const addr = ethers.utils.getCreate2Address(
        factoryAddr, salt, initCodeHash
    );
    
    if (addr.startsWith("0x24")) {
        console.log("Found salt:", salt);
        break;
    }
    nonce++;
}

Step 2: Call deploy_pair

const factory = new ethers.Contract(FACTORY_ADDRESS, FACTORY_ABI, signer);

const tx = await factory.deploy_pair(
    "My Token",        // name
    "MTK",             // symbol
    salt,              // bytes32 vanity salt
    ethers.constants.HashZero,  // packed_socials (optional)
    { value: ethers.utils.parseEther("0.0006") }
);

const receipt = await tx.wait();

// Parse the PairDeployed event
const event = receipt.events.find(e => e.event === "PairDeployed");
const tokenAddress = event.args.token;
const curveAddress = event.args.curve;

console.log("Token:", tokenAddress);  // Will start with 0x24
console.log("Curve:", curveAddress);
Timing is Critical

Your transaction must be included within the INCLUSION_WINDOW (10 blocks / 20s on Base, 44 blocks / ~132s on BSC) after the anchor block. Mine the salt and submit the transaction quickly.