8 dk okuma
UUPS Proxy, akıllı sözleşmelerde kodu yükseltebilir tutarken kullanıcı verisini ve proxy adresini korumayı amaçlayan hafif bir proxy desenidir. UUPS yaklaşımında proxy yalnızca çağrıları implementation sözleşmesine delegatecall ile yönlendirir; yükseltme mekanizmasının önemli kısmı implementation içinde yaşar. Bu mimari dağıtım maliyetini azaltabilir ve Transparent Proxy desenine göre daha yalın bir proxy sunabilir, ancak yanlış upgrade yetkisi, hatalı initializer veya storage layout değişikliği sözleşmeyi geri döndürülemez biçimde bozabilir.
Bu rehberde UUPS Proxy yapısını ERC-1822 ve ERC-1967 temellerinden başlayarak, OpenZeppelin UUPSUpgradeable yaklaşımı, initializer kullanımı, storage layout güvenliği, _authorizeUpgrade, upgrade testleri ve üretim izleme adımlarıyla ele alıyoruz. Amaç yalnızca yükseltilebilir bir sözleşme deploy etmek değil; hangi sürümün aktif olduğunu, kimin upgrade yapabildiğini ve bir yükseltmenin mevcut state’i bozup bozmadığını kontrollü biçimde yönetebilen bir sistem kurmaktır.
İçindekiler
- UUPS Proxy nedir?
- ERC-1967 depolama slotlarını anlayın
- Constructor yerine initializer kullanın
- Storage layout değişikliklerini güvenli yönetin
- _authorizeUpgrade ile yükseltme yetkisini sınırlandırın
- Upgrade öncesi otomatik uyumluluk testleri uygulayın
- Upgrade olaylarını izleyin ve yönetişim planı kurun
- Sonuç ve üretim kontrol listesi
UUPS Proxy Nedir?
UUPS (Universal Upgradeable Proxy Standard), ERC-1822 ile tanımlanan ve upgrade mantığını proxy yerine implementation sözleşmesine taşıyan yükseltilebilir proxy yaklaşımıdır. OpenZeppelin’in güncel proxy dokümantasyonu UUPS proxy’lerin ERC1967Proxy ile kullanıldığını ve implementation sözleşmesinin UUPSUpgradeable işlevlerini içermesi gerektiğini belirtir. Transparent proxy’de admin ve upgrade mantığı proxy tarafında bulunurken UUPS’ta upgrade fonksiyonları implementation tarafındadır. Bu nedenle proxy daha hafif olabilir; ancak implementation’ın upgrade özelliğini yanlışlıkla kaldırması veya yetkilendirmeyi hatalı yapması daha kritik sonuçlar doğurur.
1. ERC-1967 Depolama Slotlarını Anlayın
Proxy ile implementation aynı storage bağlamını paylaşır. ERC-1967, implementation adresi, beacon ve isteğe bağlı admin gibi proxy bilgileri için compiler’ın normal state değişkenleriyle çakışmayacağı özel depolama slotları tanımlar. Implementation adresi, proxy’nin hangi logic sözleşmesine delegatecall yapacağını belirleyen standart bir slota yazılır. Bu standardizasyon block explorer’ların proxy’yi tanımasını kolaylaştırır ve storage collision riskini azaltır. Yine de ERC-1967 yalnızca proxy’ye ait kritik slotları korur; kendi uygulama state’inizin sürümler arasında uyumunu sizin korumanız gerekir.
2. Constructor Yerine Initializer Kullanın
Upgradeable sözleşmelerde constructor implementation kontratının kendi storage’ını başlatır; proxy storage’ını başlatmaz. Bu nedenle OpenZeppelin upgradeable bileşenleri initializer desenini kullanır. initialize fonksiyonu proxy üzerinden delegatecall bağlamında çalıştırılır ve yalnızca bir kez çağrılacak şekilde korunmalıdır. Sahipsiz veya başlatılmamış proxy’ler ciddi güvenlik riski oluşturabilir. İlk deployment sırasında initialization verisini proxy constructor’ına encode ederek göndermek, proxy’nin oluşturulduğu işlemde state’i başlatmaya yardımcı olur. Ayrıca implementation sözleşmesinin kendisinin yanlışlıkla initialize edilmesini engellemek için uygun initializer kilitleme yaklaşımı kullanılmalıdır.
3. Storage Layout’ı Bir API Sözleşmesi Gibi Koruyun
UUPS upgrade sırasında proxy’nin storage’ı değişmez; yalnızca delegatecall yapılan implementation adresi değişir. Bu yüzden yeni sürümde mevcut state değişkenlerinin sırasını değiştirmek, türünü değiştirmek veya inheritance sırasını dikkatsizce değiştirmek eski verilerin yanlış slotlardan okunmasına yol açabilir. Yeni alanlar genellikle mevcut layout’ın sonuna eklenmeli, silinen alanların slotları yeniden kullanılmamalıdır. Upgradeable kütüphanelerde storage gap veya namespaced storage gibi desenlerin amacı da sürümler arasında layout güvenliğini korumaktır. OpenZeppelin Upgrades Plugins yeni implementation’ın önceki sürümle storage açısından uyumlu olup olmadığını doğrulayan kontroller sağlar; üretim upgrade’inden önce bu doğrulamaları otomatik pipeline’ın parçası yapmak gerekir.

4. _authorizeUpgrade Fonksiyonunu Gerçek Bir Güvenlik Sınırı Yapın
OpenZeppelin UUPSUpgradeable, upgradeToAndCall gibi yükseltme akışlarını sunar ancak kimin upgrade yapabileceğine sizin karar vermenizi bekler. _authorizeUpgrade fonksiyonunun erişim kontrolüyle override edilmesi zorunludur. Basit projelerde onlyOwner yeterli olabilir; yüksek değerli protokollerde multisig, timelock veya rol tabanlı yönetişim tercih edilebilir. Tek bir geliştirici cüzdanının anında upgrade yetkisine sahip olması operasyonel açıdan büyük risk taşır. Yetki modelini sözleşme kodundan bağımsız düşünmeyin: admin anahtarının kaybı, ele geçirilmesi veya yanlış role atanması doğrudan implementation kodunu değiştirme yetkisi anlamına gelebilir.
5. UUPS Uyum Kontrolünü Devre Dışı Bırakmayın
UUPS deseninin en kritik risklerinden biri, proxy’nin upgrade yeteneğini yanlış bir implementation’a geçerek kalıcı biçimde kaybetmesidir. OpenZeppelin’in UUPSUpgradeable uygulaması yeni implementation’ın beklenen ERC-1822 proxiableUUID davranışını sağlayıp sağlamadığını kontrol eden güvenlik mekanizması içerir. Bu kontrol, proxy’nin upgrade fonksiyonlarını içermeyen uyumsuz bir implementation’a geçirilmesini önlemeye yardımcı olur. Ancak custom upgrade mekanizması yazarken veya koruma katmanlarını kaldırırken bu güvence yeniden sizin sorumluluğunuza geçer. Proxy standardının düşük seviyeli detaylarına gerçekten ihtiyaç yoksa OpenZeppelin Upgrades Plugins gibi doğrulama araçlarını tercih etmek daha güvenli bir başlangıç noktasıdır.
6. Upgrade’i Deploy Etmeden Önce Davranış ve Storage Testi Yapın
Başarılı compile, güvenli upgrade anlamına gelmez. Test ortamında V1 proxy’yi gerçekçi state ile doldurun, ardından V2 implementation’a yükseltin ve tüm kritik state değerlerinin değişmeden kaldığını doğrulayın. Eski fonksiyonların davranışını, yeni fonksiyonların erişim kontrolünü, initializer/reinitializer akışlarını ve upgrade yetkisini ayrı ayrı test edin. Mümkünse fork testleriyle üretim state’ine yakın koşullar kullanın. OpenZeppelin Upgrades Plugins, yeni implementation’ın upgrade-safe ve storage-compatible olup olmadığını doğrulayan kontroller sunar; bu kontroller CI içinde zorunlu hale getirilebilir.
7. Upgrade Olaylarını İzleyin ve Geri Dönüş Planı Tasarlayın
ERC-1967, implementation slotundaki değişikliklerin Upgraded olayıyla bildirilmesini önerir. Bu event’i izlemek, aktif implementation adresinin beklenmedik biçimde değişmesini tespit etmek için önemlidir. Üretimde monitoring sistemi proxy adresleri için Upgraded event’lerini takip etmeli; yetkisiz veya plan dışı bir değişiklikte alarm üretmelidir. Upgrade öncesinde yeni implementation adresi, bytecode hash’i, audit/test sonucu ve yönetişim onayı kayıt altına alınmalıdır. Rollback her zaman güvenli değildir: V2 yeni state yazdıysa V1 koduna dönmek storage semantiğini bozabilir. Bu nedenle ‘geri dönmek’ yerine ileri düzeltme (forward fix) senaryosunu da planlayın.
Üretim Kontrol Listesi
- Proxy ERC-1967 uyumlu ve implementation adresi standart slotta tutuluyor.
- Initializer tek kullanımlık ve deployment sırasında güvenli biçimde çağrılıyor.
- Yeni sürüm storage layout’ı önceki sürümle uyumlu.
- _authorizeUpgrade yalnızca güvenilir rol/multisig/timelock tarafından geçilebiliyor.
- UUPS uyumluluk kontrolü ve proxiableUUID güvenliği korunuyor.
- Upgrade öncesi storage ve davranış testleri otomatik çalışıyor.
- Upgraded event’leri izleniyor ve yönetişim/incident planı mevcut.
Sonuç
UUPS Proxy, yükseltilebilir akıllı sözleşmeler için güçlü ve maliyet açısından verimli bir mimari sunar; ancak bu esneklik doğrudan operasyonel sorumluluk getirir. ERC-1967 slotları proxy bilgisini standartlaştırırken initializer, storage layout, upgrade yetkilendirmesi ve UUPS uyumluluk kontrolleri uygulama güvenliğinin temelini oluşturur. En güvenli yaklaşım; upgrade’i normal bir kod deploy’u değil, state taşıyan kritik bir protokol değişikliği olarak ele almaktır. Otomatik storage doğrulaması, gerçekçi upgrade testleri, multisig/timelock yetkisi ve event izleme birlikte kullanıldığında UUPS mimarisi yönetilebilir ve denetlenebilir hale gelir.
Güvenilir Araştırma Kaynakları
OpenZeppelin Contracts 5.x – Proxy
