Ми розробляємо смарт-контракти голландського аукціону для справедливого розподілу токенів. Класичний токен-сейл з фіксованою ціною створює одну з двох проблем: або ціна занадто низька — всі токени йдуть за перші секунди (газова війна, несправедливий розподіл на користь MEV-ботів), або занадто висока — сейл не заповнюється. Голландський аукціон вирішує обидві проблеми за рахунок динамічного ціноутворення: ціна починається високою і знижується доти, доки попит не зустріне пропозицію. Ціна сейлу — це ринковий кліринговий рівень, а не довільне число з whitepaper. Саме так Paradigm та a16z проводили перші великі токен-дистриб'юції в DeFi-просторі. Gnosis Protocol використовує варіацію цього механізму для batch аукціонів. Наш досвід — 5 років на ринку та понад 30 успішних контрактів. Замовте розробку під ключ — ми супроводжуємо проект від ідеї до деплою та аудиту.
Чому експоненційне зниження ціни ефективніше за лінійне? — розробка системи голландського аукціону
Найпростіша реалізація — лінійна функція:
price(t) = startPrice - (startPrice - endPrice) * (t - startTime) / duration
Проблема лінійної моделі: більшу частину часу ціна знижується повільно через рівномірність. Учасники чекають мінімуму, аукціон не заповнюється в середині, всі намагаються купити в кінці. Експоненційне зниження більш реалістично описує ринкову поведінку:
function getCurrentPrice() public view returns (uint256) {
if (block.timestamp <= startTime) return startPrice;
if (block.timestamp >= endTime) return endPrice;
uint256 elapsed = block.timestamp - startTime;
uint256 duration = endTime - startTime;
// Експоненційне зниження через 18-decimal fixed point
uint256 priceDelta = startPrice - endPrice;
uint256 decayFactor = PRBMath.exp(-int256(decayRate * elapsed / duration));
return endPrice + priceDelta * decayFactor / 1e18;
}
На практиці більшість production Dutch Auction контрактів використовують дискретні кроки зниження (step-down) замість неперервної функції — це простіше для розуміння учасниками і дешевше в газі.
| Характеристика | Лінійне зниження | Експоненційне зниження |
|---|---|---|
| Швидкість падіння на початку | Повільна | Швидка |
| Привабливість для ранніх учасників | Низька | Висока |
| Ризик незаповнення | Високий | Низький |
| Складність реалізації | Проста | Середня |
| Газові витрати | Низькі | Помірні |
Як захиститися від MEV у Dutch Auction?
У стандартному Dutch Auction всі бачать поточну ціну, і як тільки вона стає «справедливою», всі намагаються купити одночасно. MEV-боти front-run реальних покупців, виставляючи вищий gas price. Результат: газова війна, але вже при кліринговій ціні замість стартової. Рішення — commit-reveal: учасники надсилають encrypted commitment (hash від суми та salt) без розкриття наміру. Після завершення фази commitment — reveal фаза. Клірингова ціна розраховується за сукупним попитом. Це складніше в реалізації, але усуває front-running повністю. GnosisDAO використовував подібну схему для своїх аукціонів.
Ключові контрактні параметри
struct AuctionConfig {
uint256 startPrice; // Максимальна ціна (наприклад, 1 ETH за токен)
uint256 endPrice; // Мінімальна ціна (наприклад, 0.1 ETH)
uint256 startTime; // Unix timestamp початку
uint256 endTime; // Unix timestamp кінця
uint256 totalTokens; // Кількість токенів на продаж
uint256 minBidAmount; // Мінімальна покупка
bool allowWhitelist; // Обмежити до whitelist
bytes32 merkleRoot; // Merkle root для whitelist
}
Whitelist через Merkle Proof
Якщо аукціон обмежений для певних адрес:
function bid(uint256 amount, bytes32[] calldata merkleProof) external payable {
if (config.allowWhitelist) {
bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
require(
MerkleProof.verify(merkleProof, config.merkleRoot, leaf),
"Not whitelisted"
);
}
uint256 currentPrice = getCurrentPrice();
uint256 tokenAmount = msg.value * 1e18 / currentPrice;
require(tokenAmount >= config.minBidAmount, "Below minimum");
require(tokensSold + tokenAmount <= config.totalTokens, "Exceeds supply");
tokensSold += tokenAmount;
bids[msg.sender] += tokenAmount;
emit BidPlaced(msg.sender, tokenAmount, currentPrice, msg.value);
}
Повернення переплати: клірингова ціна
У класичному Dutch Auction учасники платять ціну моменту покупки. У Fair Dutch Auction (DutchX, Gnosis) — всі платять одну клірингову ціну, навіть ті, хто купив раніше за вищою. Різниця повертається. Це справедливіше, але складніше в реалізації: потрібно дочекатися кінця аукціону, розрахувати клірингову ціну, і дати кожному учаснику забрати refund через окремий claim.
function claim() external {
require(auctionEnded, "Auction not ended");
uint256 userBid = bids[msg.sender];
require(userBid > 0, "No bid");
uint256 paid = payments[msg.sender];
uint256 cost = userBid * clearingPrice / 1e18;
uint256 refund = paid - cost;
bids[msg.sender] = 0;
payments[msg.sender] = 0;
// Переводимо токени
token.transfer(msg.sender, userBid);
// Повертаємо переплату
if (refund > 0) {
(bool success, ) = msg.sender.call{value: refund}("");
require(success, "Refund failed");
}
}
Типові помилки та вразливості
Помилки розрахунку клірингової ціни. Якщо tokensSold не досяг totalTokens — аукціон закрився по endPrice. Якщо досяг раніше — клірингова ціна це ціна моменту заповнення. Контракт повинен коректно обробляти обидва сценарії, інакше або користувачі не отримають refund, або контракт віддасть більше токенів, ніж повинен.
Округлення на користь контракту. При діленні wei на ціну виникають remainder. Завжди округлюємо кількість токенів вниз, зберігаємо dust як treasury або включаємо в burn-механізм.
Reentrancy в claim(). ETH-refund перед або разом з transfer токенів — класична точка reentrancy. Оновлюємо bids[msg.sender] = 0 до будь-яких зовнішніх викликів.
Відсутність паузи. Якщо виявлено помилку під час аукціону — потрібна екстрена зупинка. Функція pause() з multisig-контролем, яка заморожує нові bids, але не блокує claim для вже зроблених.
Що входить у розробку
- Смарт-контракт Dutch Auction з підтримкою лінійного або експоненційного зниження
- Механізм commit-reveal для захисту від MEV (опціонально)
- Клірингова ціна з поверненням переплати через claim
- Whitelist на основі Merkle Tree
- Повний набір тестів на Forge + статичний аналіз Slither
- Аудит безпеки (внутрішній + зовнішній за бажанням)
- Документація та інструкція по деплою
- Підтримка після деплою (2 тижні)
Терміни розробки: 3-5 робочих днів для базового Dutch Auction, до 2 тижнів для Fair Dutch Auction з commit-reveal. Вартість розраховується індивідуально. Отримайте консультацію — оцінимо ваш проект за 1 день.
Чому обирають нас
- 5 років досвіду в розробці смарт-контрактів на Solidity та Rust
- Понад 30 успішних проектів у DeFi (гарантія якості)
- Використовуємо сучасні інструменти: Foundry, Tenderly, OpenZeppelin
- Надаємо сертифікати аудиту та формальної верифікації за запитом
Зв'яжіться з нами, щоб обговорити ваш проект. Ми підберемо оптимальну архітектуру аукціону під ваші вимоги.







