1 Įvadas –Į tamsų mišką
1 Įvadas –Vėlyvą naktį Dan Robinson, investicinės firmos Paradigm mokslininkas, matė nelaimės skambutį Uniswap Discord kanale.dviejųkitas vartotojas, bet pačiai Uniswap sutarčiai, kur jie atrodė negrįžtamai prarasti.
Tačiau Robinsonas pamatė vilties spindesį.Jis suprato, kad kiekvienas gali sukeltiburn
Sutarties funkcija, viešas įsakymas, kuris priverstų sutartį paleisti įstrigusius žetonus asmeniui, kuris jį paskambino.
Pripažinęs galimybę tapti baltojo skrybėlės herojumi, Robinsonas parengė gelbėjimo operaciją. Bet jis žinojo, kad jis nėra vienintelis. „Ethereum“ mempoolas – viešas laukimo kambarys, kuriame laukia sandoriai – yra sudėtingų robotų, žinomų kaip „apibendrinti frontrunners“, medžioklė.
Norėdamas juos įveikti, Robinsonas sugalvojo protingą dviejų dalių sandorį, tikėdamasis, kad abi dalys bus išgautos vienu metu, nepaliekant lango įsilaužimui. Tai neveikė. Tuo momentu, kai pasirodė jo pirmasis sandoris, botas jį aptiko, pakartojo visą strategiją ir pagrobė 12 000 dolerių, kol Robinsono antroji operacija netgi galėjo būti patvirtinta.
Dabar garsus esė apie incidentą, Robinson davė šį priešišką, nematoma ekosistema vardą.Ethereum is a Dark Forest.
Šiame straipsnyje mes gilinsime į sistemos, galinčios skaityti realaus laiko operacijas ir duomenis iš blockchain sandorių, dizainą, siekiant atlikti arbitražą.mathematical models underlying AMM pricingDalinamės įalgorithms for opportunity detection and optimal price entryApibrėžia taiarchitectural componentsiš mūsų botų, ir aptarticritical strategiesReikalinga sėkmingai ir saugiai vykdyti arbitražą šioje didelės rizikos aplinkoje.
DeFi kraštovaizdis: AMM, likvidumas ir arbitražo galimybės
Mūsų įvade aprašytas „Tamsusis miškas“ yra ne tik priešiška aplinka; tai gyvybinga ekosistema, pastatyta remiantis nauja finansine paradigma: decentralizuotas finansavimas (DeFi). Savo pagrindu DeFi siekia atkurti tradicines finansines paslaugas blockchain tinkluose, pašalinant tarpininkų poreikį naudojant savarankiškai vykdomas protingas sutartis.
Automatiniai rinkos kūrėjai (AMM): decentralizuotos mainų pagrindas
Tradicinės biržos remiasi užsakymų knygomis, kuriose pirkėjai ir pardavėjai pateikia pasiūlymus ir prašymus, o centrinis derinimo variklis palengvina sandorius. „DeFi“ pristato radikaliai kitokį modelį: automatizuotą rinkos kūrėją (AMM). Vietoj tiesioginio pirkėjų ir pardavėjų derinimo, AMM naudojasi likvidumo baseinais – protingomis sutartimis, turinčiomis dviejų ar daugiau žetonų atsargas – kad palengvintų sandorius. Naudotojai, žinomi kaip likvidumo teikėjai (LPs), į šiuos baseinus deponuoja lygiavertę žetonų porų vertę, uždirbdami dalį prekybos mokesčių.
Turto kaina AMM baseine nustatoma algoritmiškai pagalconstant product formulaPagrindinės UNISWAP iniciatyvos:
Čia x ir y atstovauja dviejų žetonų kiekiui likvidumo baseine, o k yra pastovus. Kai vartotojas prekiauja vienu ženklu už kitą, x ir y kiekiai baseine keičiasi, tačiau jų produktas k turi likti pastovus. Šis mechanizmas dinamiškai koreguoja kainą: perkant daugiau žetonų A sumažės jo kiekis baseine, taip padidinant jo kainą, palyginti su ženklu B, ir atvirkščiai.bonding curve, kuris diktuoja prekybos kainų taškus.
Iš šio modelio galima deterministiniu būdu apskaičiuoti išvestinę sumą (dy) iš apsikeitimo, atsižvelgiant į dviejų žetonų (x ir y) įvesties sumą (dx) ir išankstines apsikeitimo atsargas:
Key characteristics of AMMs:
- Visada likvidumas: Skirtingai nuo užsakymų knygų, kurios gali tapti plonos, AMM visada siūlo likvidumą, kol yra žetonų.
- Be leidimo: Kiekvienas gali tapti likvidumo teikėju arba prekiauti AMM be patvirtinimo.
- Kainų atradimas: Kainos nustatomos pagal turto santykį baseine, koreguojant su kiekviena prekyba.
- Slippage: Dideli sandoriai gali žymiai perkelti kainą baseine, dėl to atsiranda reiškinys, vadinamas slydimu, kai vykdoma kaina yra blogesnė už nurodytą kainą.
Nors modelis x⋅y=k (dažnai vadinamas Uniswap V2) sukūrė pagrindą, AMM išsivystė. Pavyzdžiui, Uniswap V3 įvedė „koncentruotą likvidumą“ (CLAMM), leidžiantį LP paskirstyti savo kapitalą konkrečiuose kainų diapazonuose.we will primarily focus on AMMsnaudojant pastovią produktų formulę (pvz., Uniswap V2 stiliaus baseinus), nes jie suteikia pagrindinį supratimą prieš sprendžiant sudėtingesnius modelius.
The Essence of Arbitrage in DeFi
Arbitražas, savo gryniausioje formoje, yra tuo pačiu metu pirkti ir parduoti turtą skirtingose rinkose, siekiant pasipelnyti iš jo kainos skirtumo. DeFi, tai reiškia išnaudoti kainų skirtumus tarp skirtingų AMM baseinai, arba tarp AMM ir Centralizuota birža (CEX), už tą pačią žetonų porą. Esminis neleistinas DeFi pobūdis ir suskaidytas likvidumas per įvairius protokolus sukuria derlingą pagrindą šioms galimybėms. Didelis volatilumas ir reguliavimo trūkumas šioje kylančioje finansinėje erdvėje dažnai sukelia reikšmingus kainų nuokrypius, kurie yra gyvybinis kraujas arbitražų.
Arbitražo galimybės DeFi
- Pavyzdžiui, jei 1 ETH prekiauja 2000 DAI dėl Uniswap A, bet 1 ETH prekiauja 2010 DAI dėl Uniswap B, arbitražas gali įsigyti ETH dėl Uniswap A su DAI ir iš karto parduoti tą ETH už DAI dėl Uniswap B, sumokėdamas 10 DAI skirtumą (išskyrus dujų mokesčius ir slydimą).
- Triangulinis arbitražas (Multi-Leg): Šis arbitražo tipas apima tris ar daugiau turto toje pačioje biržoje (arba keliose biržose), kad sudarytų pelningą ciklą. Pavyzdžiui, arbitražas gali pradėti nuo tokeno A, pakeisti jį tokenu B, tada tokenu B dėl tokeno C, ir galiausiai tokenu C atgal į tokeną A, baigiant daugiau tokeno A nei jie pradėjo. Bendras pavyzdys apie Uniswap gali būti: WETH -> DAI -> USDC -> WETH. Mūsų pagrindinis tikslas yra įgyvendinti ir valdyti Multi-Leg arbitražą tarp skirtingų DEX AMM.
- Flash paskolų arbitražas: Galingas ir unikalus aspektas DeFi, flash paskolos leidžia vartotojams skolintis neapmokėtą turtą, naudoti juos sandorių serijos (pavyzdžiui, arbitražo) ir grąžinti paskolą - visa tai per vieną blockchain sandorį. Jei visa operacijų seka (paskolos, prekybos, grąžinti) negali būti sėkmingai užbaigtas per tą vieną sandorį, visa operacija yra grąžinta, tarsi tai niekada neįvyko. Tai pašalina reikšmingą išankstinio kapitalo poreikį ir žymiai sumažina kliūtį patekti į didelio masto arbitražo, bet tai taip pat reiškia, kad visa arbitražo strategija turi būti kruopščiai organizuota per vieną atominę operaciją. Mes įtrauksime "flash
Lenktynės dėl pelno: iššūkiai ir konkurencija
DeFi kraštovaizdis yra labai efektyvi rinka. Kainų skirtumai yra nepastovūs, dažnai egzistuoja tik milisekundes, kol jie yra išnaudojami sudėtingų robotų.
-
Gas Fees: Every interaction with a smart contract incurs a transaction fee (gas), which can vary significantly based on network congestion. A profitable arbitrage opportunity must yield enough profit to cover these costs.
-
Slippage: The larger the trade relative to the pool’s liquidity, the greater the slippage, eroding potential profits. Accurately modeling slippage is crucial for calculating true profitability.
-
Latency: The speed at which an arbitrage bot can detect an opportunity, calculate the optimal trade, construct a transaction, and submit it to the network is paramount. Even milliseconds can make the difference between profit and loss.
-
Frontrunning and MEV: As discussed in the introduction, the “Dark Forest” is dominated by generalized frontrunners. These bots actively monitor the mempool for pending profitable transactions, replicate them, and submit their own transaction with a higher gas price to ensure their transaction is included in a block before the original one. This phenomenon falls under the umbrella of Maximal Extractable Value (MEV), representing the total value that can be extracted from block production in excess of the standard block reward and gas fees by arbitraging, liquidating, or reordering transactions within a block. Successfully navigating this environment often requires advanced strategies like leveraging MEV-Boost relays or private transaction pools. To mitigate the risk of being intercepted in public mempools, our implementation will primarily operate on Base, an EVM-compatible Layer 2 (L2) blockchain. Base’s architecture, which currently does not expose a public mempool in the same manner as Ethereum’s Layer 1, offers a different environment for transaction submission, potentially reducing traditional frontrunning risks.
-
Complexity of AMMs: As AMMs evolve (e.g., Uniswap V3’s concentrated liquidity), the mathematical modeling and state tracking required for accurate arbitrage calculations become significantly more complex.
Understanding these foundational elements of DeFi, from the mechanics of AMMs to the cut-throat nature of arbitrage competition, sets the stage for designing a robust and effective arbitrage bot. In the next chapter, we will begin to lay out the architectural blueprint for such a system.
Architektūros dizainas: Arbitražo botų infrastruktūros kūrimas
Norint sukurti pelningą arbitražo botą DeFi „Tamsiajame miške“ reikia architektūros, kurioje pirmenybė teikiama greičiui, patikimumui ir tikslumui. Kiekviena milisekundė yra svarbi, o gebėjimas apdoroti realaus laiko duomenis, nustatyti galimybes ir greitai vykdyti sandorius yra svarbiausias.
Go buvo pasirinkta kaip pagrindinė vystymosi kalba dėl savo išskirtinio našumo, tvirtų konkurencinių primitivų (goroutinų ir kanalų) ir stiprios tinklo programavimo ir žemo lygio sistemos sąveikos ekosistemos. Šios savybės yra labai svarbios sprendžiant didelį blockchain duomenų perdavimą ir lygiagrečio apdorojimo poreikį realaus laiko arbitražo sistemoje.go-ethereum
Pagrindinis Ethereum klientas.
Boto architektūra yra struktūrizuota kaipevent-driven systemsudaryta iš kelių nepriklausomų paslaugų (modulių), kurių kiekvienas veikia lygiagrečiais procesais (goroutinais). Šios paslaugos asynchroniškai bendrauja siunčiant pranešimus per „Go“ kanalus, užtikrinant laisvai susietą ir labai reaguojantį dizainą.
Bendra sistemos architektūra
Arbitražo roboto infrastruktūra gali būti vizualizuota kaip vamzdynas, kuriame duomenys teka iš blockchain, yra apdorojami ir analizuojami, o kulminacija yra pelningų sandorių vykdymas.
-
Blockchain Data Reader Service: Responsible for real-time ingestion of blockchain events data.
-
Market Graph Service: Maintains an in-memory representation of the DeFi market and identifies arbitrage paths.
-
Arbitrage Strategy Service: Evaluates detected opportunities for profitability and prepares trade instructions.
-
Transaction Builder Service: Constructs and dispatches blockchain transactions.
-
Honeywall Service: A post-execution checker that enhances security and maintains market integrity by identifying and blacklisting malicious pools.
This modularity allows each service to focus on a specific task, minimizing dependencies and optimizing performance for its particular workload. Communication between services is strictly asynchronous, leveraging Go’s channels for message passing, which naturally facilitates a non-blocking and highly concurrent operation.
Blockchain duomenų skaitytuvo paslauga: mūsų botų akys ir ausys duomenų sraute
Ši paslauga veikia kaip pagrindinė roboto sąsaja su žaliavais, realaus laiko duomenimis, tekančiais per bloką. „Tamsiajame miške“ informacija yra valiuta, o mūsų gebėjimas greitai ir tiksliai ją įsisavinti yra svarbiausias.extract crucial financial data pointsTai skatins mūsų sprendimų priėmimo mechanizmą.
- Prisijungimas ir duomenų įsisavinimas: skaitytuvas prisijungia prie blockchain mazgo per WebSockets. Šis nuolatinis, dvipusis ryšys leidžia nedelsiant priimti naujus blokų antraštes ir, svarbiau, išmaniųjų sutarčių išleistus įvykių žurnalus. Paslauga yra konfigūruota specialiai klausytis Swap, Mint, Burn ir Sync įvykių iš Decentralized Exchange (DEX) išmaniųjų sutarčių. Šie įvykiai yra labai svarbūs, nes jie rodo likvidumo rezervų pokyčius, tiesiogiai paveikdami žetonų kainas.
- Nauji blokų antraštės: prenumeruodami naujus blokų antraštes, mes gauname nedelsiant pranešimą apie būsenos pokyčius. Kiekvienas naujas blokas yra patvirtintas bloko dabartinės realybės akimirkos, įskaitant naujus sandorius, atnaujintus balansus ir naujas likvidumo bazės būsenas. Šis srautas suteikia pagrindinius mūsų rinkos grafiko periodinių atnaujinimų duomenis ir patvirtina mūsų pačių operacijų rezultatus.
func (er *EthereumReader) SubscribePairs() error {
parsedABI := constants.PairAbi
// Set up the filter
query := ethereum.FilterQuery{
Topics: [][]common.Hash{
{
parsedABI.Events["Swap"].ID,
parsedABI.Events["Mint"].ID,
parsedABI.Events["Burn"].ID,
parsedABI.Events["Sync"].ID,
},
},
}
logs := make(chan types.Log)
sub, err := er.ethClient.SubscribeFilterLogs(context.Background(), query, logs)
if err != nil {
return err
}
// Start Routine to read swaps events
log.Println("[READING SWAPS...]")
go func() {
for {
select {
case err = <-sub.Err():
log.Println("[RESET CONNECTION...] Subscription error: ", err)
pairInfo := GraphMessage{
Ok: false,
}
*er.pairChan <- pairInfo
time.Sleep(5 * time.Minute)
er.ethClient = clients.ResetConnection()
er.SubscribePairs()
return
case vLog := <-logs:
start := time.Now()
pairAddress := vLog.Address
if er.filter.IsPairBlackListed(pairAddress.Hex()) {
continue
}
blockNumber := vLog.BlockNumber
if blockNumber > er.currentBlockNumber {
// New block detected, reset cache
er.lastUpdatedBlock = nil
er.lastUpdatedBlock = make(map[common.Address]uint64)
er.currentBlockNumber = blockNumber
}
// Check if already updated for this pair in current block
if _, exists := er.lastUpdatedBlock[pairAddress]; exists {
continue
}
t0, t1, f, r0, r1, err := er.getPairDataFromHelper(pairAddress)
if err != nil {
continue
}
dex := f.String()
router, err := constants.GetRouterAddressFromFactory(dex)
if err != nil {
continue
}
// Update cache
er.lastUpdatedBlock[pairAddress] = blockNumber
elapsed := time.Until(start)
pairInfo := GraphMessage{
Ok: true,
DexCheck: true,
Pair: pairAddress.Hex(),
Token0: Token{Address: t0.Hex()},
Token1: Token{Address: t1.Hex()},
Reserve0: r0,
Reserve1: r1,
Dex: router,
GetTime: elapsed,
}
*er.pairChan <- pairInfo
}
}
}()
return nil
}
- „Custom Smart Contract“ duomenų agregavimui ir išankstiniam filtravimui: siekiant optimizuoti efektyvumą ir sumažinti perteklinius grandinės skambučius, „Reader“ naudoja specialiai šiam tikslui parašytą individualią išmaniąją sutartį. Ši sutartis veikia kaip agregatorius, teikiantis vieną optimizuotą skambutį, kad būtų galima gauti atsargas ir kitą suvestinę informaciją kelioms likvidumo poroms. Pagrindinė šios individualios sutarties funkcija yra jos įmontuota išankstinė patikra dėl įprastų sukčiavimo savybių ar pernelyg didelių prekybos mokesčių baseine prieš grąžinant duomenis.
- Pagrindinė logika yra „checkPair“ metodas, kuris įvertina žetonų poros saugumą ir grąžina suvestinius duomenis.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract ArbHelperMap {
mapping(address => address) public factoryToRouter;
address public owner;
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
constructor() {
owner = msg.sender;
// Pre-populate known mappings
factoryToRouter[0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6] = 0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24;
factoryToRouter[0x02a84c1b3BBD7401a5f7fa98a384EBC70bB5749E] = 0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb;
factoryToRouter[0xFDa619b6d20975be80A10332cD39b9a4b0FAa8BB] = 0x327Df1E6de05895d2ab08513aaDD9313Fe505d86;
factoryToRouter[0x71524B4f93c58fcbF659783284E38825f0622859] = 0x6BDED42c6DA8FBf0d2bA55B2fa120C5e0c8D7891;
factoryToRouter[0x3E84D913803b02A4a7f027165E8cA42C14C0FdE7] = 0x8c1A3cF8f83074169FE5D7aD50B978e1cD6b37c7;
factoryToRouter[0x9A9A171c69cC811dc6B59bB2f9990E34a22Fc971] = 0x1b7655aa64b7BD54077dE56B64a0f92BCba05b85;
}
function addFactoryRouter(address factory, address router) external onlyOwner {
require(factory != address(0) && router != address(0), "Zero address");
factoryToRouter[factory] = router;
}
struct Result {
bool success;
address token0;
address token1;
address factory;
uint112 reserve0;
uint112 reserve1;
}
// Helper function to get pair data
function _getPairData(address pairAddress) private view returns (
bool success,
address token0,
address token1,
address factory,
uint112 reserve0,
uint112 reserve1,
address router
) {
success = false;
try IPair(pairAddress).token0() returns (address _token0) {
token0 = _token0;
try IPair(pairAddress).token1() returns (address _token1) {
token1 = _token1;
try IPair(pairAddress).factory() returns (address _factory) {
factory = _factory;
try IPair(pairAddress).getReserves() returns (uint112 r0, uint112 r1, uint32) {
reserve0 = r0;
reserve1 = r1;
router = factoryToRouter[factory];
if (router != address(0)) {
success = true;
}
} catch {}
} catch {}
} catch {}
} catch {}
}
// Helper function to check if pair passes tax limit
function _checkTaxLimit(
address router,
address token0,
address token1,
uint amountIn,
uint maxTaxPermille
) private view returns (bool) {
address[] memory path = new address[](2);
path[0] = token0;
path[1] = token1;
try IRouter(router).getAmountsOut(amountIn, path) returns (uint[] memory buyOuts) {
if (buyOuts.length < 2) return false;
address[] memory reversePath = new address[](2);
reversePath[0] = token1;
reversePath[1] = token0;
try IRouter(router).getAmountsOut(buyOuts[1], reversePath) returns (uint[] memory sellOuts) {
if (sellOuts.length < 2) return false;
uint minReturn = amountIn - (amountIn * maxTaxPermille / 1000);
return sellOuts[1] >= minReturn;
} catch {
return false;
}
} catch {
return false;
}
}
function checkPair(address pairAddress, uint amountIn, uint maxTaxPermille) external view returns (Result memory r) {
// Initialize result with default values
r.success = false;
// Skip processing if pair address is zero
if (pairAddress == address(0)) return r;
// Get pair data
bool success;
address token0;
address token1;
address factory;
uint112 reserve0;
uint112 reserve1;
address router;
(success, token0, token1, factory, reserve0, reserve1, router) = _getPairData(pairAddress);
// If we couldn't get pair data or there's no router, return early
if (!success) return r;
// Check tax limits
bool passedTaxCheck = _checkTaxLimit(router, token0, token1, amountIn, maxTaxPermille);
// Populate result if tax check passed
if (passedTaxCheck) {
r.success = true;
r.token0 = token0;
r.token1 = token1;
r.factory = factory;
r.reserve0 = reserve0;
r.reserve1 = reserve1;
}
return r;
}
}
- Po šių įvykių priėmimo ir apdorojimo skaitytuvas normalizuoja duomenis ir siunčia atnaujinimus (pvz., naujas rezervines vertes konkrečiam baseinui) kaip pranešimus per Go kanalą rinkos grafiko tarnybai.
Rinkos grafikos paslauga: DeFi rinkos žemėlapis
Market Graph Service yra centrinis žvalgybos vienetas, palaikantis realaus laiko, atminties atvaizdą DeFi rinkoje.directed graphir kur:
- Ryšiai: atstovauja atskiroms kriptovaliutoms (pvz., WETH, USDC, DAI).
- Ribos: atstovauja likvidumo baseinus įvairiuose DEXe (pvz., Uniswap V2 ETH/DAI baseinas, SushiSwap USDC/WETH baseinas).
- Duomenų struktūra ir atnaujinimai: Ši paslauga gauna atnaujinimus iš "Blockchain Data Reader" paslaugos per kanalus. Gavus naujus rezervinius duomenis dėl baseino, ji atnaujina atitinkamą kraštą grafike.
- Visi skaičiavimai, susiję su žetonų sumomis ir valiutos keitimo kursais, naudoja Go matematinį / didelį paketą (BigInt arba BigFloat). Tai yra labai svarbu norint išlaikyti savavališką tikslumą, užkirsti kelią plūduriuojančio taško netikslumams, dėl kurių gali būti praleistos galimybės arba neteisingi pelno skaičiavimai.
- Arbitražo kelio aptikimas: Bellman-Ford algoritmas: Šio paslaugos širdyje yra FindArbitrage funkcija, kuri naudoja grafo perėjimo algoritmą, ypač Bellman-Ford. Šis algoritmas unikaliai sugeba rasti neigiamus ciklus grafe, kuris yra būtent tai, kas atitinka arbitražo galimybę mūsų rinkos modelyje (kur logaritminiai valiutos kursai naudojami kaip krašto svoriai). Skirtingai nuo daugelio kitų grafo teorijos algoritmų, kurie orientuojasi į efektyviausio kelio nustatymą, Bellman-Ford sugebėjimas aptikti neigiamus ciklus daro jį išskirtinai efektyviu tiek DeFi, tiek kiekybinių finansų programoms, kuriose siekiama pelno iš cikliškų neatitikimų.
Arbitražo strategijos paslauga: pelno nustatymas ir optimizavimas
Atsisiųskite atnaujintus įvykius išMarket Graph ServiceArbitražo strategijos tarnyba nuolat stebi naujai aptiktų arbitražo kelių rinkos grafiką.
- Galimybių vertinimas: Kiekvieną kartą, kai grafikas atnaujinamas arba "FindArbitrage" nustato galimą arbitražo kelią, ši paslauga pradeda veikti.
- Optimalus įvesties kiekio apskaičiavimas (konveksinis optimizavimas): svarbiausias žingsnis yra nustatyti optimalią įvesties sumą (dx) arbitražo sekai. Tai yra ne triviali problema, nes pelningumas yra ne linijinė įvesties sumos funkcija, kaip parodyta dokumente „Uniswap rinkų analizė“. Tai veikia slydimas ir mokesčiai per kelis apsikeitimus. Paslauga tai išsprendžia kaip konveksinę optimizavimo problemą, naudojant „Go“ gonum/optimize paketą.
- Prekybos apsikeitimo modeliavimas: prieš sudarant sandorį paslauga atlieka visų apsikeitimo sandorių imituojamą vykdymą nustatytame arbitražo kelyje, naudodama pastovią produkto formulę ir apskaičiuotą optimalią įvesties sumą.Šio modeliavimo metu kiekvienam tarpiniam apsikeitimo žingsniui taip pat nustatomos mažiausios išvesties sumos.Tai užtikrina, kad netikėtai mažų faktinių išvesties atvejais (pvz., dėl staigių kainų svyravimų ar didelio slydimo grandinėje) sandoris grįš su minimaliais dujų nuostoliais, o ne vykdydamas nepelningą ar prarandančią prekybą.
- Visi mokesčiai: Įskaitant DEX prekybos mokesčius (pvz., 0,3% už Uniswap V2).
- Slippage: tiksliai modeliuojant kiekvienos prekybos kainų poveikį seka.
- Dujų sąnaudos: apskaičiuojami dujų mokesčiai, reikalingi visam sandoriui, atsižvelgiant į grandinę (pagrindą) ir dabartines tinklo sąlygas.
- Tik tuo atveju, jei apskaičiuotas grynasis pelnas yra bent 0,5% pradinės įvesties sumos (arba konfigūruojamos ribos), galimybė laikoma perspektyvia.
- Pranešimas apie vykdymą: jei pelninga galimybė atitinka kriterijus, arbitražo strategijos paslauga surenka visus būtinus duomenis – užsakytą apsikeitimo seka (užpakaliai), optimalią įvesties sumą ir kitus atitinkamus parametrus – ir siunčia pranešimą per Go kanalą Transaction Builder paslaugai.
Prekės aprašymas: Swift Execution
"Transaction Builder" paslauga yra botų vykdymo ranka, kurios užduotis yra greitai sukurti ir pateikti arbitražo sandorį į blockchain.
- Sandorio kūrimas: gavus galimybę iš Arbitražo strategijos tarnybos, ši paslauga nedelsdama pradeda kurti atominės blokų grandinės sandorį.
- Išmanioji sutarčių sąveika (atominiai apsikeitimai): ši paslauga sąveikauja su specialiai sukurta išmaniąja sutartimi, skirta vykdyti visas arbitražo operacijas (daugelį apsikeitimų) vienoje atominėje operacijoje.Ši sutartis taip pat tvarko tokenų patvirtinimus toje pačioje sandorio sraute.Ši logika yra labai svarbi siekiant užkirsti kelią priekiniam ar atgaliniam nusileidimui arbitražo sekos viduryje, nes visa operacija sėkmingai ar nesėkmingai veikia kaip vienas vienetas.
- Čia yra „Solidity“ funkcija, kuri tvarko arbitražo vykdymą be „flash“ paskolos, reikalaudama, kad savininkas (botas) finansuotų pradinę sumąIn:
struct SwapStep {
address router;
address[] path;
uint minOut;
}
function executeArb(
address inputToken,
uint amountIn,
SwapStep[] calldata steps,
uint minFinalOut
) external onlyOwner returns (uint finalAmountOut) {
require(steps.length > 0, "No steps");
// Transfer tokens from msg.sender to contract
require(IERC20(inputToken).transferFrom(msg.sender, address(this), amountIn), "Transfer in failed");
address currentToken = inputToken;
uint currentAmount = amountIn;
for (uint i = 0; i < steps.length; i++) {
SwapStep calldata step = steps[i];
require(step.path[0] == currentToken, "Path mismatch");
address outputToken = step.path[step.path.length - 1];
// Save balance before swap
uint balanceBefore = IERC20(outputToken).balanceOf(address(this));
// Safe approve
require(IERC20(currentToken).approve(step.router, 0), "Reset approve failed");
require(IERC20(currentToken).approve(step.router, currentAmount), "Approve failed");
IUniswapV2Router(step.router).swapExactTokensForTokens(
currentAmount,
step.minOut,
step.path,
address(this),
block.timestamp
);
uint balanceAfter = IERC20(outputToken).balanceOf(address(this));
uint received = balanceAfter - balanceBefore;
require(received >= step.minOut, "Slippage too high");
currentToken = outputToken;
currentAmount = received;
}
require(currentAmount >= minFinalOut, "Final output too low");
require(IERC20(currentToken).transfer(owner, currentAmount), "Final transfer failed");
return currentAmount;
}
- "Flash Loan" integracija: Jei optimali arbitražo suma reikalauja "flash" paskolos, kūrėjas integruoja "flash" paskolos logiką (pasiskolinti → vykdyti apsikeitimus → grąžinti) į vieną, nedalomą sandorį, naudojant individualią sutartį, kuri palengvina šią atominę operaciją per "Aave" "FlashLoanSimple" sąsają.
- Čia yra „Solidity“ sutarties funkcija „ExecuteOperation“ (dalis didesnės „FlashLoanReceiver“ sutarties), kurią kviečia „Aave Pool“ ir kurioje yra arbitražo logika, naudojant pasiskolintas lėšas:
function startArbitrage(
address token,
uint256 amount,
SwapStep[] calldata steps,
uint256 minFinalOut
) external onlyOwner {
bytes memory params = abi.encode(steps, minFinalOut);
POOL.flashLoanSimple(address(this), token, amount, params, 0);
}
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external override returns (bool) {
require(msg.sender == address(POOL), "Untrusted lender");
require(initiator == address(this), "Unauthorized initiator");
(SwapStep[] memory steps, uint256 minFinalOut) = abi.decode(params, (SwapStep[], uint256));
// Execute the arbitrage
address currentToken = asset;
uint currentAmount = amount;
for (uint i = 0; i < steps.length; i++) {
SwapStep memory step = steps[i];
require(step.path[0] == currentToken, "Path mismatch");
address outputToken = step.path[step.path.length - 1];
// Save balance before swap
uint balanceBefore = IERC20(outputToken).balanceOf(address(this));
// Safe approve
require(IERC20(currentToken).approve(step.router, 0), "Reset approve failed");
require(IERC20(currentToken).approve(step.router, currentAmount), "Approve failed");
IUniswapV2Router(step.router).swapExactTokensForTokens(
currentAmount,
step.minOut,
step.path,
address(this),
block.timestamp
);
uint balanceAfter = IERC20(outputToken).balanceOf(address(this));
uint received = balanceAfter - balanceBefore;
require(received >= step.minOut, "Slippage too high");
currentToken = outputToken;
currentAmount = received;
}
require(currentAmount >= amount + premium, "Insufficient profit");
require(currentAmount >= minFinalOut, "Final output too low");
// Repay the loan
require(IERC20(asset).approve(address(POOL), amount + premium), "Approval failed");
// Transfer profits to owner
uint profit = IERC20(asset).balanceOf(address(this)) - (amount + premium);
if (profit > 0) {
require(IERC20(asset).transfer(owner, profit), "Profit transfer failed");
}
return true;
}
- Dinamiškai įvertina sandoriui reikalingą dujų kiekį ir nustato tinkamą dujų kainą (arba prioritetinį mokestį už L2, pvz., Bazę), kad būtų užtikrintas tinkamas įtraukimas į bloką.
- Transakcijų siuntimas: Kai pasirašyta, pasirašyta operacija siunčiama į bazinės blokų grandinės mazgą. Bazės pasirinkimas yra strateginis: skirtingai nuo Ethereum L1, dabartinėje bazės architektūroje nėra viešai matomo mempolo tradicinėje prasme. Tai reiškia, kad sandoriai yra mažiau linkę tiesiogiai apibendrinti, kai robotai nuskaito mempolį. Nors Maksimali išgaunama vertė (MEV) vis dar egzistuoja L2s, jos ištraukimo mechanizmai skiriasi nuo L1, o tiesioginis mempolo sniping yra žymiai sumažintas, suteikiant labiau nuspėjamą vykdymo aplinką arbitražams.
- Asynchronous Feedback: After sending the transaction, the service sends a notification to the Honeywall Service to signal that a transaction has been initiated and requires monitoring.
„Honeywall“ paslauga: vykdymo patvirtinimas ir saugumas
Honeywall paslauga veikia kaip kritinis vykdymo patikrinimas ir tvirtas saugumo sluoksnis arbitražo botui. jos vaidmuo yra patvirtinti įvykdytų operacijų rezultatus ir apsaugoti nuo kenkėjiškų veikėjų.
- Sandorio rezultatų stebėjimas: Po to, kai sandorio kūrėjas išsiunčia sandorį, „Honeywall“ paslauga stebi jo įtraukimą į bloką ir jo rezultatą.
- Pelno įrašymas: jei sandoris yra sėkmingas ir atneša pelną (kaip tikimasi iš modeliavimo), pelno duomenys yra registruojami veiklos stebėjimui ir analizei.
- Nesėkmės analizė: sandorio nesėkmės atveju „Honeywall“ analizuoja grąžinimo priežastį.
- Honeypot / sukčiavimo aptikimas ir juodasis sąrašas: Pagrindinė saugumo funkcija yra jos gebėjimas identifikuoti „honeypot“ žetonus ar baseinus, kurie įgyvendina apgaulingą logiką (pvz., Leidžia pirkti, bet neleidžia parduoti, arba nustato pernelyg didelius paslėptus mokesčius pardavimams).
- Išorinių paslaugų teikėjų integracija: ji integruojasi su išoriniu paslaugų teikėju arba žinomų „Honeypot“ sutarčių duomenų baze, kad nukreiptų nesėkmingų sandorių poras ir taip nustatytų galimus sukčiavimo atvejus.
- Dinaminis juodasis sąrašas: Jei tam tikra pora ar baseinas yra identifikuojamas kaip medaus puodelis arba problemiškas dėl netikėtai didelių mokesčių, jis nedelsiant pridedamas prie juodojo sąrašo, palaikomo duomenų bazės.
- "Bloom Filter" integracija: Šis juodasis sąrašas efektyviai tvarkomas per "Bloom" filtro mechanizmą.Tai leidžia "Blockchain Data Reader" paslaugai greitai patikrinti naujai pastebėtas poras prieš juodąjį sąrašą, netgi atgaunant jų atsargas arba pridedant juos prie rinkos grafiko.Tai veikia kaip aktyvi gynyba, užkertant kelią botui švaistyti išteklius ar bandyti prekiauti žinomomis probleminėmis poromis ateityje.
Architektūrinio dizaino išvada
Modulinė, į įvykius orientuota architektūra, įgyvendinta „Go“, kartu su specializuotomis duomenų įsisavinimo, rinkos modeliavimo, galimybių optimizavimo, greito vykdymo ir patikimo saugumo paslaugomis, sudaro mūsų didelio našumo arbitražo roboto stuburą.
Galimybių aptikimas ir optimalus vykdymas: botų smegenys
Tikrasis arbitražo roboto intelektas slypi jo gebėjime greitai ir tiksliai nustatyti pelningas galimybes nuolat besikeičiančioje rinkoje, o tada optimizuoti vykdymą, kad būtų galima gauti didžiausią grąžą.Šis skyrius nagrinėja pagrindinius algoritmus ir matematinius modelius, kurie palaiko mūsų roboto sprendimų priėmimo procesą, nuo rinkos kartografavimo kaip grafikas iki tiksliai apskaičiuojant optimalius prekybos dydžius ir imituojant rezultatus.
DeFi rinkos modeliavimas kaip grafikas
As introduced in the architectural overview, our Market Graph Service represents the DeFi landscape as a directed graph. In this model, individual tokens (e.g., WETH, DAI, USDC) serve as nodes, o likvidumo grupės įvairiose decentralizuotose biržose (DEX) veikia kaipedges connecting these tokens. Each edge’s weight represents the cost of transacting through that pool.
Norėdami efektyviai aptikti arbitražo galimybes, kurios pasireiškia kaip pelningas ciklas, mes transformuojame pelningos prekybos sekos paieškos problemą įnegative cycleŠi transformacija pasiekiama taikant logaritminę funkciją valiutų kursams.
Logaritmų poreikis ciklo aptikimui
Pagrindinė arbitražo idėja yra pradinės sumos padauginimas iš valiutos keitimo kursų serijos, kad galų gale būtų daugiau pradinio turto.TokenX
Prekiaukite jais dėlTokenY
TadaTokenY
užTokenZ
Ir pagaliauTokenZ
Atgal įTokenX
Mūsų galutinė suma būtų:
Working with products in graph algorithms is cumbersome. A common technique in computational finance to transform multiplicative problems into additive ones is to apply a logarithm. By taking the natural logarithm of each exchange rate, the product becomes a sum:
Dabar, siekiant pelningo ciklo, mums reikialn (Galutinis ) > ln (A)Kas reiškialn(RateX→Y) + ln(RateY→Z) + ln(RateZ→X) > 0Tačiau tipiški trumpiausio kelio algoritmai (pavyzdžiui, „Bellman-Ford“, kuriuos mes naudojame) yra skirti ieškoti kelių su minimaliusumąNorėdami, kad pelningas ciklas mūsų grafike pasirodytų kaip „neigiamas ciklas“, mes tiesiog paneigiame logaritmines normas:
ln(RateX→Y) + ln(RateY→Z) + ln(RateZ→X) > 0Su šia transformacija, neigiamų svorių suma, dėl kurios atsiranda neigiama vertė (ty neigiamas ciklas), tiesiogiai rodo pelningą arbitražo galimybę.
Tikslios operacijos suBigInt
Tokenų kiekis DeFi gali labai skirtis, nuo mažų frakcijų (pvz., ERC-20 žetonų su 18 dešimtainiais taškais) iki labai didelių skaičių (pvz., stablecoins). Šis ekstremalus heterogeniškumas, apimantis iki 18 reikšmingų skaičių, daro standartinę plūduriuojančio taško aritmetiką labai jautrią tikslumo klaidoms.
Norėdami tai įveikti, mūsų rinkos grafiko paslauga ir iš tikrųjų visi skaičiavimai, susiję su tokenų sumomis ir valiutos kursais, naudojasi "Go"math/big
Pakuotė – konkrečiaiBigInt
Aritmetiniai skaičiai irBigFloat
naudojant plūduriuojančio taško operacijas, jei reikia.BigFloat
siūlo savavališką tikslumą, taikantlog
dviejųBigInt
arbaBigFloat
vertės reikalauja kruopštaus tvarkymo, kaip standartasmath.Log
Funkcijos veikia natūraliaifloat64
Čia būtini individualizuoti įgyvendinimai arba išorinės bibliotekos, galinčios naudoti savavališko tikslumo logaritmus.
func getLogRate(reserve0, reserve1 *big.Int) *big.Float {
const prec = 1024
resIn := new(big.Float).SetPrec(prec).SetInt(reserve0)
resOut := new(big.Float).SetPrec(prec).SetInt(reserve1)
// Effective Rate
rate := new(big.Float).SetPrec(prec).Quo(resOut, resIn)
logRate := bigfloat.Log(rate)
return logRate.Neg(logRate)
}
Arbitražo kelio aptikimas: Bellman-Ford algoritmas
Kai DeFi rinka yra tiksliai modeliuojama kaip grafikas su logaritminiais neigiamais krašto svoriais, arbitražo galimybių nustatymas sumažėja iki nustatymo.negative cyclesŠioje knygoje. „Dėl to mes naudojameBellman-Ford algorithm.
Pavadintas po Richard Bellman ir Lester Ford Jr., Bellman-Ford yra universalus trumpiausio kelio algoritmas, galintis tvarkyti grafikus su neigiamais krašto svoriais. Skirtingai nuo Dijkstros algoritmo, kuris nepavyksta esant neigiamiems ciklams, Bellman-Ford yra specialiai sukurtas juos aptikti. Jo istorinė reikšmė pranoksta teorinį kompiuterių mokslą; jis rado programas įvairiose srityse, įskaitant tinklo maršrutą (kur jis padeda rasti pigiausius kelius su skirtingomis sąnaudomis) ir, kritiškai, kiekybiniame finansavime, siekiant nustatyti pelningas prekybos galimybes valiutų rinkose.
Algoritmas veikia iteratyviai atpalaiduojant kraštus, palaipsniui ieškant trumpesnių kelių į visus mazgus iš šaltinio. Jei po ÁthaV Átha−1 iteracijų (kur ÁthaV Átha yra viršūnių skaičius), papildoma N-oji iteracija randa kelią, kuris vis dar gali būti „atsipalaidavęs“ (t. y. galima rasti trumpesnį kelią), tai rodo neigiamo ciklo buvimą. Ši savybė daro jį puikiu mūsų naudojimo atveju: neigiamas ciklas reiškia prekybos seką, kuri lemia grynąjį pelną, būtent tai, ko siekia arbitražo botas.
type Edge struct {
Pair string
From Token
To Token
LogRate *big.Float
Reserve0 *big.Int
Reserve1 *big.Int
Dex string
MinOut *big.Int
}
type Graph struct {
nodes map[string]Token
Edges map[string][]*Edge
pairChan *chan GraphMessage
dexCheckChan *chan DexDexMessage
subscriptions []*chan time.Duration
mu sync.RWMutex
}
// Bellman-Ford algorithm to find arbitrage cycles
func (g *Graph) FindArbitrage(source Token) ([]*Edge, bool) {
sourceKey := source.Address
g.mu.RLock()
defer g.mu.RUnlock()
distance := make(map[string]*big.Float)
predecessor := make(map[string]*Edge)
// 1. Init
for token := range g.nodes {
distance[token] = new(big.Float).SetInf(false)
}
distance[sourceKey] = new(big.Float).SetFloat64(0)
// 2. Relax edges V-1 times
for i := 0; i < len(g.nodes)-1; i++ {
for _, edgeList := range g.Edges {
for _, e := range edgeList {
from := e.From.Address
to := e.To.Address
if !distance[from].IsInf() && new(big.Float).Add(distance[from], e.LogRate).Cmp(distance[to]) < 0 {
distance[to].Add(distance[from], e.LogRate)
predecessor[to] = e
}
}
}
}
// 3. Negative cycle detection
var cycleStartToken string
for _, edgeList := range g.Edges {
for _, e := range edgeList {
from := e.From.Address
to := e.To.Address
if !distance[from].IsInf() && new(big.Float).Add(distance[from], e.LogRate).Cmp(distance[to]) < 0 {
cycleStartToken = to
break
}
}
if cycleStartToken != "" {
break
}
}
if cycleStartToken == "" {
return nil, false // No Arbitrage
}
// 4. detect first cycle node
visited := make(map[string]bool)
current := cycleStartToken
for !visited[current] {
visited[current] = true
edge := predecessor[current]
if edge == nil {
return nil, false // missing edge
}
current = edge.From.Address
}
// 5. Complete cycle
cycleStart := current
cycle := []*Edge{}
for {
edge := predecessor[current]
if edge == nil {
return nil, false // missing edge
}
cycle = append(cycle, edge)
current = edge.From.Address
if current == cycleStart {
break
}
}
// 6. Invert cycle
for i, j := 0, len(cycle)-1; i < j; i, j = i+1, j-1 {
cycle[i], cycle[j] = cycle[j], cycle[i]
}
return cycle, true
}
Optimalios įplaukų sumos apskaičiavimas: maksimalus pelnas
Kai nustatomas neigiamas ciklas (arbitražo galimybė), kitas kritinis žingsnis yra nustatytioptimal input amountTai nėra savavališka; arbitražo galimybės pelningumas yra netiesinė prekybos dydžio funkcija dėl būdingo slydimo ir mokesčių, susijusių su AMM apsikeitimais.
Kaip išsamiai aprašyta „Uniswap rinkų analizėje“, pastovi produktų formulė iš esmės reiškia, kad įvesties ir išeities sumų santykis yra išlenktas. Konkrečiai, didėjant prekybos dydžiui, efektyvus valiutos keitimo kursas blogėja dėl baseino nekintamumo.Tai reiškia, kad yra saldus taškas: per maža suma gali nepadengti dujų mokesčių, o per didelė suma gali sukelti pernelyg didelį slydimą, eroduojantį pelną.
Maksimalus pelno padidinimas yraconvex optimization problemDėl N apsikeitimo serijos arbitražo kelyje galutinė išėjimo suma (taigi ir pelnas) gali būti išreikšta pradinės įvesties sumos funkcija (dx ). Nors tikslus daugiapakopio arbitražo analitinis sprendimas gali būti sudėtingas, ypač su skirtingomis mokesčių struktūromis ir slydimo kreivėmis įvairiose AMM, funkcija, atstovaujanti pelną minus sąnaudas (įskaitant dujas), paprastai yra išgaubta.
Mūsų arbitražo strategijos paslauga tai sprendžia, pasitelkdama optimizavimo sprendimą iš „Go“gonum/optimize
Šis sprendėjas atlieka funkciją, atitinkančią grynąjį pelną (pelną iš apsikeitimo sandorių, atėmus apskaičiuotus dujų mokesčius ir bet kokias „flash“ paskolos įmokas) ir suranda įvesties sumą, kuri maksimaliai padidina šią vertę.amountOut
Formulėsdy = (x + dx) / (dx⋅ y)
už kiekvieną arbitražo kelio žingsnį, atsižvelgiant į tarpines atsargas, mokesčius ir slydimą kiekviename etape.
func getOptimalAmoutIn(edges []*Edge, decimals int) (*float64, error) {
factor := math.Pow10(decimals)
intMax, _ := constants.GetRouterReserveFromToken(edges[0].From.Address)
maxCapital := new(big.Float).Mul(new(big.Float).SetInt64(intMax), big.NewFloat(factor))
fee := big.NewFloat(0.997)
problem := optimize.Problem{
Func: func(x []float64) float64 {
delta := big.NewFloat(x[0])
if delta.Cmp(big.NewFloat(0)) < 0 || delta.Cmp(maxCapital) > 0 {
return math.Inf(1)
}
delta_i := new(big.Float).Set(delta)
for _, edge := range edges {
effectiveIn := new(big.Float).Mul(delta_i, fee)
reserveIn := new(big.Float).SetInt(edge.Reserve0)
reserveOut := new(big.Float).SetInt(edge.Reserve1)
num := new(big.Float).Mul(reserveOut, effectiveIn)
denom := new(big.Float).Add(reserveIn, effectiveIn)
delta_i = new(big.Float).Quo(num, denom)
}
profit := new(big.Float).Sub(delta_i, delta)
result, _ := profit.Float64()
return -result
},
}
result, err := optimize.Minimize(problem, []float64{1.0}, nil, nil)
if err != nil {
return nil, err
}
return &result.X[0], nil
}
Swapų modeliavimas ir pelningumo vertinimas
Prieš išsiunčiant bet kokį sandorį, arbitražo strategijos tarnyba atlieka kruopštųsimulated executionŠis žingsnis yra labai svarbus siekiant patikrinti faktinį pelningumą, atsižvelgiant į realaus laiko rinkos sąlygas ir tikslius siūlomų sandorių parametrus.
Simuliacijoje naudojamos susijusių likvidumo baseinų dabartinės atsargos ir apskaičiuota optimali įvesties suma.Kiekvienam kelių pėdų kelio žingsniui ji taiko konkrečią AMM formulę (pvz., Uniswap V2 tipo baseinų pastovios produkto formulę), kad apskaičiuotų numatomą išvestį:
func (ab *ArbitrageBuilderV2) calculateProfitabilityWithSlippage(edges []*Edge, decimals int) (*big.Float, *big.Float, error) {
opt, err := getOptimalAmoutIn(edges, decimals)
if err != nil {
return nil, nil, err
}
optBig := new(big.Float).SetFloat64(*opt)
amount := new(big.Float).Set(optBig)
fee := big.NewFloat(0.997)
for _, edge := range edges {
if edge.Reserve0 == nil || edge.Reserve1 == nil ||
edge.Reserve0.Cmp(big.NewInt(0)) == 0 || edge.Reserve1.Cmp(big.NewInt(0)) == 0 {
return nil, nil, errors.New("edge has invalid reserves")
}
reserveIn := new(big.Float).SetInt(edge.Reserve0)
reserveOut := new(big.Float).SetInt(edge.Reserve1)
amountInWithFee := new(big.Float).Mul(amount, fee)
if amountInWithFee.Cmp(reserveIn) >= 0 {
return big.NewFloat(-1.0), nil, errors.New("amount exceeds available reserves")
}
// "x * y = k"
numerator := new(big.Float).Mul(reserveOut, amountInWithFee)
denominator := new(big.Float).Add(reserveIn, amountInWithFee)
amountOut := new(big.Float).Quo(numerator, denominator)
amount = amountOut
}
profit := new(big.Float).Sub(amount, optBig)
profit.Sub(profit, ab.EstimateGasCost(len(edges)))
profit.Sub(profit, new(big.Float).Mul(optBig, big.NewFloat(0.005)))
normalizedProfit := new(big.Float).Quo(profit, new(big.Float).SetFloat64(math.Pow10(decimals)))
return normalizedProfit, optBig, nil
}
Svarbiausia, kad simuliacija taip pat apimaminimum output amount (minOut)Patikrinkite kiekvieną vidutinį žingsnįminOut
vertės yra išgaunamos iš imituotų numatomų išėjimų ir nustatomos kaip faktinės grandinės operacijos parametrai.Jei dėl tinklo vėlavimo, priekinės ar netikėtų rinkos sąlygų faktinė grandinės apsikeitimo grąža yra mažesnė nei nurodytaminOut
Šis mechanizmas yra gyvybiškai svarbi apsaugos priemonė, neleidžianti botui užbaigti nepelningos prekybos sekos ir apriboti nuostolius tik dujomis, išleidžiamomis atvirkštinėje prekyboje.
Tik tuo atveju, jei galutinis grynasis pelnas, nepaisant visų mokesčių, nuolaidų, dujų sąnaudų ir „flash“ paskolų įmokų, viršija iš anksto nustatytą sumą.profit threshold(pvz., 0,5% pradinės įvesties sumos) yra galimybė, laikoma perspektyvia ir perduota Transaction Builder Service vykdymui.
Sandorių inžinerija: greitas vykdymas tamsiame miške
Nustatyti pelningą arbitražo galimybę yra tik pusė mūšio; kitas, galbūt svarbesnis, pusė yra gebėjimas vykdyti prekybą su neprilygstamu greičiu ir patikimumu. „DeFi“ hiper-konkurenciniame „Tamsiajame miške“, kur galimybės yra miglotos ir sudėtingos robotai gyvena kiekvieną milisekundę, sandorių inžinerija tampa meno forma.Transaction Builder Servicesukurta siekiant užtikrinti žaibo greitą ir saugų vykdymą.
Greitumo imperatyvas
Decentralizuotų biržų arbitražo galimybių pelningumo langas dažnai matuojamas milisekundėmis. Kainų skirtumai greitai aptinkami ir išnaudojami daugelio automatizuotų sistemų, sukuriant žiaurią lenktynes būti pirmuoju įtraukti pelningą sandorį į naują bloką. Bet koks vėlavimas, nors ir nedidelis, gali sukelti galimybę būti pasisavinęs konkurentas, todėl nesėkmingas sandoris ir švaistomi dujų mokesčiai.
In-Memory optimizavimas momentiniams sandoriams kurti
Norint pasiekti reikiamą greitį, mūsų sistema teikia pirmenybę, kad visi esminiai sandorių komponentai būtų lengvai prieinami atmintyje, pašalinant brangias I / O operacijas ar grandinės skambučius kritinio sandorio kūrimo etapo metu.
- Iš anksto suskirstytos ir supakuotos ABI: išmaniosios sutarties taikymo dvejetainės sąsajos (ABI) apibrėžia, kaip sąveikauti su sutartimis. Užuot analizuojant ABI apibrėžtis ir kodavimo funkcijos skambučius kiekvienos operacijos metu, mūsų sistema iš anksto suskirsto ir supakuoja reikiamas ABI duomenų struktūras ir funkcijų atrankas į žaliąsias bytes[] diapazonus. Šios iš anksto apskaičiuotos bendrų sutarčių sąveikos byte sekos (pvz., swapExactTokensForTokens, flashLoanSimple, transferFrom) saugomos atmintyje. Kai nustatoma arbitražo galimybė, sandorio kūrėjas gali greitai surinkti skambučių duomenis, tiesiog
- Cached On-Chain duomenys sandorių laukams: Norint išvengti nereikalingų grandinės kvietimų į sandorių metaduomenis, speciali naudingumo struktūra roboto viduje palaiko kritines, dažnai atnaujinamas reikšmes atmintyje:
- Sąskaitos nonsas: Nonsas (transakcijų, siunčiamų iš adreso, skaičius) yra labai svarbus siekiant užkirsti kelią atkūrimo atakoms ir užtikrinti sandorių užsakymą.Jis yra paimamas vieną kartą, o po to palaipsniui tvarkomas atmintyje, o tvirtas klaidų tvarkymas vėl sinchronizuojamas, jei sandoris nepavyksta arba netikėtai neįtraukiamas į užsakymą.
- Optimalūs dujų parametrai: vietoj užklausų tinkle dėl dujų kainų (arba bazinių mokesčių / prioritetinių mokesčių EIP-1559 grandinėse) už kiekvieną sandorį, botas periodiškai surenka optimalius dujų parametrus.
- Pasirašytojo informacija: privatus raktas bot piniginėje ir susijęs pasirašytojo objektas (naudojamas kriptografiniam sandorių pasirašymui) įkeliami į atmintį inicijavimo metu.
Laikydami šiuos gyvybiškai svarbius komponentus atmintyje, „Transaction Builder“ paslauga gali sukurti ir pasirašyti visą blokų grandinės sandorį vos per keletą mikrosekundžių, paruoštą nedelsiant išsiųsti.
Dinaminis išmaniųjų sutarčių pasirinkimas: „Flash“ paskolos prieš tiesioginius apsikeitimus
Arbitražo strategijos paslauga perduoda optimizuotą arbitražo kelią ir apskaičiuotą optimalią įvesties sumą sandorio kūrėjui.amountIn
ir ar ji viršija iš anksto apibrėžtą kapitalo slenkstį (arba jei strategija aiškiai to reikalauja), sandorio kūrėjas dinamiškai pasirenka dvi pagrindines protingas sutartis vykdymui:
- Tiesioginio apsikeitimo vykdymo sutartis: Galimybėms, kurios gali būti tiesiogiai finansuojamos botui priklausančio kapitalo, kūrėjas naudoja executeArb funkciją (ar panašią) individualioje daugiašalėje apsikeitimo proxy sutartyje. Kaip parodyta 3 skyriuje, ši sutartis paima įvesties žetonus iš boto piniginės ir atlieka visą apsikeitimo seką vienoje atominėje operacijoje.
- "Flash Loan" integruota sutartis: Kai apskaičiuota optimali arbitražo suma yra žymiai didesnė nei turimas botas kapitalas, statybininkas siekia atskiros, individualizuotos protingos sutarties, skirtos inicijuoti ir valdyti "flash" paskolas. Šios sutarties pradžiaArbitražo funkcija (kaip išsamiai aprašyta 3 skyriuje) prašo "flash" paskolos iš tokio protokolo kaip "Aave", kuris tada atšaukia sutarties vykdymąOperation funkcija.
Šis dinamiškas pasirinkimas užtikrina efektyvų kapitalo paskirstymą ir optimalų strategijos įgyvendinimą, atsižvelgiant į kiekvienos aptiktos galimybės ypatumus.
Mempool Dynamics: „Ethereum L1“ prieš „Layer 2“ grandines
Kritinis arbitražo vykdymo aspektas yra suprasti blockchain sandorių sklaidos mechanizmą, ypačmempool.
-
Ethereum L1 Mempool: On Ethereum’s Layer 1, the mempool is a public, transparent waiting room for all pending transactions. Transactions broadcasted by users or bots are relayed to various nodes across the network, becoming visible to anyone monitoring the mempool. This transparency is the breeding ground for generalized frontrunning bots (often referred to as “searchers” or “MEV bots”). These sophisticated entities continuously scan the mempool for profitable transactions (e.g., large swaps that cause significant price impact, liquidations, or other arbitrage attempts). Upon detecting such a transaction, they quickly construct an identical or similar transaction, replace the original recipient address with their own, and submit it with a higher gas price (or higher priority fee in EIP-1559) to ensure their transaction is included in the block before the original, thereby stealing the profit. This competitive landscape makes direct arbitrage on L1 highly challenging without leveraging specialized MEV relays.
-
Layer 2 (L2) Chains and Reduced Mempool Visibility (e.g., Base): Our bot strategically operates on Base, an EVM-compatible Layer 2 blockchain. The architecture of many L2s, including Base, fundamentally alters the traditional L1 mempool dynamic. Base does not currently expose a publicly visible mempool in the same manner as Ethereum Layer 1. Instead, transactions are typically sent directly to a centralized sequencer or a private mempool before being batched and committed to the L1.
This architectural difference significantly reduces the direct threat of generalized frontrunning. While MEV still exists on L2s (e.g., through sequencer-controlled ordering or other means), the immediate, public visibility of pending transactions that enables L1 frontrunning is largely absent. This provides a more predictable and secure execution environment for our arbitrage transactions, as the bot’s crafted atomic operations are less likely to be “sniped” before they even reach a block producer. This improved execution predictability contributes directly to higher success rates for profitable arbitrages.
Nodo greitis ir saugumas: patikimo vykdymo pagrindas
Ryšys su blokų grandine yra vienas visų duomenų ir sandorių įėjimo ir išėjimo taškas.
- Aukštos kokybės mazgo ryšys: „Transaction Builder“ paslauga prisijungia prie specializuoto, aukštos kokybės mazgo teikėjo (pvz., „Alchemy“, „Infura“ arba savarankiškai prieglobos mazgo). Greitas ir mažo uždelsimo ryšys yra būtinas norint sumažinti laiką tarp sandorio pasirašymo ir jo plitimo į tinklą.
- Nodo saugumas ir vientisumas: prijungto mazgo saugumas yra vienodai svarbus. Naudojant patikimus mazgo teikėjus arba užtikrinant labai apsaugotą savarankišką mazgą, labai svarbu užkirsti kelią žmogaus viduryje išpuoliams ar duomenų manipuliavimui. Nukentėjęs mazgas gali potencialiai išleisti privačius raktus, įšvirkšti kenkėjiškus sandorius arba manipuliuoti duomenimis, o tai lemia katastrofiškus nuostolius. Mūsų sistemos priklausomybė nuo privačių RPC galinių taškų (jei yra iš teikėjų) ir saugių ryšių kanalų (https HTTP, wss WebSockets) sustiprina šią saugumo poziciją.
Kruopščiai optimizuojant greitį kiekviename sluoksnyje, nuo atminties duomenų struktūrų ir išankstinio skaičiavimo iki strateginės grandinės atrankos ir tvirtos mazgų infrastruktūros, mūsų arbitražo botas yra skirtas pranokti konkurentus ir saugiai išnaudoti besikeičiančias galimybes DeFi kraštovaizdyje.
Navigavimas tamsiame miške: iššūkiai, etika ir ateities perspektyvos
Arbitražo roboto kūrimas ir eksploatavimas DeFi „Tamsiajame miške“ liudija decentralizuotų technologijų galią, tačiau taip pat atskleidžia didelius iššūkius ir etinius aspektus.
Nuolatinė kova su piktybiniais veikėjais: Bloom vaidmuo
Pradinis optimizmas, susijęs su DeFi neleistinu pobūdžiu, deja, buvo sušvelnintas kenkėjiškų veikėjų plitimu.Honeywall ServiceTai yra gyvybiškai svarbi paskutinė gynybos linija, tačiau šių blogų veikėjų išradingumas nuolat reikalauja besivystančių atsakomųjų priemonių.
Pagrindinis šios gynybos elementas yraBloom filter"Bloom" filtras yra tikimybinė duomenų struktūra, kuri gali greitai ir efektyviai išbandyti, ar elementas yra rinkinio narys. Jis yra labai erdvinis, bet turi mažą "klaidingų teigiamų" tikimybę (nurodant, kad elementas yra rinkinyje, kai jis nėra), nors niekada "klaidingų neigiamų". Mūsų kontekste "Bloom" filtras naudojamas iš anksto filtruoti gaunamus įvykių duomenis iš "Blockchain Data Reader" paslaugos. Jame yra žinomų kenkėjiškų ar didelių mokesčių likvidumo porų adresų hashai. Prieš atliekant bet kokį išsamų apdorojimą ar atsargų paėmimą, greitas patikrinimas prieš "Bloom" filtrą gali nedelsiant atmesti žinomų probleminių por
Nepaisant sudėtingų išankstinių patikrinimų, įgyvendintų mūsų įprastaiArbHelperMap
Išmanioji sutartis (ypač_checkTaxLimit
logika, kuri imituoja apskritojo kelionių apsikeitimą, kad būtų galima įvertinti mokesčius), kai kurioms kenkėjiškoms poroms vis dar pavyksta apeiti šiuos pradinius grandinės patvirtinimus.getAmountsOut
funkcija (naudojama kainų užklausoms) grąžinti atrodytų normalias, mažo mokesčio išvestis.swapExactTokensForTokens
arba pagrįstastransfer
Šios funkcijos gali nustatyti pernelyg didelius paslėptus mokesčius (pavyzdžiui, 99 %) pardavimo operacijoms arba net visiškai apriboti pardavimą, veiksmingai sugavus lėšas.
Per mūsų bandymų fazę mes susidūrėme su daugybe tokių apgaulingų porų. aš asmeniškai surinko keletą porų adresų, kurie sėkmingai praėjo pradinįgetAmountsOut
patikrinimai, bet atskleidė paslėptus mokesčius arba pardavimo apribojimus tik per faktinį (simuliuotą ar atvirkštinį) sandorį vietinėje duomenų bazėje. Šis db failas bus viešai prieinamas projekto GitHub saugykloje, kuris tarnauja kaip bendruomenės šaltinis, kad padėtų kitiems išvengti šių spąstų.
Etikos pasekmės ir tamsiųjų miškų šešėlis
„Tamsos miško“ analogija tinka ne tik konkurencijai tarp robotų, bet ir platesniam DeFi etiniam kraštovaizdžiui. arbitražo efektyvumas, nors ir labai svarbus rinkos sveikatai ir kainų atradimui, ateina su griežta realybe: arbitražo generuojamas pelnas dažnai atspindi vertę, išgautą iš mažiau sudėtingų rinkos dalyvių.
Visapusiška kultūraFOMO (Fear Of Missing Out), kartu su bendru supratimo apie pagrindinius blokų grandinės mechanizmus ir finansines priemones trūkumu, daugelis mažmeninių vartotojų lengvai patenka į šią aplinką. jie patenka į labai nepastovias rinkas, sąveikauja su naujais protokolais ir vykdo sandorius be visiško supratimo apie tokias sąvokas kaip slydimas, MEV ar paslėpti sutarčių mokesčiai.
Šis dinamiškas, nors ekonomiškai logiškas tiems, kurie turi pažangias priemones, skleidžia šešėlį decentralizuotų technologijų reputacijai. Pasakojimas gali greitai pereiti nuo „finansinio įgalinimo“ prie „grobio elgesio“, eroduojant pasitikėjimą erdvėje, kuri kitaip turi didžiulį pažadą. DeFi pagrindinis tikslas yra demokratizuoti finansus, suteikiant neleistiną prieigą ir skaidrumą. Tačiau sudėtingas MEV pobūdis ir sukčiavimo paplitimas gali netyčia pakenkti šiems idealams, sukuriant dviejų lygių sistemą, kurioje tik technologiškai patyrę žmonės gali saugiai naršyti. Būtina, kad, kaip statybininkai, mes pripažintume šiuos etinius aspektus ir skatintume did
Išvada: vis dar plaukiojant tamsiame miške
Nepaisant būdingo DeFi kraštovaizdžio sudėtingumo ir nuolatinių iššūkių, šio arbitražo boto inžinerijos kelionė buvo puikus teorinių principų, atitinkančių praktinį įgyvendinimą, patvirtinimas.speed, precision, and data-driven insights, galintis aptikti ir vykdyti daugiapakopio arbitražo galimybes.
Iš pradžių „Tamsiajame miške“ buvo įprasta tikėtis, kad didžiąją arbitražo vertės dalį iš karto perims dideli, gerai išteklių turintys žaidėjai, pasinaudodami savarankiškai prieinamais mazgais ir tiesiogine prieiga prie blokų gamintojų. tačiau mūsų bandymai ir sėkmingi sandoriai parodė, kad mažesniems, gerai suprojektuotiems robotams tikrai įmanoma nuosekliai rasti ir pasinaudoti šiomis trumpalaikėmis galimybėmis:
Nors pelningas arbitražas senesniuose AMM modeliuose, pvz., Uniswap V2 (kurie daugiausia remiasi nuolatiniais produktų baseinais), gali būti sudėtingas ilgalaikiam išlaikymui dėl didėjančių dujų sąnaudų ir padidėjusios konkurencijos, „Tamsus miškas“ ir toliau vystosi. Naujausi įgyvendinimai, pvz., „Uniswap V3“ koncentruoti likvidumo AMM (CLAMM), įveda naujus arbitražo vektorius, kuriems reikia sudėtingesnio modeliavimo, tačiau dažnai duoda didesnę grąžą dėl padidėjusio kapitalo efektyvumo. Be to, auganti kryžminio arbitražo sritis, panaudojant tiltus ir tarpblockchain komunikacijos protokolus, siūlo didesnę ribą, susijusią
Taigi, nors aš vis dar esu neturtingas, galiu pasitikėti, kad tapau puikiu miško navigatoriumi.My compass is sharper, my map more detailed, and I understand the whispers of the canopy.
Projekto saugykla
Tiems, kurie nori pasinerti giliau į praktinį įgyvendinimą ir labai realius duomenis už kai kurių "spąstų", apie kuriuos kalbėjome, mūsų kodų bazės ir duomenų bazės, kurioje yra žinomų kenkėjiškų žetonų porų, sanitarinė versija yra prieinama manoGithub archyvasŠios 85 konkrečios poros, nors ir mažos, sukuria neproporcingai didelį sandorių kiekį, nes jos nuolat bando vilioti naivius robotus į nepelningas operacijas.
Github archyvasReferencijos
- Dan Robinson, Georgios Konstantopoulos „Ethereumas yra tamsus miškas“.
- Guillermo Angeris, Hsien-Tang Kao, Rei Chiang, Charlie Noyes ir Tarun Chitra. „Uniswap rinkų analizė“, Cryptoeconomic Systems.
- Claudio Gebbia. „Arbitražo robotų analizė ir įgyvendinimas centralizuotoje ir decentralizuotoje finansų srityje“, Ciuricho universitetas.
- Y. Zhang, Z. Li, T. Yan, Q. Liu, N. Vallarano ir C. J. Tessone, „Pelno padidinimas arbitražo grandinėse“. archyvas.