Fee Rehypothecation
Create Multicurve pools with RehypeDopplerHook for advanced fee distribution and buyback mechanisms
Rehype Pools use the RehypeDopplerHookInitializer to distribute trading fees across beneficiaries, LPs, and buyback destinations.
Fee distribution model
Fees are split into four categories (must sum to 100%):
Asset Buyback
Buy back the token
Numeraire Buyback
Buy back the quote token
Beneficiary
Stream to configured addresses
LP
Distribute to liquidity providers
Basic example
import { DopplerSDK, getAddresses } from '@whetstone-research/doppler-sdk';
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';
async function main() {
const account = privateKeyToAccount(privateKey);
const addresses = getAddresses(base.id);
const publicClient = createPublicClient({
chain: base,
transport: http(rpcUrl),
});
const walletClient = createWalletClient({
chain: base,
transport: http(rpcUrl),
account,
});
const sdk = new DopplerSDK({
publicClient,
walletClient,
chainId: base.id,
});
// Get protocol owner for beneficiary requirement (min 5%)
const protocolOwner = await sdk.getAirlockBeneficiary();
// Beneficiaries receive the beneficiaryPercentWad portion of fees
const beneficiaries = [
protocolOwner, // 5% to protocol (minimum required)
{ beneficiary: account.address, shares: parseEther('0.95') }, // 95% to creator
];
const BUYBACK_DESTINATION = account.address; // receives bought-back tokens
const params = sdk
.buildMulticurveAuction()
.tokenConfig({
name: 'Rehype Token',
symbol: 'RHT',
tokenURI: 'https://example.com/metadata.json',
})
.saleConfig({
initialSupply: parseEther('1000000000'),
numTokensToSell: parseEther('1000000000'),
numeraire: addresses.weth,
})
.withCurves({
numerairePrice: 3000, // ETH = $3000 USD
curves: [
{ marketCap: { start: 500_000, end: 1_500_000 }, numPositions: 10, shares: parseEther('0.3') },
{ marketCap: { start: 1_000_000, end: 5_000_000 }, numPositions: 15, shares: parseEther('0.4') },
{ marketCap: { start: 4_000_000, end: 50_000_000 }, numPositions: 10, shares: parseEther('0.3') },
],
beneficiaries,
})
.withRehypeDopplerHook({
hookAddress: addresses.rehypeDopplerHookInitializer!,
buybackDestination: BUYBACK_DESTINATION,
customFee: 3000, // 0.3% swap fee
// Distribution must sum to WAD (100%)
assetBuybackPercentWad: parseEther('0.20'), // 20%
numeraireBuybackPercentWad: parseEther('0.20'), // 20%
beneficiaryPercentWad: parseEther('0.30'), // 30%
lpPercentWad: parseEther('0.30'), // 30%
})
.withGovernance({ type: 'noOp' })
.withMigration({ type: 'noOp' })
.withUserAddress(account.address)
.withDopplerHookInitializer(addresses.dopplerHookInitializer!)
.withNoOpMigrator(addresses.noOpMigrator!)
.build();
const result = await sdk.factory.createMulticurve(params);
console.log('Pool:', result.poolId);
console.log('Token:', result.tokenAddress);
}
main();Fee distribution strategies
Heavy buyback (price support)
LP-first (attract liquidity)
Treasury-building
Configuring and updating fee distribution
After configuring the token, sale, and curves, set the Rehype fee beneficiaries and an optional durable fee controller. Beneficiaries receive the config's beneficiary allocations according to their shares. The controller can replace the config after launch, or it can be assigned to addresses such as 0xdead to make the config immutable.
Beneficiary shares must sum to WAD. The controller is fixed at pool creation, so use an operational wallet or multisig that will remain available to sign updates.
buybackDestination is an alternative builder input for the same overloaded onchain buybackDst field, so do not set both. That field receives proceeds when no feeBeneficiaries are configured and/or the directBuyback routing mode is used.
Connect the SDK to the controller wallet to replace the pool's complete fee distribution config:
setFeeDistribution replaces all eight values; it is not a partial update. The four assetFeesTo* values must sum to WAD, and the four numeraireFeesTo* values must separately sum to WAD. The update does not change the fee schedule, routing mode, or beneficiary shares.
Read the active config with:
Atomic dev buys
Use withDevBuy to create the pool and execute an exact-input purchase in the same transaction:
The SDK uses the chain's configured Bundler by default. Use .withBundler(address) only for a compatible custom deployment.
For compatible Rehype pools, initialization grants that Bundler a pool-specific exemption for its first swap in the launch transaction. The dev buy still pays the protocol's share of the Rehype fee.
Native numeraires send exactly exactAmountIn with the bundle. ERC-20 numeraires require sufficient balance and Bundler allowances. createMulticurve submits an approval first when needed.
Omit vesting to send purchased tokens directly to recipient. When supplied, vestingDuration must be at least one day, cliffDuration cannot exceed it, and permissionless claims can trigger delivery but cannot change the recipient.
Collecting fees
Anyone can trigger fee collection; fees are distributed automatically to the initializer, but each address listed as a beneficiary must then claim their own fees from the initializer:
Configuration reference
RehypeDopplerHookConfig
hookAddress
Address
Deployed RehypeDopplerHookInitializer (must be whitelisted)
buybackDestination
Address
Receives buyback tokens
customFee
number
Swap fee in bps (3000 = 0.3%)
feeDistributionInfo
object
Separate four-way WAD splits for asset and numeraire fees
assetBuybackPercentWad
bigint
% for asset buyback (in WAD)
numeraireBuybackPercentWad
bigint
% for numeraire buyback (in WAD)
beneficiaryPercentWad
bigint
% for beneficiaries (in WAD)
lpPercentWad
bigint
% for LPs (in WAD)
graduationCalldata
Hex
Optional calldata on graduation
Rules
Distribution sum: All four percentages must equal
WAD(1e18)Distribution updates: Only the fixed fee distribution controller can replace the eight-value config
Beneficiary shares: Must sum to
WAD; protocol owner needs at least 5%Note: each beneficiary must collect their own fees by calling collectFees
Hook whitelisting:
hookAddressmust be enabled inDopplerHookInitializerMigration: Use
noOp- rehype pools don't migrate liquidityDev buys: Supported by compatible DopplerHookInitializer and Rehype initializer deployments
Pool status: Enters "Locked" (status = 2)
Last updated