Fair Price Discovery System for New Tokens
One of the most difficult tasks when launching a token is determining a fair initial price. Classical mechanisms — fixed price at IDO or CEX listing — are systematically unfair: insiders know the price in advance, bots buy the first blocks, retail buyers enter at the high. The result is predictable: sharp pump at the start, dump within hours, community with losses.
Fair price discovery is not just "fair price," but a mechanism where price is formed by aggregated market signals, not by team position or large participants. There are several implementations, and the choice depends on project specifics.
Fair launch mechanisms: comparison of approaches
Dutch Auction (descending auction)
Price starts high and linearly (or exponentially) declines until sufficient demand accumulates. Participants see the current price and decide: buy now or wait for a decline. Equilibrium price is the one at which the entire placement volume is purchased.
Solidity implementation:
contract DutchAuction {
uint256 public immutable startPrice;
uint256 public immutable endPrice;
uint256 public immutable startTime;
uint256 public immutable duration;
uint256 public immutable totalTokens;
uint256 public tokensSold;
function currentPrice() public view returns (uint256) {
if (block.timestamp >= startTime + duration) return endPrice;
uint256 elapsed = block.timestamp - startTime;
uint256 priceDrop = (startPrice - endPrice) * elapsed / duration;
return startPrice - priceDrop;
}
function buy(uint256 tokenAmount) external payable {
uint256 price = currentPrice();
uint256 cost = price * tokenAmount / 1e18;
require(msg.value >= cost, "Insufficient ETH");
require(tokensSold + tokenAmount <= totalTokens, "Sold out");
tokensSold += tokenAmount;
// transfer tokens + refund excess
}
}
Advantages: pricing determined by market, no fixed allocation. Disadvantages: "wait until the last moment" strategy creates a rush in the final auction blocks — everyone waits for minimum price, then buys simultaneously. This is MEV heaven.
Gnosis used Dutch Auction for GNO placement. Results were mixed: mechanics worked, but gas wars in final blocks negated some advantages for retail participants.
Liquidity Bootstrapping Pool (LBP)
Balancer mechanism: pool with variable weights. Starts with token overweight (e.g., 96/4 TOKEN/USDC), gradually transitions to balanced distribution (50/50). Initial high price declines with sales and weight changes.
Key difference from Dutch Auction: price reacts to real demand in real time. No predetermined decline curve — there is an AMM that adjusts to buys and sells.
// LBP parameters in Balancer v2
const poolParams = {
tokens: [projectToken, USDC],
startWeights: [0.96, 0.04], // 96% TOKEN, 4% USDC at start
endWeights: [0.50, 0.50], // 50/50 at end
swapFeePercentage: ethers.utils.parseEther("0.01"), // 1%
duration: 3 * 24 * 60 * 60, // 72 hours
};
Why this is fairer: a large whale cannot buy everything in the first block — high initial token weight raises price exponentially on large purchases. Bots without informational advantage cannot predict where equilibrium will be.
Projects using LBP: Gitcoin, Radicle, numerous DeFi launches via Copper. This is the de facto standard for DeFi token launch on Ethereum.
TWAMM (Time-Weighted Average Market Maker)
Conceptually different approach: large orders are executed in small pieces over a long period (hours, days). No single "listing" moment — price forms gradually through continuous trading.
FraxSwap implemented TWAMM on-chain. For fair launch this means: instead of "listing Friday at 14:00 UTC," there is "placement from Monday to Friday, each block a small volume." Bots lose advantage — no single moment of attack.
Bonding Curve with commit-reveal
Another approach: bonding curve with commit-reveal phase to fight frontrunning. During the commit phase, participants send keccak256(amount + salt) without revealing the amount. After commit-phase ends — reveal: everyone reveals their orders, final price determined by the curve with full demand.
// Commit phase
mapping(address => bytes32) public commitments;
function commit(bytes32 commitment) external payable {
require(block.timestamp < commitDeadline, "Commit phase ended");
commitments[msg.sender] = commitment;
// ETH deposit — maximum possible amount
}
// Reveal phase
function reveal(uint256 amount, bytes32 salt) external {
require(block.timestamp >= revealStart, "Reveal not started");
bytes32 expected = keccak256(abi.encodePacked(amount, salt, msg.sender));
require(commitments[msg.sender] == expected, "Invalid reveal");
// record actual demand for final price calculation
}
Protection against specific attacks
Sybil attacks
One participant creates thousands of addresses to appear "broad-based" and receive disproportionate share. Solutions:
- Proof of Humanity / Worldcoin: uniqueness verification. Difficult to integrate in contract, but possible via Merkle proofs.
- Quadratic funding weighting: allocation proportional to square root of sum, not sum. Sybil loses meaning: 100 addresses at $1 each give $10 "weight," one address at $100 — $10 "weight." Equivalent for honest, unprofitable for Sybil.
- Snapshot + whitelist: use off-chain criteria (on-chain activity, NFT ownership) to form whitelist via Merkle tree.
Whale manipulation
Whale deposits huge volume in the final auction moment, shifting price. Protection:
- Max allocation per address: limit share per address. Doesn't solve Sybil but limits obvious whale impact.
- Gradual price adjustment: LBP mechanically resistant to this — exponential price growth on large buys.
- Time-locked participation: participants must register N days before auction. Reduces last-minute possibility.
MEV on final Dutch Auction blocks
If auction ends at a specific timestamp — final blocks are MEV attraction. Mitigation: random deadline via Chainlink VRF, or continuous Dutch Auction without fixed end.
On-chain vs off-chain price discovery
Fully on-chain discovery: transparent, verifiable, but expensive in gas and slow. Every participant interacts with contract.
Hybrid approach: off-chain orderbook + on-chain settlement. Participants sign orders off-chain (EIP-712), final distribution posted on-chain in a batch transaction. This is Gnosis Auction model.
// Example batch settlement
struct Order {
address bidder;
uint256 sellAmount; // USDC
uint256 buyAmount; // minimum TOKEN
bytes32 signature;
}
function settleAuction(
Order[] calldata orders,
uint256 clearingPrice // USDC per TOKEN, 18 decimals
) external onlyAuctioneer {
for (uint i = 0; i < orders.length; i++) {
uint256 tokensOut = orders[i].sellAmount * 1e18 / clearingPrice;
require(tokensOut >= orders[i].buyAmount, "Below min");
// transfer tokens
}
}
Auctioneer (centralized element) calculates clearing price off-chain and posts result. This is compromise between efficiency and decentralization — auctioneer can be multisig or DAO.
VRGDA (Variable Rate Gradual Dutch Auction)
Mechanism developed by Art Gobblers team. Price adjusts based on deviation of actual sales from planned schedule. If tokens sell faster than plan — price rises, slower — falls.
function getVRGDAPrice(
int256 timeSinceStart, // in seconds, signed
uint256 sold // tokens already sold
) public view returns (uint256) {
return targetPrice.mulWadUp(
decayConstant.mulWadUp(timeSinceStart - getTargetSaleTime(sold + 1)).expWad()
);
}
VRGDA suited for continuous emission (NFT series, governance tokens with ongoing distribution), less applicable for one-time IDO.
Integration with DEX liquidity after launch
Fair price discovery is only the first step. Next critical task: prevent price from immediately crashing after auction completion. Solutions:
Automatic seed liquidity: part of collected funds + part of tokens automatically added to Uniswap v3 pool. Smart contract does this atomically on auction completion.
Concentrated liquidity positioning: instead of full range (like in Uniswap v2), liquidity positioned in ±30% range from clearing price. This provides deep market near fair price.
Vesting LP tokens: team LP position locked for 6–12 months via TimeLock. This signals to market: liquidity won't be rug-pulled.
Stack and development process
| Component | Technology |
|---|---|
| LBP contract | Balancer v2 SDK + custom parameters |
| Dutch Auction | Solidity + Foundry |
| Batch settlement | Gnosis Auction fork or custom |
| Price oracle | Chainlink + Uniswap v3 TWAP |
| Frontend | wagmi + viem + React, real-time price via WebSocket |
| MEV protection | Flashbots Protect RPC |
Phase 1 (1–2 weeks): mechanism selection for specific tokenomics, parameter audit (starting price, duration, min/max allocation), legal analysis (not all mechanisms are regulatory neutral in all jurisdictions).
Phase 2 (3–4 weeks): contract development, Balancer integration or custom auction contract, testing on mainnet fork.
Phase 3 (1–2 weeks): frontend for participation, monitoring, scripts for post-auction liquidity.
Phase 4: external audit of contracts — mandatory, especially for custom mechanisms. LBP on Balancer inherits Balancer audit, custom implementations — no.
Fair price discovery directly impacts community trust in the project. Technically solvable, and choosing the right mechanism for a specific project is more important than perfect implementation of the wrong one.







