7 dk okuma
Solidity upgradeable smart contract mimarisi, zincire bir kez dağıtılan akıllı sözleşmenin iş mantığını daha sonra değiştirebilmenizi sağlar. Bu esneklik; hata düzeltme, yeni özellik ekleme ve protokolün değişen ihtiyaçlara uyum sağlaması açısından güçlüdür. Fakat aynı mekanizma yanlış tasarlandığında initializer ele geçirilmesi, storage layout bozulması veya yetkisiz upgrade gibi kritik riskler doğurabilir. Proxy tabanlı upgrade yaklaşımında kullanıcılar sabit bir proxy adresiyle etkileşir; proxy state’i tutar ve çağrıları delegatecall ile implementation kontratına yönlendirir. Yeni sürüm geldiğinde proxy’nin sakladığı implementation adresi değiştirilir, böylece kullanıcı adresi ve zincir üzerindeki state korunur.
OpenZeppelin’in güncel dokümantasyonu UUPS, Transparent ve Beacon proxy desenlerini destekler. ERC-1967 ise proxy’nin implementation, admin ve beacon bilgileri için standart storage slotları tanımlar. Bu rehberde production seviyesinde güvenli bir upgrade akışını yedi adımda ele alıyoruz.
Proxy mimarisi, initializer kullanımı, upgrade authorization ve storage layout güvenliğini çalışan Solidity örneğinde inceleyebilirsiniz.
GitHub Projesini İncele →İçindekiler
- Proxy tabanlı upgrade mantığı nedir?
- UUPS ve Transparent proxy arasındaki fark
- ERC-1967 storage slotları neden önemlidir?
- Constructor yerine initializer nasıl kullanılır?
- Storage layout nasıl korunur?
- Upgrade yetkisi nasıl güvence altına alınır?
- Validate, test ve rollback planı nasıl kurulmalı?
- Sonuç ve üretim kontrol listesi
Solidity Upgradeable Smart Contract Nedir?
Upgradeable kontrat yapısında state ile iş mantığı ayrılır. Proxy kontratı kullanıcının çağrılarını alır, kendi storage alanını korur ve çağrıyı implementation kontratına delegatecall ile aktarır. Delegatecall nedeniyle kod implementation’dan çalışsa da storage proxy’ye aittir. Bu ayrım upgrade’in temel avantajını sağlar: implementation adresi değişebilirken kullanıcı bakiyesi, sahiplik bilgisi veya protokol state’i proxy üzerinde kalır.
1. Proxy Desenini Başta Doğru Seçin
OpenZeppelin Upgrades Plugins; UUPS, Transparent ve Beacon proxy desenlerini destekler. UUPS ve Transparent proxy’ler tek tek upgrade edilir; Beacon deseninde ise aynı beacon’a bağlı çok sayıda proxy tek bir beacon upgrade’iyle birlikte güncellenebilir. UUPS yaklaşımında upgrade mantığı implementation kontratında yer alır ve _authorizeUpgrade fonksiyonu üzerinden erişim kontrolü uygulanır. Transparent proxy’de upgrade yönetimi proxy admin modeliyle ayrılır. Daha küçük proxy ve daha düşük deployment maliyeti isteyen sistemlerde UUPS yaygın bir seçimdir; ancak upgrade yetkisinin implementation içinde doğru korunması zorunludur.
2. ERC-1967 Slotlarını Standart Şekilde Kullanın
Proxy ve implementation aynı storage alanını paylaştığı için implementation adresini sıradan bir state variable slotunda tutmak çakışma riski yaratır. ERC-1967; implementation, beacon ve admin adresleri için compiler’ın normal değişken yerleşimiyle çakışmayacak standart slotlar tanımlar. Bu standart aynı zamanda block explorer ve tooling’in bir kontratın proxy olduğunu anlamasını kolaylaştırır. OpenZeppelin ERC1967Proxy bu standardı temel alır.
3. Constructor Yerine Initializer Kullanın ve Implementation’ı Kilitleyin
Proxy arkasında çalışan implementation kontratının constructor’ı proxy storage’ını başlatmaz. Bu nedenle constructor mantığı initialize gibi normal bir fonksiyona taşınmalıdır ve initializer modifier ile yalnızca bir kez çalışması sağlanmalıdır. Daha da önemlisi, implementation kontratını başıboş bırakmayın. OpenZeppelin _disableInitializers() çağrısını implementation constructor’ında kullanarak implementation adresinin doğrudan initialize edilmesini engellemeyi önerir. Aksi halde bir saldırgan implementation kontratını sahiplenebilir ve bazı tasarımlarda proxy güvenliğini etkileyebilir.
4. Storage Layout Değişikliklerini En Kritik Upgrade Kuralı Olarak Görün
Upgradeable kontratlarda mevcut state variable’ların sırası ve tipi keyfi biçimde değiştirilemez. Örneğin uint256 x ardından string y bulunan bir sürümde yeni bir değişkeni x’in önüne eklemek, x’in tipini değiştirmek veya x ile y’nin sırasını ters çevirmek eski storage verilerinin yeni kod tarafından yanlış okunmasına neden olabilir. Güvenli yaklaşım yeni değişkenleri mevcut layout’un sonuna eklemektir. OpenZeppelin Upgrades araçları validateUpgrade ve upgradeProxy sırasında storage compatibility kontrolleri yapabilir. OpenZeppelin Contracts 5.x upgradeable paketinde ERC-7201 namespaced storage layout yaklaşımı da kullanılır.
5. Upgrade Yetkisini Tek Bir EOA’ya Bağlamayın
Bir upgrade anahtarı protokolün en güçlü yetkilerinden biridir. Tek bir kişisel cüzdanın ele geçirilmesi tüm implementation kodunun kötü niyetli sürümle değiştirilmesine yol açabilir. UUPS kullanıyorsanız _authorizeUpgrade fonksiyonunu güçlü bir role bağlayın. Üretim sistemlerinde multisig, timelock veya yönetişim mekanizmasıyla upgrade yetkisini dağıtmak daha güvenlidir. Transparent proxy kullanıyorsanız ProxyAdmin ownership’i aynı şekilde güvence altına alın. Upgrade işlemlerinin zincir üstü event’leri ve operasyon logları düzenli olarak izlenmelidir.
6. Upgrade Sürümünde Initialization İhtiyacını Planlayın
Yeni sürüm yalnızca fonksiyon ekliyorsa ek initialization gerekmeyebilir; fakat yeni modül state başlatmak istiyorsa reinitializer mekanizması gerekebilir. Initializable sürüm numarası yaklaşımı her initialization adımının yalnızca bir kez çalışmasını sağlar. Parent initializer’ların doğru sırayla ve yalnızca gerekli kez çağrıldığından emin olun. Upgrade transaction’ı ile initialization çağrısını mümkün olduğunca atomik hale getirmek, kontratın kısa süreli de olsa yarı başlatılmış durumda kalmasını önler.
7. Upgrade’i Zincire Göndermeden Önce Doğrulayın
Upgrade işlemi üretimde doğrudan denenmemelidir. Önce storage compatibility doğrulaması çalıştırın, unit ve integration testlerini geçirin, fork veya testnet ortamında mevcut proxy state’iyle yeni implementation’ı çalıştırın. Özellikle access control, pausable mekanizmalar, token accounting ve kritik state invariants için regression testleri hazırlayın. OpenZeppelin Upgrades Plugins prepareUpgrade/validateUpgrade gibi araçlarla yeni implementation’ın upgrade-safe olup olmadığını kontrol etmeye yardımcı olur. Ayrıca başarısız bir upgrade sonrası geri dönüş için önceki implementation adresini ve rollback operasyonunu önceden planlayın.
Üretim Kontrol Listesi
- Proxy deseni (UUPS / Transparent / Beacon) iş ihtiyacına göre seçildi.
- Implementation constructor’ında _disableInitializers() ile kontrat kilitlendi.
- Initializer ve reinitializer akışları test edildi.
- Storage layout değişiklikleri validateUpgrade ile doğrulandı.
- Upgrade yetkisi multisig/timelock veya güçlü rol yönetimine bağlandı.
- Testnet/fork üzerinde gerçek state ile upgrade provası yapıldı.
- Önceki implementation ve rollback planı operasyon ekibinde kayıtlı.
Sonuç
Solidity upgradeable smart contract mimarisi, akıllı sözleşmelere uzun ömür ve değişime uyum kazandırır; ancak klasik kontrat geliştirmeye göre ek operasyon ve güvenlik disiplini ister. Proxy standardı, initializer güvenliği, storage layout uyumluluğu ve upgrade yetkilendirmesi ayrı ayrı doğru kurulmalıdır. En güvenli yaklaşım, upgrade’i normal deployment’tan daha kritik bir değişiklik yönetimi süreci olarak ele almak; kod doğrulamasını, yetki ayrımını, testnet provası ve rollback planını birlikte işletmektir. Bu disiplin sağlandığında proxy tabanlı mimari, zincir üstü state’i koruyarak protokolün kontrollü biçimde evrilmesini sağlar.
Güvenilir Araştırma Kaynakları
OpenZeppelin Contracts 5.x – Proxy API
OpenZeppelin – Writing Upgradeable Contracts

