İçeriğe atla

Yazılar

Akıllı sözleşme denetimine hazırlık kontrol listesi

Akıllı sözleşme denetiminizden önce 30 kontrol: kapsam ve dokümantasyon, testler, Foundry fuzz ve invariant testleri, Slither triyajı, erişim kontrolü, entegrasyonlar ve dağıtım.

sigmacode.io mühendislik ekibi8 dk okuma

Bu sayfada (9)
  1. 1. Kapsam ve dokümantasyon
  2. 2. Kod hijyeni ve statik analiz
  3. 3. Testler
  4. 4. Fuzz ve invariant testi
  5. 5. Erişim kontrolü ve yükseltilebilirlik
  6. 6. Harici entegrasyonlar
  7. 7. Dağıtım ve operasyonlar
  8. 8. Denetim lojistiği
  9. Size nasıl yardımcı olabiliriz

Bir akıllı sözleşme denetimi pahalıdır ve kesin bir süreyle sınırlıdır. Denetçilere sabit sayıda gün verilir; kodun ne yapması gerektiğini anlamak için harcanan, hareketli bir commit'i kovalayan veya sizin yazmadığınız testleri yazan her saat, gerçekten fon kaybettirebilecek mantığa harcanmayan bir saattir. Bulgular raporu da ödemesini yaptığınız sorunlar yerine eksik NatSpec, floating pragma'lar ve test edilmemiş revert yollarıyla dolar.

İyi hazırlanmış bir kod tabanı, aynı bütçeyle daha derin bir denetim alır. Bu kontrol listesi, kodu harici bir denetçiye teslim etmeden önce yerine oturttuğumuz şeyleri toplar: dokümantasyon, kod hijyeni, test, erişim kontrolü, entegrasyonlar, dağıtım ve lojistik alanlarında 30 somut kontrol. Denetimin yerini tutmaz; denetim süresinin önemli yere gitmesini sağlar.

1. Kapsam ve dokümantasyon#

Denetçiler davranışı ancak anladıkları bir niyete karşı doğrulayabilir; bu yüzden niyetin yazılı olması gerekir.

  • Bir commit hash'i dondurun. Denetçilere etiketlenmiş tek bir commit verin ve sözleşme süresince incelenen kodu değiştirmeyin. Düzeltmeler ayrı bir branch'e gider ve düzeltme inceleme turunda gözden geçirilir.
  • nSLOC ile bir kapsam dosya listesi yayınlayın. Kapsamdaki her sözleşmeyi yolu ve normalize edilmiş kaynak kod satırı sayısıyla listeleyin ve neyin kapsam dışı olduğunu açıkça belirtin (kütüphaneler, mock'lar, script'ler, daha önce denetlenmiş dosyalar). Denetçiler nSLOC'a göre fiyat verir ve plan yapar; doğru bir sayım iki taraf için de sürprizleri önler.
  • Bir mimari genel bakış yazın. Sözleşmeleri, birbirlerini nasıl çağırdıklarını, hangi sözleşmelerin fon tuttuğunu ve ana kullanıcı akışlarını anlatan bir iki sayfa. Çağrıların ve token akışlarının basit bir diyagramı, denetçilere saatlerce tersine mühendislik kazandırır.
  • Davranışı ve invariant'ları düz yazıyla belirtin. Her external fonksiyonun ne yapması gerektiğini ve her zaman sağlanması gereken özellikleri tanımlayın; örneğin "kullanıcı bakiyelerinin toplamı totalAssets'e eşittir" veya "ücretleri yalnızca timelock değiştirebilir". Bu ifadeler hem denetçilerin incelemesinin hem de kendi invariant testlerinizin temelini oluşturur.
  • Bilinen sorunları ve kabul edilen riskleri belgeleyin. Halihazırda bildiğiniz sınırlamaları ve kabul ettiğiniz tasarım kararlarını — merkeziyet ödünleşimleri veya desteklenmeyen token tipleri gibi — listeleyin. Bu, onları bulgular raporunun dışında tutar ve denetçilere nerede zaten düşünmüş olduğunuzu gösterir.

2. Kod hijyeni ve statik analiz#

Kod tabanındaki gürültü denetim süresine mal olur ve düşük değerli bulgular üretir; denetçiler görmeden önce temizleyin.

  • Derleyiciyi sabitleyin ve sıfır uyarıya ulaşın. Floating ^0.8.0 yerine kesin bir pragma solidity 0.8.x; kullanın ve foundry.toml'daki sürüm, optimizer runs, via_ir ve evm_version değerlerinin dağıtacağınızla eşleşmesini sağlayın. Her derleyici uyarısı düzeltilmeli ya da bilinçli olarak açıklanmalıdır.
  • Bağımlılıkları sabitleyin ve listeleyin. OpenZeppelin Contracts ve diğer tüm kütüphaneleri kesin bir sürüme kilitleyin; örneğin etiketli bir v5.x submodule'ü veya package.json'da kesin bir sürüm. Tüm bağımlılıkları denetim dokümantasyonunda listeleyin ve kopyaladığınız ya da değiştirdiğiniz dosyaları işaretleyin.
  • Ölü kodu, TODO'ları ve hata ayıklama çıktısını kaldırın. Kapsamdaki sözleşmelerden kullanılmayan fonksiyonları, yorum satırına alınmış kodu, console.log import'larını ve arta kalan test yardımcılarını silin. Açık TODO'lar bitmemiş mantık sinyali verir ve öyle raporlanır.
  • External ve public fonksiyonlarda NatSpec'i tamamlayın. Her external ve public fonksiyon @notice, @param, @return ve gerektiğinde erişim kontrolü ile revert'ler hakkında bir not içermelidir. Custom error'lar kullanın ve zincir dışında önemli olan her durum değişikliği için event yayınlayın.
  • Slither çalıştırın ve her bulguyu triyajlayın. Dondurulmuş commit'te slither çalıştırın ve her bulguyu tek satırlık bir gerekçeyle düzeltildi, yanlış pozitif veya kabul edildi olarak sınıflandırın. Aderyn gibi ikinci bir araç genellikle farklı kalıplar yakalar; triyajlanmış çıktıyı paylaşmak, hangi otomatik bulguların halihazırda ele alındığını denetçilere söyler.

3. Testler#

Testler, kodun nasıl kullanılması gerektiğini denetçilere gösterir ve proof of concept'leri hızlıca yazmalarını sağlar.

  • Her external fonksiyonu kapsayın ve raporu yayınlayın. Her external ve public fonksiyon, happy path'in en az bir testine ihtiyaç duyar. forge coverage ile satır ve dal kapsama raporu üretin ve kapsanmayan dalları gizlemek yerine açıklayın.
  • Revert yollarını ve uç durumları test edin. Yetkisiz çağrıların, geçersiz parametrelerin, sıfır miktarların ve sınır değerlerin beklenen custom error ile revert ettiğini vm.expectRevert ile doğrulayın. Test edilmemiş revert yolları, doğrulama ve erişim kontrolü hatalarının saklandığı yerdir.
  • Gerçek entegrasyonlara karşı fork testleri çalıştırın. Protokol DEX'ler, borç verme piyasaları veya oracle'lar gibi harici sözleşmelerle konuşuyorsa, sabitlenmiş blok numaralarıyla bir mainnet veya L2 fork'una karşı test edin. Mock'lar yalnızca kodunuzun karşı tarafla ilgili varsayımlarınızla çalıştığını kanıtlar.

4. Fuzz ve invariant testi#

Fuzzing kimsenin düşünmediği girdi kombinasyonlarını bulur; invariant testleri ise sistemin çağrı dizileri boyunca tutarlı kaldığını kontrol eder.

  • Sayısal girdi alan her fonksiyonu fuzz edin. Miktarlar, zaman damgaları, pay hesaplamaları ve ücret matematiği için Foundry fuzz testleri yazın ve girdileri aşırı vm.assume yerine bound() ile sınırlayın. Uç değerlerde yuvarlama yönü ve taşma tipik hedeflerdir.
  • Handler'larla durumlu invariant testleri yazın. Sistemi birkaç aktörden gerçekçi dizilerde çağıran handler sözleşmeleriyle Foundry invariant testini kullanın. Her çağrı dizisinden sonra ödeme gücü, değer korunumu ve erişim kontrolü özelliklerini kontrol edin.
  • Yazılı invariant'ları ve test takımını senkron tutun. Spesifikasyonunuzdaki her invariant bir invariant testine karşılık gelmeli ve her invariant testi spesifikasyona geri izlenebilmelidir. Takımı CI'da anlamlı sayıda run ve depth ile çalıştırın; yalnızca yerel olarak varsayılanlarla değil.

5. Erişim kontrolü ve yükseltilebilirlik#

Ayrıcalıklı fonksiyonlar ve yükseltmeler sistemdeki her varlığı taşıyabilir veya kilitleyebilir; bu yüzden güven modeli açık olmalıdır.

  • Her ayrıcalıklı rolü ve fonksiyonu listeleyin. Her rolü, hangi fonksiyonları çağırabileceğini, kimin elinde olduğunu ve anahtarı ele geçirilirse en kötü senaryonun ne olduğunu belgeleyin. Bu, denetçilerin ilk isteyeceği güven varsayımları bölümüdür.
  • Yönetici gücünü bir multisig ve timelock arkasına koyun. Kritik parametreler ve yükseltmeler Safe gibi bir multisig tarafından kontrol edilmeli ve kullanıcı fonlarını etkileyen değişiklikler için bir TimelockController veya eşdeğer bir gecikme olmalıdır. İmzacı eşiğini ve gecikmeyi belgeleyin.
  • Yükseltilebilir sözleşmeler için storage layout'unu kontrol edin. Proxy'ler için ERC-7201 isim alanlı storage'a sahip OpenZeppelin v5 upgradeable sözleşmelerini kullanın ve yükseltmeleri OpenZeppelin upgrades araçlarıyla doğrulayın. Bir yükseltme kapsamdaysa sürümler arası storage layout diff'ini ekleyin.
  • Initializer'ları ve yükseltme fonksiyonlarını koruyun. Implementation constructor'ında _disableInitializers() çağırın, initializer ve reinitializer modifier'larını doğru kullanın ve UUPS proxy'lerinde (ERC-1822) _authorizeUpgrade'i kısıtlayın. Korumasız bir implementation sözleşmesi, denetçilerin asla raporlamak zorunda kalmaması gereken bir bulgudur.

6. Harici entegrasyonlar#

Her dış çağrı, başkasının kodu hakkında bir varsayımdır ve her varsayım yazılmalı ve test edilmelidir.

  • Oracle bayatlığını ve arızasını ele alın. updatedAt'i feed'in heartbeat'iyle karşılaştırın, sıfır veya negatif fiyatları reddedin ve L2'lerde sequencer uptime feed'ini kontrol edin. Oracle erişilemezken protokolün ne yaptığına karar verin ve bunu belgeleyin.
  • Token tuhaflıklarını hesaba katın. Hangi token tiplerinin desteklendiğini belirtin ve transfer ücretli, rebase, 18 ondalıklı olmayan ve standart dışı ERC-20 tokenları ele alın veya açıkça dışlayın. Transferler için SafeERC20 kullanın ve alınan miktarın önemli olduğu yerlerde bakiye farklarını ölçün.
  • Reentrancy yüzeylerini haritalayın. Her dış çağrıyı ve token transferini listeleyin, checks-effects-interactions'ı izleyin ve durum paylaşılan yerlerde ReentrancyGuard (veya EIP-1153 ile ReentrancyGuardTransient) kullanın. Fonksiyonlar arası ve salt okunur reentrancy ile ERC-721, ERC-1155 ve ERC-777 tokenlarından gelen callback'leri göz önünde bulundurun.
  • MEV ve front-running'i düşünün. Swap'lara ve yatırmalara slippage limitleri ve deadline'lar ekleyin, ERC-4626 vault'larını ilk yatırımcı enflasyon saldırısına karşı koruyun ve işlem sıralamasına bağlı her mantığı gözden geçirin. Hangi sıralama risklerini kabul ettiğinizi belgeleyin.

7. Dağıtım ve operasyonlar#

Denetlenen kod, ancak dağıtıldığı ve işletildiği şekilde güvenlidir.

  • Dağıtım script'lerini tekrar üretilebilir ve parametreleri belgelenmiş yapın. Dondurulmuş commit'ten Foundry script'leriyle dağıtın, her constructor ve initializer parametresini versiyon kontrolüne alınmış yapılandırmada tutun ve script'leri denetim kapsamına ya da en azından handoff'a dahil edin. Yanlış parametrelerle dağıtılmış doğru bir sözleşme hâlâ bozuktur.
  • Doğrulanmış kaynaklarla bir testnet'te prova yapın. Tam dağıtım script'ini bir testnet'te ve bir mainnet fork'unda çalıştırın, kaynakları blok gezgininde doğrulayın ve rollerin amaçlanan adreslere ulaştığını kontrol edin. Denetçilere testnet adreslerini verin ki gerçek bir dağıtımla etkileşebilsinler.
  • Duraklatma, runbook ve izlemeyi hazırlayın. Kimin neyi duraklatabileceğine karar verin, kısa bir olay runbook'u yazın ve rol değişiklikleri, yükseltmeler, büyük çekimler ve duraklatılmış durumlar için alarmlar kurun. Denetçiler acil durum yollarını inceleyecektir; denetimden önce var olmaları gerekir.

8. Denetim lojistiği#

İyi lojistik denetimi akıcı tutar ve düzeltme turunun gerçekten kullanılmasını sağlar.

  • Bir teknik irtibat kişisi ve bir kanal belirleyin. Kod tabanını bilen ve soruları saatler içinde yanıtlayabilecek bir geliştirici atayın ve denetim süresince ortak bir kanal üzerinde anlaşın. Yanıtlanmayan her soru incelemeyi durdurur.
  • Düzeltmeler ve bir düzeltme inceleme turu için zaman ayırın. Rapor gelir gelmez geliştirici kapasitesi planlayın ve denetçilerin düzeltmeleri gözden geçirmesi konusunda önceden anlaşın. İncelenmemiş düzeltmeler, denetim onay verdikten sonra yeni hatalar getirebilir.
  • Önceki denetimleri ve incelemeleri açıklayın. Daha önceki denetim raporlarını, düzeltme durumlarını ve iç incelemeleri paylaşın. Denetçiler böylece değişene odaklanabilir ve önceki bulguların gerilemediğini kontrol edebilir.

Size nasıl yardımcı olabiliriz#

Sabit kapsamlı, bir iki haftalık bir Audit-Readiness Sprint'i sunuyoruz: bir tehdit modeli, test takımı boşluk analizi, Foundry fuzz ve invariant testleri, Slither triyajı, önceliklendirilmiş bir düzeltme listesi ve kapsam, dokümantasyon ile bilinen sorunları içeren bir denetim handoff paketi. Biz bir denetim firması değiliz ve sprint harici bir denetimin yerini tutmaz; kodunuzu denetçilerin zamanlarını mantığa harcayabileceği şekilde hazırlar. Ayrıntılar fiyatlandırma sayfamızda ve Blockchain & Web3 hizmetlerimizde bulunur.

Kod tabanınız için ücretsiz bir tahmin isterseniz projenizden bize bahsedin. Herhangi bir kod paylaşmadan önce bir karşılıklı NDA imzalamaktan memnuniyet duyarız.

Aklınızda bir proje mi var?

Ne geliştirdiğinizi anlatın. İş günlerinde bir saat içinde kıdemli bir mühendis yanıt verir — ardından dürüst bir değerlendirme, net bir kapsam ve genellikle birkaç iş günü içinde sabit fiyatlı veya aşamalı bir teklif alırsınız.

Önce yazmayı mı tercih edersiniz? Bize yazın

Doğrudan Ing. Ismet Mesic ile konuşursunuz, Tech lead.