# İmza kimi söyler, neyi değil

> İmzalanmış bir işlem kesin görünür. Oysa imza, geçerli bir şeyi kimin onayladığını kanıtlar — çalışan şeyin onayladıkları şey olduğunu değil. DeFiLoops bu boşluğa şunu koyar: bir içerik makbuzu ve bir işlemin gerçekte ne yaptığına bakan bir simülasyon.

- Source: https://defiloops.com/tr/blog/a-signature-says-who-not-what
- Published: 2026-09-15
- Category: Security
- Tags: security, agentic-wallet, signatures, simulation, execution
- Author: DeFiLoops

---
İmzalanmış bir işlem hikâyenin sonu gibi hissettirir. Yetkili biri onayladı, imza doğrulanıyor,
zincir buna uyacak. Bitti.

Ama *onaylandı* ile *çalıştırıldı* arasında bir boşluk var ve göründüğünden geniş. Bir ajanın
imzaladığı an ile işlemin bir bloğa girdiği an arasında bir rota seçilir, calldata kurulur ve
dakikalar geçer. İmza, **kimin** onayladığına dair bir ifadedir — sonunda **neyin** çalıştığı
hakkında neredeyse hiçbir şey söylemez. O boşluğu kapatmak güvenlik işinin büyük kısmıdır ve
hiçbiri imza değildir.

## Ajan gerçekte neyi imzalar

Ajanımız hiçbir zaman ham bir işlem imzalamaz. **Tipli bir niyet** imzalar — bir tutar, listeden
adı verilmiş bir mekân, bir aralık — ve adaptör çağrıyı bu parametrelerden kurar. Ele geçirilmiş
bir ajanın bir çağrıyı saldırgana yöneltememesinin bütün sebebi budur: ona hedef verilmemiştir
([bunu burada yazdık](/blog/the-executor-that-trusted-itself)).

Ama tipli olsun ya da olmasın, bir imza yalnızca hash'lediği alanları kapsar. Ve bir EIP-712
mesajı bir *alt kümeyi* hash'ler.

<Callout type="danger" title="İmza, bir örnek hakkında değil, bir sınıf hakkında bir ifadedir">
  Tek bir teminatlandırma niyetinde, **yirmi altı isteğe bağlı alandan yirmi biri zincire hiç
  ulaşmaz.** İmza ajana kusursuzca çözülür — onları hiç kapsamamıştır sadece. Yani geçerli bir
  imza, ajanın *geçerli niyetlerden oluşan geniş bir ailedeki bir şeyi* onayladığını kanıtlar.
  Hangisini olduğunu kanıtlamaz. Geçerlilik ailenin bir özelliğidir; kimlik değildir.
</Callout>

Çatlak budur. İmzalama ile çalıştırma arasında bu kapsanmayan alanlardan birini
değiştirebilen her şey, *her imzayı doğrulanır bırakarak* *ne olduğunu* değiştirir. Niyetin
hâlâ geçerli olup olmadığını yeniden denetlemek işe yaramaz — değişmiş niyet de geçerlidir. İki
denetim de hemfikirdir, farklı niyetler hakkında.

## Dakikalar arayla iki onay

Bir adaptör planı bilerek iki kez yetkilendirilir, çünkü ilk onay anında calldata mevcut
değildir.

<Steps>
  <Step title="Grubu imzala ve bir makbuz bas">
    İmzalayan her adımı doğrular, her birinin EIP-712 mesajını imzalar ve bir **doğrulama
    makbuzu** basar — aynı anahtarla imzalanmış bir ifade: *tam olarak şu içerik hash'lerine
    sahip niyetleri, tam olarak şu limitler altında, bu zincirdeki bu hesap için doğruladım.*
    İçerik hash'i, imzalanan alt kümeyi değil, **her** alanı kapsar.
  </Step>
  <Step title="Planın henüz bilemeyeceği rotayı kur">
    Ancak şimdi yönlendirme takasın havuzlarını seçer ve gerçek calldata'yı kurar. İkinci bir
    onayın bütün sebebi budur — baytlar az önce mevcut değildi.
  </Step>
  <Step title="Tam baytları yetkilendir ve makbuzu denetle">
    İkinci durak, elindeki şeyin içerik hash'ini yeniden hesaplar ve makbuzla karşılaştırır. Aynı
    niyet, bit bit — zincirin asla görmeyeceği her alan dâhil. Kapsanmayan tek bir alan
    değiştiyse hash'ler uyuşmaz ve reddeder.
  </Step>
</Steps>

Makbuz tek bir kesin iş yapar: *"bu geçerli mi?"* sorusunun — ki birinci durak onu zaten
yanıtladı ve ikincisi faydalı biçimde yeniden yanıtlayamaz — yerine gerçekten önemli olan
*"bu aynı mı?"* sorusunu koyar. İkinci durağın yalnızca ikinci durakta öğrenebileceği şeyleri,
örneğin rotanın iyi dolup dolmadığını, orada öğrenmeye devam eder. Tazelik makbuzdan asla
güvenilerek alınmaz; 12:00'de basılmış bir makbuz 12:20 hakkında hiçbir şey söylemez, bu yüzden
zamanlama her hâlükârda yeniden denetlenir.

<Callout type="warn" title="Makbuz neden damgalanmış değil, imzalanmış">
  Ajanın kendi anahtarıyla imzalanır ve sabit bir etiketle alan ayrımı yapılır; böylece bir
  makbuz özeti para hareket ettiren bir EIP-712 mesajıyla asla çakışamaz. HMAC değil — o,
  dağıtılacak, döndürülecek ve eninde sonunda sızacak paylaşılan bir sır demek olurdu; güvenli
  bir enklav içinde ise *içeri* girmesi gereken bir sır. Anahtar zaten oradadır. Maliyeti adım
  başına değil, grup başına bir fazladan imzadır.
</Callout>

## Bir işlemin *ne yaptığına* bakan denetim

Yukarıdakilerin tamamı işlemin onaylanan işlem olduğunu kanıtlar. *Güvenli* olduğunu
kanıtlamaz — doğru imzalanmış, doğru eşleşmiş bir niyet yine de berbat dolan bir havuzdan
geçebilir veya arkasında bir onay bırakabilir. Bu yüzden herhangi bir şey yayınlanmadan önce onu
çalıştırırız.

Simülatör işlemi gerçek ve güncel bir bloğa karşı **yayınlamadan** çalıştırır —
`debug_traceCall` — ve her çağrıyı, logu ve durum değişikliğini bildirir. Sonra tek bir kural
sonucu yargılar. Sistemdeki, ne istendiğine değil bir işlemin *ne yaptığına* bakan tek kuraldır.

<Spec title="Simülasyonun yayından önce reddettikleri" rows={[
  ['Planın beyan etmediği net bir kayıp', 'Hesap yalnızca planın kaybettiğini söylediği kadarını kaybedebilir. Ötesindeki her şey reddedilir.'],
  ['Geriye kalan herhangi bir onay', 'Her (sahip, harcayan) onayı sıfırda bitmelidir. Ayakta kalan bir onay, bir saldırganın geride bırakabileceği en değerli şeydir — işlemden sonra da yaşar ve başka hiçbir şey onu aramaz.'],
  ['Tabanın altında bir çıktı', 'Planın satın aldığı şey, planın zaten imzaladığı tabanda ya da üstünde gelmelidir. Kötü dolan bir rota zincirde geri dönmek yerine burada, ucuza ve gazdan önce reddedilir.'],
  ['Hiçbir adımın taşımadığı bir NFT', 'Planda bir adım taşımadıkça hiçbir pozisyon ya da token hareket etmez. Bir Uniswap pozisyonu bir NFT\'dir ve id\'si daha önce tutar sanılmış bir sayıdır.'],
]} />

Bunu mümkün kılan hile, simülasyonun *gerçek* sayıları döndürmesidir; böylece fiyat oracle'ına
ihtiyacı olmaz — planın zaten taşıdığı tabanla karşılaştırır. Ve geri dönen bir çağrı, etrafından
dolaşılacak bir hata değildir; bulgunun kendisidir. Paketteki herhangi bir çağrı geri dönerse
işlemin hiçbir etkisi kalıcı olmaz, ve yayından önce reddetmek boşa gaz yakan bir zincir
geri dönüşünü ucuz ve okunaklı bir *hayır*'a çevirir.

<Callout type="warn" title="Simülasyon ne değildir">
  Zincirin kendi denetimlerinin yerine geçmez. Simülasyon tek bir bloktaki bir tahmindir; işlem
  daha sonraki birine iner, bu yüzden `minOut` hâlâ imzalanır ve adaptör hâlâ onu uygular. Bu,
  yeni bir doğruluk kaynağı değil, daha ucuz, daha erken ve daha okunaklı bir reddir. Ve fiyat
  hakkında bir yargı da değildir: kötü dolan ama tabanın üstünde kalan bir rota geçer. *Onu*
  sınırlamak, bir tabanın ne kadar geniş olabileceğiyle ilgili bir sorudur, simülasyonla değil.
</Callout>

## Boşluktaki her şey kapalı başarısız olur

Bunları yan yana dizin: her adımda biçim aynıdır — güvenli cevap *hayır*'dır ve varsayılan odur.

<StatRow>
  <Stat value="kim" label="bir imzanın kanıtladığı" />
  <Stat value="ne" label="makbuz + simülasyonun kanıtladığı" accent />
  <Stat value="hayır" label="herhangi biri uyuşmadığında cevap" />
</StatRow>

Sınırlandırılmamış bir koruma reddeder. Eksik bir makbuz reddeder. Uyuşmayan bir içerik hash'i
reddeder. Planla uyuşmayan bir simülasyon reddeder — tek bir bayt yayınlanmadan önce. Bunların
hiçbiri imza değildir. İmza hiçbir zaman zor kısım olmadı; yalnızca *birinin* *bir şeyi*
onayladığını kanıtladı. Hat, bunun *şu* şey olduğunu ve *şu* şeyin planın dediğini yaptığını
kanıtlamak için var.

## Bunların herhangi biri nasıl değerlendirilir

Bu sayfaya güvenmeniz gerekmiyor. Gerçek bir yürütme hattını bir imza ve bir dualdan ayıran
soru kısadır: **onaylandığı an ile indiği an arasında ne denetleniyor?**

Cevap "imza doğrulanıyor" ise, imzanın kapsamadığı her alan açıktır ve calldata'yı kuran her ne
ise ona tamamen güvenilmektedir. Cevap bir *içerik makbuzu* ve bir *etki simülasyonu* adını
veriyorsa, bir imzanın yapamadığı iki şey — aynılığı kanıtlamak ve gerçekte ne olduğunu
yargılamak — bunu yapabilen bir şey tarafından yapılıyor demektir.