SDK migration guide

Migrate from the (legacy) Doppler v3 or v4 SDK to the latest

Migration Guide

This guide helps you migrate from doppler-v3-sdk or doppler-v4-sdk to the unified @whetstone-research/doppler-sdk using the builder pattern.

Overview of Changes

The new SDK consolidates both V3 and V4 functionality into a single package with clearer terminology:

  • V3 → Static Auctions: Fixed price range liquidity bootstrapping

  • V4 → Dynamic Auctions: Gradual Dutch auctions with Uniswap V4 hooks

  • Unified API: Single SDK instance handles both auction types

  • Improved Types: Discriminated unions for type-safe configurations

  • viem Integration: Replaced ethers.js with viem for better performance

Installation

Remove the old packages and install the new unified SDK:

# Remove old packages
npm uninstall @doppler/v3-sdk @doppler/v4-sdk ethers

# Install new packages
npm install @whetstone-research/doppler-sdk viem

Initialization Changes

Before (V3 SDK)

import { ReadWriteFactory } from '@doppler/v3-sdk';
import { ethers } from 'ethers';

const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
const signer = new ethers.Wallet(privateKey, provider);

const factory = new ReadWriteFactory(signer, chainId);

Before (V4 SDK)

import { ReadWriteFactory } from '@doppler/v4-sdk';
import { ethers } from 'ethers';

const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
const signer = new ethers.Wallet(privateKey, provider);

const factory = new ReadWriteFactory(signer, chainId);

After (Unified SDK)

import { DopplerSDK } from '@whetstone-research/doppler-sdk';
import { createPublicClient, createWalletClient, http } from 'viem';
import { base } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

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

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

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

Creating Auctions

Static Auctions (Previously V3)

Before

// Manually encode migration data
const liquidityMigratorData = await factory.encodeV4MigratorData({
  fee: 3000,
  tickSpacing: 60,
  lockDuration: 365 * 24 * 60 * 60,
  beneficiaries: sortedBeneficiaries,
});

const { poolAddress, tokenAddress } = await factory.create({
  name: 'My Token',
  symbol: 'MTK',
  tokenURI: 'https://example.com/token',
  vestingDuration: 0,
  yearlyMintRate: 0,
  totalSupply: parseEther('1000000'),
  numTokensToSell: parseEther('500000'),
  startTick: -92103,
  endTick: -69080,
  fee: 3000,
  numeraire: wethAddress,
  initialRecipients: [],
  initialAmounts: [],
  contracts: {
    governor: governorAddress,
    tokenFactory: addresses.tokenFactory,
    poolInitializer: addresses.v3Initializer,
    liquidityMigrator: addresses.v4Migrator,
    airlock: addresses.airlock,
  },
  integrator: integratorAddress,
  liquidityMigratorData,
});

After (Builder pattern)

import { StaticAuctionBuilder } from '@whetstone-research/doppler-sdk'

const params = new StaticAuctionBuilder()
  .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/token' })
  .saleConfig({
    initialSupply: parseEther('1000000'),
    numTokensToSell: parseEther('500000'),
    numeraire: wethAddress,
  })
  .poolByTicks({ startTick: -92103, endTick: -69080, fee: 3000 })
  .withMigration({
    type: 'uniswapV4',
    fee: 3000,
    tickSpacing: 60,
    streamableFees: { lockDuration: 365 * 24 * 60 * 60, beneficiaries: sortedBeneficiaries },
  })
  .withVesting({ duration: 0n })
  .withIntegrator(integratorAddress)
  .withUserAddress(governorAddress)
  .build()

const result = await sdk.factory.createStaticAuction(params)

Dynamic Auctions (Previously V4)

Before

// Calculate gamma manually
const gamma = calculateGamma(...);

// Mine hook address
const minedAddress = await hookAddressMiner.mine({
  dopplerDeployer: addresses.dopplerDeployer,
  prefix: '0x00',
});

const { hookAddress, tokenAddress } = await factory.create({
  name: 'My Token',
  symbol: 'MTK',
  tokenURI: 'https://example.com/token',
  // ... many parameters
  poolInitializerData: encodePoolInitializerData({
    minimumProceeds,
    maximumProceeds,
    startingTime,
    endingTime,
    startingTick,
    endingTick,
    epochLength,
    gamma,
    isToken0,
    numPDSlugs,
    fee,
    tickSpacing,
  }),
});

After (Builder pattern)

import { DynamicAuctionBuilder } from '@whetstone-research/doppler-sdk'

const params = new DynamicAuctionBuilder()
  .tokenConfig({ name: 'My Token', symbol: 'MTK', tokenURI: 'https://example.com/token' })
  .saleConfig({ initialSupply: parseEther('1000000'), numTokensToSell: parseEther('500000'), numeraire: wethAddress })
  .poolConfig({ fee: 3000, tickSpacing: 60 })
  .auctionByPriceRange({
    priceRange: { startPrice: 0.0001, endPrice: 0.01 },
    minProceeds: parseEther('50'),
    maxProceeds: parseEther('500'),
    durationDays: 7,
    epochLength: 3600,
  })
  .withMigration({
    type: 'uniswapV4',
    fee: 3000,
    tickSpacing: 60,
    streamableFees: { lockDuration: 365 * 24 * 60 * 60, beneficiaries: [...] },
  })
  .withUserAddress(governorAddress)
  .build()

const result = await sdk.factory.createDynamicAuction(params)

Interacting with Auctions

Before (Both SDKs)

// Manual contract calls with ethers
const pool = new ethers.Contract(poolAddress, poolAbi, provider);
const slot0 = await pool.slot0();
const liquidity = await pool.liquidity();

After (Unified SDK)

// Static Auction
const staticAuction = await sdk.getStaticAuction(poolAddress);
const poolInfo = await staticAuction.getPoolInfo();
const hasGraduated = await staticAuction.hasGraduated();

// Dynamic Auction
const dynamicAuction = await sdk.getDynamicAuction(hookAddress);
const hookInfo = await dynamicAuction.getHookInfo();
const currentEpoch = await dynamicAuction.getCurrentEpoch();

Token Interactions

Before

import { Derc20 } from 'doppler-v3-sdk';

const token = new Derc20(tokenAddress, signer);
const balance = await token.balanceOf(address);

After (Unified SDK)

import { Derc20 } from '@whetstone-research/doppler-sdk';

const token = new Derc20(publicClient, walletClient, tokenAddress);
const balance = await token.getBalanceOf(address);
const vestingData = await token.getVestingData(address);

Quoter Changes

Before

import { Quoter } from 'doppler-v3-sdk';

const quoter = new Quoter(signer, chainId);
const quote = await quoter.quoteExactInputSingle({
  tokenIn,
  tokenOut,
  fee,
  amountIn,
  sqrtPriceLimitX96,
});

After

const quoter = sdk.quoter;
const quote = await quoter.quoteV3ExactInputSingle({
  tokenIn,
  tokenOut,
  fee,
  amountIn,
  sqrtPriceLimitX96: 0n,
});

Last updated