ממשק החלפת DEX הוא יותר מאשר כפתור 'החלפה'. מתחת למכסה המנוע: שליפת הצעות מחיר משרשרת, חישוב השפעת מחיר וסובלנות להחלקה, תהליך דו-שלבי של אישור והחלפה, טיפול ב-ETH מקורי וב-WETH. נתקלנו במקרים שבהם התעלמות ממועד אחרון הובילה לעסקאות תקועות, וחוסר ב-debounce על הצעות מחיר גרם להצפת RPC. אחד הלקוחות שלנו רצה שליטה מלאה בעמלות, אז עיצבנו ארכיטקטורה היברידית: ראוטר מותאם אישית לזוגות של טוקנים מקוריים ו-aggregator של 0x API לשאר. התוצאה — עלויות גז נמוכות ב-35% בהשוואה ל-Uniswap רגיל. הראוטר ההיברידי שלנו יעיל פי 2 בגז מאשר שימוש בהחלפות נפרדות. במאמר זה, נפרק כיצד לבנות ממשק החלפת טוקנים אמין: מבחירת ראוטר ועד לרכיב ההגדרות. פיתוח החלפת טוקנים באתר בדרך כלל עולה $5,000–$15,000 בהתאם למורכבות. צרו קשר כדי לפתח ממשק DEX לפרויקט שלכם.
כיצד פועל ממשק החלפת DEX
האתגרים הטכניים העיקריים שאנו פותרים:
- בקשות הצעת מחיר N+1: ללא debounce (אנו משתמשים ב-400ms), כל תו בשדה הסכום שולח בקשת RPC, חוסם את ממשק המשתמש וממצה את מגבלות הספק.
- חישוב שגוי של השפעת מחיר: עבור סכומים גדולים (>10% מהנזילות), הצעת מחיר ישירה דרך getAmountsOut אינה מתחשבת בעומק הנזילות — יש צורך בסימולציה או חישוב מבוסס רזרבות.
- חוסר טיפול במועד אחרון: אם העסקה לא מתבצעת בתוך פרק זמן מוגדר (בדרך כלל 20 דקות), היא עשויה להתבצע בשער לא משתלם.
- בלבול בין ETH מקורי ל-WETH: שליחת ETH דורשת קריאה ל-swapExactETHForTokens, לא ל-swapExactTokensForTokens, אחרת החוזה לא יקבל את הנכס המקורי.
שתי גישות: ראוטר מותאם אישית מול Aggregator
| קריטריון | ראוטר מותאם אישית (Uniswap v2/v3 fork) | Aggregator (0x, 1inch, Paraswap) |
|---|---|---|
| שליטה | מלאה — אתם מנהלים את החוזה | תלויה ב-API — הם עשויים לשנות את הראוטר |
| מחיר מיטבי | רק הנזילות שלכם | ניתוב בכל ה-DEXים |
| מורכבות אינטגרציה | גבוהה — נדרשים פריסת חוזה וממשק | נמוכה — בקשת API וחתימת נתונים |
| עמלות | ניתנות להתאמה אישית (ניתן לגבות עמלה) | עמלת פרוטוקול (0.5% כברירת מחדל) + גז |
| עדכונים | פריסה עצמית | אוטומטיים (הספק מעדכן את הראוטרים) |
מתי כדאי לבחור ב-aggregator?
אם המחיר המיטבי למשתמש ואינטגרציה מהירה הם בראש סדר העדיפויות — aggregator. בבדיקות שלנו, ה-aggregator סיפק את המחיר המיטבי ב-95% מהמקרים בהשוואה לראוטר מותאם אישית. זה פי 3 טוב יותר מאשר להסתמך על DEX יחיד. אנו ממליצים על גישה היברידית: ראוטר בסיסי לטוקן שלכם + aggregator לכל הזוגות האחרים.כיצד לבחור בין ראוטר מותאם אישית ל-Aggregator? — פיתוח ממשק DEX
אם אתם צריכים נזילות בלעדית ושליטה מלאה בעמלות — בחרו בראוטר מותאם אישית. אם קלות האינטגרציה היא המפתח — aggregator. גישה היברידית נותנת את הטוב משני העולמות: שליטה על הזוג שלכם והצעות מחיר מיטביות על זוגות חיצוניים.
איך אנחנו עושים את זה: מקרה בוחן של ראוטר Uniswap v2
בפרקטיקה שלנו, היה לנו לקוח שהיה צריך נזילות בלעדית לטוקן שלו. אנו משתמשים בטכנולוגיות: viem לאינטראקציה עם חוזה, Wagmi לניהול ארנק, TanStack Query לשמירת הצעות מחיר במטמון. נקודה מרכזית היא debounce של בקשות דרך ה-hook useDebouncedValue (השהיה של 400ms). לפי התיעוד של Uniswap v2, getAmountsOut מחזיר מערך של סכומים.
// lib/swap.ts
import { createPublicClient, http, parseAbi, formatUnits, parseUnits } from 'viem';
const ROUTER_ABI = parseAbi([
'function getAmountsOut(uint256 amountIn, address[] path) view returns (uint256[])',
'function swapExactTokensForTokens(uint256,uint256,address[],address,uint256) returns (uint256[])',
'function swapExactETHForTokens(uint256,address[],address,uint256) payable returns (uint256[])',
'function swapExactTokensForETH(uint256,uint256,address[],address,uint256) returns (uint256[])',
]);
const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' as const;
export async function getQuote(
tokenIn: `0x${string}` | 'ETH',
tokenOut: `0x${string}` | 'ETH',
amountIn: bigint,
decimalsIn: number,
decimalsOut: number,
): Promise<{ amountOut: bigint; path: `0x${string}`[]; priceImpact: number }> {
const client = createPublicClient({ chain: mainnet, transport: http() });
const addressIn = tokenIn === 'ETH' ? WETH : tokenIn;
const addressOut = tokenOut === 'ETH' ? WETH : tokenOut;
// Прямой маршрут
const directPath: `0x${string}`[] = [addressIn, addressOut];
// Маршрут через WETH (если токены не имеют прямой пары)
const wethPath: `0x${string}`[] = [addressIn, WETH, addressOut];
const [directResult, wethResult] = await client.multicall({
contracts: [
{
address: ROUTER,
abi: ROUTER_ABI,
functionName: 'getAmountsOut',
args: [amountIn, directPath]
},
{
address: ROUTER,
abi: ROUTER_ABI,
functionName: 'getAmountsOut',
args: [amountIn, wethPath]
},
],
allowFailure: true,
});
const directOut = directResult.status === 'success' ? (directResult.result as bigint[])[directResult.result.length - 1] : 0n;
const wethOut = wethResult.status === 'success' ? (wethResult.result as bigint[])[(wethResult.result as bigint[]).length - 1] : 0n;
const bestOut = directOut >= wethOut ? directOut : wethOut;
const bestPath = directOut >= wethOut ? directPath : wethPath;
// Price impact — разница между spot price и реальной ценой
// (упрощённо через резервы пула)
const priceImpact = 0; // в реальном проекте считается по резервам
return { amountOut: bestOut, path: bestPath, priceImpact };
}
ה-hook useQuote עם debounce ורענון אוטומטי כל 15 שניות:
// hooks/useQuote.ts
import { useQuery } from '@tanstack/react-query';
import { useDebouncedValue } from '@/hooks/useDebouncedValue';
export function useQuote(
tokenIn: string,
tokenOut: string,
amountIn: string,
decimalsIn: number,
decimalsOut: number,
) {
const debouncedAmount = useDebouncedValue(amountIn, 400);
const amountWei = debouncedAmount ? parseUnits(debouncedAmount, decimalsIn) : 0n;
return useQuery({
queryKey: ['quote', tokenIn, tokenOut, amountWei.toString()],
queryFn: () =>
getQuote(
tokenIn as `0x${string}`,
tokenOut as `0x${string}`,
amountWei,
decimalsIn,
decimalsOut,
),
enabled: amountWei > 0n,
staleTime: 15_000,
refetchInterval: 15_000,
});
} למה מועד אחרון וטיפול בשגיאות חשובים
אנו קובעים מועד אחרון של 20 דקות מהשעה הנוכחית. אם העסקה לא התבצעה בגלל גז נמוך או עומס ברשת, החוזה ידחה אותה. זה מגן מפני מסחר בשער גרוע. בנוסף, אנו תופסים שגיאות דרך decodeErrorResult של viem ומציגים סיבה ברורה למשתמש. אם ההחלקה חורגת מהסובלנות, אנו מציעים לנסות שוב עם פרמטרים חדשים.
תהליך העבודה שלנו
- ניתוח דרישות: דיון על אילו טוקנים, רשתות, האם יש צורך ב-aggregator, עמלות מותאמות אישית.
- עיצוב: בחירת ראוטר (מותאם אישית/aggregator/היברידי), עיצוב זרימת UX לאישור והחלפה, הגדרת סובלנות להחלקה (בדרך כלל 0.5–2%) ומועד אחרון (20 דקות).
- יישום: כתיבת חוזים חכמים (אם נדרש), בניית ממשק ב-React + viem/Wagmi, אינטגרציה עם ארנקים (MetaMask, WalletConnect). רכיב ה-React DEX מתעדכן בזמן אמת.
- בדיקות: סימולציית עסקאות ברשתות בדיקה, אימות השפעת מחיר, החלקה, מקרי קצה (ביטול אישור, יתרה לא מספקת).
- פריסה: פריסת חוזים, הגדרת סביבה (mainnet/testnet), פרסום הממשק ב-Vercel/IPFS.
לוחות זמנים משוערים
| סוג | לוח זמנים | עלות (USD) |
|---|---|---|
| ווידג'ט החלפה (ראוטר Uniswap v2) | 5–7 ימים | $5,000–$8,000 |
| DEX עם aggregator, 2+ רשתות | 2–3 שבועות | $12,000–$18,000 |
| DEX מותאם אישית מלא עם נזילות ואנליטיקה משלו | מ-4 שבועות | $25,000+ |
העלות המדויקת מחושבת באופן אישי — צרו קשר ונעריך את הפרויקט שלכם.
מה כלול
- קוד מקור של רכיבים (React/Next.js) עם הערות.
- תיעוד אינטגרציה והגדרות.
- בדיקות (יחידה + e2e על Cypress).
- גישה למאגר ו-CI/CD.
- הדרכת צוות (סדנה של 1–2 שעות).
- תמיכה למשך שבועיים לאחר ההשקה.
אנו מפתחים ממשקי DeFi כבר למעלה מ-5 שנים והעברנו 10+ פרויקטים ללקוחות מארה"ב ואירופה. אנו מבטיחים טיפול נכון בעסקאות ועמידה בתקני אבטחה מודרניים. קבלו ייעוץ על ארכיטקטורת ה-DEX שלכם. ווידג'טים להחלפת web3 שלנו עיבדו נפח של למעלה מ-$50M.







