UniswapV4'ün duyurulmasından bu yana bu takas platformu, basit bir takas platformundan bir altyapı hizmet sağlayıcısına dönüşerek önemli bir dönüşüm geçirdi. Özellikle V4'ün Hooks özelliği geniş çapta ilgi gördü. Derinlemesine araştırmalardan sonra herkesin bu dönüşümü ve uygulanmasını daha iyi anlamasına yardımcı olacak bazı içerikler derledim.
UniswapV4'ün inovasyonunun odak noktası yalnızca AMM teknolojisini geliştirmek değil aynı zamanda ekosistemi genişletmektir. Bu yenilik özellikle aşağıdaki temel özellikleri içerir:
İlerleyen bölümlerde bu özelliklerin önemini ve uygulama ilkelerini detaylı olarak anlatacağım.
Kaynak: https://twitter.com/jermywkh/status/1670779830621851650
UniswapV4, her bir işleme karşılık gelen tokenların bakiye değişikliklerini takip etmek için Çift Girişli Defter Tutmaya benzer bir kayıt tutma yöntemini benimser. Bu Çift Girişli Defter Tutma yöntemi, her işlemin aynı anda birden fazla hesaba kaydedilmesini ve bu hesaplar arasındaki varlık dengesinin dengeli kalmasının sağlanmasını gerektirir. Örneğin, bir kullanıcının havuzdan 100 TokenA'yı 50 TokenB ile değiştirdiğini varsayalım. Defterdeki kayıt şu şekilde olacaktır:
UniswapV4'te bu kayıt tutma yöntemi öncelikle büyük işlemler için kullanılır ve lockState.currencyDelta[currency] adlı bir depolama değişkeni kullanılır. Kodda token bakiyesi değişikliklerinin miktarını kaydetmek için kullanılır. Bu deltanın değeri pozitifse havuzdaki token miktarında beklenen artışı, negatif değer ise token miktarında beklenen düşüşü temsil eder. Alternatif olarak, değer pozitifse havuzdaki token eksikliği miktarını (alınması beklenen miktar) belirtirken negatif değer, havuzdaki token fazlasını (kullanıcıların çekmesi beklenen miktar) gösterir. Aşağıdaki liste, çeşitli operasyonların Token Deltası üzerindeki etkilerini göstermektedir:
Bu işlemler arasında yalnızca "yerleştirme" ve "alma", tokenların fiili transferini içerirken, diğer işlemler yalnızca TokenDelta değerinin güncellenmesinden sorumludur.
Burada TokenDelta'nın nasıl güncelleneceğini göstermek için basit bir örnek kullanıyoruz. Bugün 100 TokenA'yı 50 TokenB ile değiştirdiğimizi varsayalım:
Tüm takas işlemi tamamlandığında hem TokenADelta hem de TokenBDelta 0'a sıfırlanır. Bu, işlemin tamamen dengelendiği anlamına gelir ve böylece hesap bakiyelerinin tutarlılığı sağlanır.
Daha önce UniswapV4'ün TokenDelta'yı kaydetmek için Depolama Değişkenlerini kullandığı belirtilmişti. Ancak sözleşme kapsamında Depolama Değişkenlerini okumak ve yazmak oldukça pahalıdır. Bu bizi Uniswap tarafından tanıtılan başka bir EIP'ye getiriyor: EIP1153 - Geçici Depolama İşlem Kodları.
UniswapV4, TokenDelta'yı güncellemek için EIP1153 tarafından sağlanan TSTORE ve TLOAD işlem kodlarını kullanmayı planlıyor. Geçici Depolama İşlem Kodlarını benimseyen Depolama Değişkenleri, işlemin bitiminden sonra atılacaktır (Bellek Değişkenlerine benzer şekilde), böylece gas ücretleri azaltılacaktır.
EIP1153'ün yaklaşan Cancun yükseltmesine dahil olacağı doğrulandı ve burada bildirildiği gibi UniswapV4 de Cancun yükseltmesinden sonra yayına gireceğini belirtti.
kaynak: https://etherworld.co/2022/12/13/transient-storage-for-beginners/
UniswapV4 bir kilit mekanizması sunar; bu, herhangi bir Havuz işlemini gerçekleştirmeden önce, bir kilit almak için önce PoolManager.lock() öğesini çağırmanız gerektiği anlamına gelir. lock()'un yürütülmesi sırasında TokenDelta değerinin 0 olup olmadığını kontrol eder, aksi halde geri döner. PoolManager.lock() başarıyla edinildiğinde msg.sender'ın lockAcquired() işlevini çağırır. lockAcquired() fonksiyonu içerisinde swap ve changePosition gibi Havuz ile ilgili işlemler gerçekleştirilir.
Süreç aşağıda gösterilmiştir. Bir kullanıcının bir Token Takas işlemi gerçekleştirmesi gerektiğinde, lockAcquired() işleviyle (Geri Arama Sözleşmesi olarak anılır) bir Akıllı Sözleşme çağırması gerekir. Geri Arama Sözleşmesi ilk olarak PoolManager.lock()'u çağırır, ve ardından PoolManager, Geri Arama Sözleşmesinin lockAcquired() işlevini çağırır. lockAcquired() fonksiyonunun içerisinde swap, swap, take gibi Pool işlemlerine ilişkin mantık tanımlanır. Son olarak, lock() sona ermek üzereyken PoolManager, bu işlemle ilişkili TokenDelta'nın 0'a sıfırlanıp sıfırlanmadığını kontrol ederek Havuzdaki varlıkların dengesinin bozulmadan kalmasını sağlar.
Singleton Sözleşmesi, UniswapV4'ün önceki Fabrika Havuzu modelini terk ettiği anlamına gelir. Her Havuz artık bağımsız bir Akıllı Sözleşme değildir ancak tüm Havuzlar tek bir tekil sözleşmeyi paylaşır. Flash Muhasebe mekanizmasıyla birleştirilen bu tasarım, yalnızca gerekli Depolama Değişkenlerinin güncellenmesini gerektirerek operasyonların karmaşıklığını ve maliyetini daha da azaltır.
Aşağıdaki örnekte, UniswapV3 örnek olarak kullanıldığında, ETH'nin DAI ile değiştirilmesi en az dört Token aktarımı (Depolama yazma işlemleri) gerektirir. Buna USDC, USDT ve DAI Tokenları için kaydedilen birden fazla değişiklik dahildir. Ancak UniswapV4'teki iyileştirmeler ve Flash Muhasebe mekanizmasıyla birlikte yalnızca bir Token aktarımına ihtiyaç duyulur (DAI'nin Havuzdan kullanıcıya taşınması), işlem sayısı ve maliyetler önemli ölçüde azalır.
Kaynak: https://twitter.com/Uniswap/status/1671208668304486404
UniswapV4'ün son güncellemesinde en dikkat çeken özellik Hooks Mimarisidir. Bu güncelleme Havuzun kullanılabilirliği açısından büyük esneklik sağlar. Kancalar, Havuzda belirli işlemler gerçekleştirilirken Kanca Sözleşmesi aracılığıyla tetiklenen ek eylemlerdir. Bu eylemler, başlatma (havuz oluşturma), değişiklik yapma (likidite ekleme/kaldırma), takas etme ve bağışlama olarak kategorize edilir. Her kategorinin yürütme öncesi ve yürütme sonrası eylemleri vardır.
Bu tasarım, kullanıcıların belirli işlemlerden önce ve sonra özel mantığı yürütmesine olanak tanıyarak onu daha esnek hale getirir ve UniswapV4'ün işlevselliğini genişletir.
kaynak: https://github.com/Uniswap/v4-core/blob/main/whitepaper-v4-draft.pdf
Daha sonra, UniswapV4'teki Hook'ların gerçek çalışma sürecini açıklamak için bir Limit Emri örneği kullanacağız. Başlamadan önce UniswapV4'te Limit Emirleri uygulama prensibini kısaca açıklayalım.
Limit emrinin UniswapV4 uygulaması, belirli bir fiyat aralığına likidite ekleyerek ve ardından o aralıktaki likidite takas edilirse likiditeyi kaldırma işlemini gerçekleştirerek çalışır.
Örnek olarak ETH için 1900-2000 fiyat aralığında likidite eklediğimizi ve ardından ETH'nin fiyatının 1800'den 2100'e çıktığını varsayalım. Bu noktada daha önce 1900-2000 fiyat aralığında eklediğimiz tüm ETH likiditesinin (ETH-USDC havuzunda olduğu varsayılarak) USDC ile takas edilmiş olması. Şu anda likiditeyi ortadan kaldırarak, 1900-2000 mevcut fiyat aralığında ETH piyasa emrini gerçekleştirmeye benzer bir etki elde edebiliriz.
Bu örnek UniswapV4'ün GitHub'undan alınmıştır. Bu örnekte, Limit Order Hook sözleşmesi afterInitialize ve afterSwap olmak üzere iki kanca sağlar. AfterInitialize kancası, birisi takas yaptıktan sonra hangi limit emirlerinin eşleştiğini belirlemek amacıyla bir havuz oluştururken fiyat aralığını (tik) kaydetmek için kullanılır.
Kullanıcının emir vermesi gerektiğinde Hook sözleşmesi, kullanıcının belirlediği fiyat aralığı ve miktarına göre likidite ekleme işlemini gerçekleştirir. Limit emirleri için Hook sözleşmesinde place() fonksiyonunu görebilirsiniz. Ana mantık, kilidi aldıktan sonra limit emri vermeye eşdeğer olan likidite ekleme işlemini gerçekleştirmek için lockAcquiredPlace() fonksiyonunu çağırmaktır.
kaynak: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L246
Kullanıcı bu Havuz içerisinde bir Swap Token tamamladıktan sonra Havuz, Hook sözleşmesinin afterSwap() fonksiyonunu çağıracaktır. AfterSwap'in ana mantığı, önceki fiyat aralığı ile mevcut fiyat aralığı arasında gerçekleştirilen önceden verilmiş emirlerin likiditesini ortadan kaldırmaktır. Bu davranış, doldurulan siparişe eşdeğerdir.
kaynak: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L192
Burada bir limit emrinin gerçekleştirilme sürecini gösteren bir akış şeması bulunmaktadır:
Yukarıdakiler Kanca mekanizmasını kullanarak Limit-Emir uygulama sürecinin tamamıdır.
Kancaların paylaşmaya değer bulduğum birkaç ilginç noktası var.
Öncesi/sonrası belirli işlemleri gerçekleştirme kararı, Hook sözleşme adresinin en soldaki 1 baytı tarafından belirlenir. 1 bayt 8 bit'e eşittir, bu da 8 ek eyleme karşılık gelir. Havuz, Kanca sözleşmesinin karşılık gelen kanca fonksiyonunun çağrılıp çağrılmayacağına karar vermek için bu eylemin bitinin 1 olup olmadığını kontrol edecektir. Bu aynı zamanda Hook sözleşmesinin adresinin belirli bir şekilde tasarlanması gerektiği ve Hook sözleşmesi olarak keyfi olarak seçilemeyeceği anlamına da gelir. Bu tasarım temel olarak gaz tüketimini azaltmayı ve daha verimli operasyonlar elde etmek için maliyeti sözleşmeli dağıtıma kaydırmayı amaçlamaktadır. (Not: Uygulamada, koşulları karşılayan sözleşme adreslerini kaba kuvvetle hesaplamak için farklı CREATE2 tuzları kullanılabilir)
Hooks, her eylemin öncesinde ve sonrasında ek işlemler gerçekleştirebilmenin yanı sıra dinamik ücretlerin uygulanmasına da destek vermektedir. Havuz oluştururken dinamik ücretlerin etkinleştirilip etkinleştirilmeyeceğini belirtebilirsiniz. Dinamik ücretler etkinleştirilirse, tokenlar değiştirilirken Hook sözleşmesinin getFee() işlevi çağrılır. Hook sözleşmesi, Havuzun mevcut durumuna göre alınacak ücret miktarını belirleyebilir. Bu tasarım, fiili koşullara göre esnek ücret hesaplamasına olanak tanıyarak sistemin esnekliğini artırır.
Her Havuzun Kanca sözleşmesini oluşturma sırasında belirlemesi gerekir ve daha sonra değiştirilemez (ancak farklı Havuzlar aynı Kanca sözleşmesini paylaşabilir). Bunun temel nedeni Kancaların PoolKey'in bir parçası olarak kabul edilmesi ve PoolManager'ın hangi Havuzun üzerinde çalışacağını belirlemek için PoolKey'i kullanmasıdır. Varlıklar aynı olsa dahi Hook sözleşmesi farklı ise farklı bir Havuz olarak değerlendirilecektir. Bu tasarım, farklı Havuzların durum ve operasyonlarının bağımsız olarak yönetilebilmesini sağlayarak Havuzların tutarlılığını sağlar. Ancak Havuz sayısı arttıkça yönlendirmenin karmaşıklığı da artar (belki de UniswapX bu sorunu çözmek için tasarlanmıştır).
UniswapV4, Uniswap ekosisteminin tamamını genişletmeyi, Uniswap Havuzlarının temeli üzerine daha fazla hizmetin oluşturulmasını sağlayacak altyapıya dönüştürmeyi açıkça vurguluyor. Bu, Uniswap'in rekabet gücünü artırmaya yardımcı olur ve alternatif hizmetlerin riskini azaltır. Ancak beklenen başarıya ulaşıp ulaşamayacağı henüz bilinmiyor. Öne çıkan bazı özellikler arasında Flash Accounting ve EIP1153 kombinasyonu yer alıyor ve gelecekte daha fazla hizmetin bu özellikleri benimseyeceğine ve bunun da çeşitli uygulama senaryolarına yol açacağına inanıyoruz. Bu UniswapV4'ün temel konseptidir ve UniswapV4'ün nasıl çalıştığına dair daha derin bir anlayış sağlayacağını umuyoruz. Yazıda hatalar varsa lütfen belirtmekten çekinmeyin. Ayrıca tartışmaları ve geri bildirimleri de memnuniyetle karşılıyoruz.
Son olarak makaleyi inceleyip değerli geri bildirimde bulundukları için Anton Cheng ve Ping Chen'e teşekkür ederiz!