Static auctions

Create coins with Doppler's static bonding curve, aka Doppler v3

With proceeds migration to Uniswap v2

/*
 * Example: Create a Static Auction with Uniswap V2 Migration
 *
 * This example demonstrates:
 * - Creating a token with fixed price range on Uniswap V3
 * - Migrating liquidity to Uniswap V2 after graduation
 * - Monitoring auction progress
 */

// UNCOMMENT IF RUNNING LOCALLY
// import { DopplerSDK, StaticAuctionBuilder } from '@whetstone-research/doppler-sdk';

import { DopplerSDK } from '../src';
import {
  createPublicClient,
  createWalletClient,
  http,
  parseEther,
  formatEther,
} from "viem";
import { base } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

// Load environment variables
const privateKey = process.env.PRIVATE_KEY as `0x${string}`;
const rpcUrl = process.env.RPC_URL || "https://mainnet.base.org";

async function main() {
  // 1. Set up clients
  const account = privateKeyToAccount(privateKey);

  const publicClient = createPublicClient({
    chain: base,
    transport: http(rpcUrl),
  });

  const walletClient = createWalletClient({
    chain: base,
    transport: http(rpcUrl),
    account,
  });

  // 2. Initialize SDK
  const sdk = new DopplerSDK({
    publicClient,
    walletClient,
    chainId: base.id,
  });

  // 3. Define auction parameters via builder
  const params = sdk.buildStaticAuction()
    .tokenConfig({
      name: "TEST",
      symbol: "TEST",
      tokenURI: "https://example.com/token-metadata.json",
    })
    .saleConfig({
      initialSupply: parseEther("1000000"), // 1M tokens
      numTokensToSell: parseEther("500000"), // Sell 500k tokens
      numeraire: "0x4200000000000000000000000000000000000006", // WETH on Base
    })
    .poolByTicks({ startTick: 175000, endTick: 225000, fee: 10000 })
    .withMigration({ type: "uniswapV2" })
    .withUserAddress(account.address)
    .withGovernance({ type: 'default' })
    .build();

  console.log("Creating static auction...");
  console.log("Token:", params.token.name, `(${params.token.symbol})`);
  console.log("Selling:", formatEther(params.sale.numTokensToSell), "tokens");
  console.log("Price range: 0.0001 - 0.001 ETH per token");

  try {
    // 4. Create the auction
    const result = await sdk.factory.createStaticAuction(params);

    console.log("\n✅ Auction created successfully!");
    console.log("Pool address:", result.poolAddress);
    console.log("Token address:", result.tokenAddress);
    console.log("Transaction:", result.transactionHash);

    // 5. Get the auction instance
    const auction = await sdk.getStaticAuction(result.poolAddress);

    // 6. Monitor the auction
    console.log("\nMonitoring auction...");

    const poolInfo = await auction.getPoolInfo();
    console.log("Current liquidity:", formatEther(poolInfo.liquidity));
    console.log("Current sqrtPriceX96:", poolInfo.sqrtPriceX96.toString());

    // 7. Check graduation status
    const hasGraduated = await auction.hasGraduated();
    console.log("Has graduated:", hasGraduated);

    if (!hasGraduated) {
      console.log("\nAuction is still active. It will graduate after:");
      console.log("- 7 days have passed since creation");
      console.log("- Minimum proceeds are collected");
      console.log("\nLiquidity will then migrate to Uniswap V2");
    }

    // 8. Get current price
    const currentPrice = await auction.getCurrentPrice();
    console.log("\nCurrent price (in tick form):", currentPrice.toString());

    // 9. Calculate actual price from tick
    // This is simplified - in production use proper tick math
    const actualPrice = Number(currentPrice) / 1e18;
    console.log("Approximate price:", actualPrice, "ETH per token");
  } catch (error) {
    console.error("\n❌ Error creating auction:", error);
    process.exit(1);
  }

  console.log("\n✨ Example completed!");
}

main();

With proceeds migration to Uniswap v4

import { DopplerSDK, getAirlockOwner } from '../src';
import { parseEther, createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';

const privateKey = process.env.PRIVATE_KEY as `0x${string}`;
const rpcUrl = process.env.RPC_URL ?? "https://mainnet.base.org";
const account = privateKeyToAccount(privateKey);

if (!privateKey) throw new Error('PRIVATE_KEY must be set');

// Example: Creating a static auction that migrates to Uniswap V4
async function createStaticAuctionExample() {
  // Create viem clients
  const publicClient = createPublicClient({
    chain: base,
    transport: http(rpcUrl),
  });

  const walletClient = createWalletClient({
    chain: base,
    transport: http(rpcUrl),
    account: account,
  });

  if (!publicClient || !walletClient) {
    throw new Error('Failed to create viem clients');
  }

  // Initialize the SDK
  const sdk = new DopplerSDK({
    publicClient,
    walletClient,
    chainId: 8453, // Base mainnet
  });

  const airlockOwner = await getAirlockOwner(publicClient);

  // Configure the static auction with the builder
  const params = sdk
    .buildStaticAuction()
    .tokenConfig({
      name: 'My Token',
      symbol: 'MTK',
      tokenURI: 'https://example.com/token-metadata.json',
    })
    .saleConfig({
      initialSupply: parseEther('1000000000'), // 1 billion tokens
      numTokensToSell: parseEther('900000000'), // 900 million for sale
      numeraire: '0x4200000000000000000000000000000000000006', // WETH on Base
    })
    .poolByTicks({ startTick: 175000, endTick: 225000, fee: 3000 })
    .withVesting({ duration: BigInt(365 * 24 * 60 * 60), cliffDuration: 0 })
    .withMigration({
      type: 'uniswapV4',
      fee: 3000,
      tickSpacing: 60,
      streamableFees: {
        lockDuration: 365 * 24 * 60 * 60, // 1 year
        beneficiaries: [
          { address: account.address, percentage: 9500 }, // 95%
          { address: airlockOwner, percentage: 500 }, // 5%
        ],
      },
    })
    .withUserAddress(account.address)
    .withGovernance({ type: "default" })
    .build();

  // Create the static auction
  const result = await sdk.factory.createStaticAuction(params);

  console.log('Pool created:', result.poolAddress);
  console.log('Token created:', result.tokenAddress);
  console.log('Transaction:', result.transactionHash);

  // Later, interact with the auction
  const auction = await sdk.getStaticAuction(result.poolAddress);
  const hasGraduated = await auction.hasGraduated();

  if (hasGraduated) {
    console.log('Auction is ready for migration!');
  }
}

const main = async () => {
  await createStaticAuctionExample();
};

main();

Last updated