İlk bölümde "güvenli iletişim hattımızı" kurmuştuk. Bu bölümde işin kalbine, yani swap mantığını yazma kısmına geçiyoruz. Görevimiz; Uniswap V3 için sadece gizli kalacak değil, aynı zamanda gerçekleşmesi garanti altına alınmış bir işlem hazırlamak.
1. Swap İşleminin Hazırlanması
Örnek olarak bir ETH - USDC swap'i kurgulayalım. İşlemin bir bundle (paket) içinde geçerli olabilmesi için, objeyi ağa önceden yayınlamadan, arka planda hazırlamamız gerekiyor.
Masada şunların olması şart:
- Uniswap V3 Router adresi.
exactInputSinglefonksiyonu için (en azından minimal düzeyde) bir ABI.- Öncelik payını hesaba katan bir gaz hesaplaması.
Altın Kural: Flashbots paketlerinde standart
gasPricedevre dışı kalır; yerinemaxFeePerGasvemaxPriorityFeePerGasgelir. Paketinizin bloğa girip girmeyeceğini belirleyen asıl şey priorityFee, yani doğrulayıcıya (validator) verdiğiniz "bahşiştir".
2. Kod: Oluşturma ve Simülasyon
Projemize swap.ts dosyasını ekleyelim. Buradaki asıl olay .simulate() metodunda bitiyor. Bu, Flashbots'un en büyük kozu: Gerçek gaza tek kuruş harcamadan, işlemin blokzincirinin o anki durumunda çalışıp çalışmayacağını test etmenizi sağlar.
import { ethers } from "ethers";
import { FlashbotsBundleRawTransaction } from "@flashbots/ethers-provider-bundle";
// Uniswap V3 Router ile etkileşim için gereken en temel ABI
const ROUTER_ABI = [
"function exactInputSingle((address tokenIn, address tokenOut, uint24 fee, address recipient, uint256 deadline, uint256 amountIn, uint256 amountOutMinimum, uint160 sqrtPriceLimitX96)) external payable returns (uint256 amountOut)"
];
const ROUTER_ADDRESS = "0xE592427A0AEce92De3Edee1F18E0157C05861564";
export async function createAndSimulateBundle(wallet: ethers.Wallet, flashbotsProvider: any, provider: ethers.Provider) {
const block = await provider.getBlock("latest");
const nextBlockNumber = block!.number + 1;
// 1. Arayüzü oluştur ve işlem verilerini hazırla
const iface = new ethers.Interface(ROUTER_ABI);
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 dakikalık süre
const amountIn = ethers.parseEther("0.1"); // 0.1 ETH swap ediyoruz
const params = {
tokenIn: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
tokenOut: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
fee: 3000, // %0.3 havuz
recipient: wallet.address,
deadline: deadline,
amountIn: amountIn,
amountOutMinimum: 0, // Canlıda her zaman slippage (fiyat kayması) hesaplayın!
sqrtPriceLimitX96: 0
};
const data = iface.encodeFunctionData("exactInputSingle", [params]);
// 2. İşlem yapısı
const transaction = {
to: ROUTER_ADDRESS,
value: amountIn,
data: data,
chainId: 1,
type: 2, // EIP-1559
gasLimit: 250000,
maxFeePerGas: ethers.parseUnits("50", "gwei"),
maxPriorityFeePerGas: ethers.parseUnits("2", "gwei"), // Doğrulayıcıya giden "rüşvet"
nonce: await wallet.getNonce()
};
// 3. İmzalı paketi (bundle) oluştur
const signedBundle = await flashbotsProvider.signBundle([
{
signer: wallet,
transaction: transaction
}
]);
// 4. SİMÜLASYON (Kritik aşama)
console.log("Paket simülasyonu başlatılıyor...");
const simulation = await flashbotsProvider.simulate(signedBundle, nextBlockNumber);
if ("error" in simulation) {
console.error(`Simülasyon başarısız: ${simulation.error.message}`);
return;
}
console.log("Simülasyon canavar gibi!", JSON.stringify(simulation, null, 2));
return signedBundle;
}
3. Teknik Detay: Simülasyon Neden Şart?
"Genel" mempool'da, eğer işleminiz başarısız olursa (gaz limitinin yetmemesi veya fiyatın değişmesi gibi), işlem yine de bloğa girer ve siz o gaz ücretini kuzu kuzu ödersiniz.
Flashbots dünyasında ise:
- Eğer simülasyon hata verirse, paketi hiç göndermezsiniz. Zararınız sıfır olur.
- Paket gönderilse bile, eğer bloktaki şartlar değişmişse ve işlem kârsız hale gelmişse; doğrulayıcı paketi görmezden gelir.
Özetle: Gaz ücretini sadece "Stealth Swap" işleminiz gerçekten gerçekleştiğinde ödersiniz.
4. "Rüşvet" (Priority Fee) Nasıl Hesaplanır?
Doğrulayıcılar, paketleri kendilerine sağladığı kâra göre sıraya dizerler. Bir paketin kârlılığı (Gas Price Score) şu şekilde hesaplanır:

Sıradan bir swap yapıyorsanız 1-2 gwei'lik bir maxPriorityFeePerGas genelde yeterlidir. Ancak piyasanın çok hareketli olduğu anlarda, bu özel yollarda bile bloğa girmek için rekabet kızışabilir.
Şu an elimizde ne var?
İmzalanmış, doğrulanmış ve gönderilmeye hazır bir paketimiz var. Uniswap kodunun düzgün çalışacağından ve cüzdandaki bakiyenin tüm masrafları karşılayacağından artık eminiz.
Bir sonraki (ve son) bölümde: Blok bekleme döngüsünü yazacak, paketi gerçek anlamda ağa salacak ve aracımız için kullanışlı bir CLI arayüzü oluşturacağız.