Neler yeni
Türkiye’nin Lider Kripto Para Forumu

Blockchain dünyasının Türkçe Wikipedia'sına hoş geldiniz!

Hemen ücretsiz üye olun ve kayıt olduğunuz anda coin kazanmaya başlayın. Kendi konularınızı paylaşın, diğer üyelerle etkileşim kurun ve dilediğiniz zaman coinlerinizi çekin.

Katılmak için şimdi harekete geçin!

Bölüm 1: Giriş ve Solidity’ye Genel Bakış

Solidity Nedir?

Giriş

Solidity, Ethereum blockchain'i üzerinde akıllı sözleşmeler geliştirmek için kullanılan yüksek seviyeli bir programlama dilidir. Ethereum’un vizyonu, merkeziyetsiz, güvenli ve şeffaf bir şekilde çalışan uygulamalar yaratmaktır. Bu uygulamaların temel yapı taşları ise akıllı sözleşmelerdir. Akıllı sözleşmeler, belirli bir koşul yerine getirildiğinde otomatik olarak tetiklenen kod bloklarıdır. Solidity, bu sözleşmeleri yazmak için en yaygın kullanılan dildir ve Ethereum blockchain'inde merkeziyetsiz uygulamaların (DApp'ler) temelini oluşturur.

Solidity, Ethereum ağı üzerinde yalnızca merkeziyetsiz finans (DeFi) uygulamaları değil, aynı zamanda dijital koleksiyonlar, oyunlar, ticaret platformları ve daha pek çok blockchain tabanlı çözümü destekleyen güçlü bir araçtır. Geliştiriciler, Solidity kullanarak Ethereum üzerinde değiştirilemez ve güvenli akıllı sözleşmeler oluşturabilirler.

Solidity’nin Tanımı (Devam)

Solidity, Ethereum blockchain'inde akıllı sözleşmeler yazmaya yönelik bir programlama dilidir. Ethereum, dünya çapında merkeziyetsiz uygulamalar (DApp'ler) geliştirmek için kullanılan en popüler blockchain platformlarından biridir ve Solidity bu platformda sözleşmeler yazmak için en yaygın kullanılan dildir. Ethereum blockchain'i, yalnızca bir dijital para birimi olan Ether (ETH) ile işlem yapmanın ötesine geçerek, blockchain üzerinde koşullara dayalı otomatik işlem gerçekleştiren akıllı sözleşmelerin oluşturulmasına olanak tanır. Akıllı sözleşmeler, bir kullanıcı belirli bir işlem gerçekleştirdiğinde, söz konusu koşullar sağlandığında otomatik olarak devreye giren kod parçacıklarıdır.

Solidity'nin temel amacı, blockchain üzerinde akıllı sözleşmeler geliştirmek ve bu sözleşmeleri güvenli bir şekilde dağıtmaktır. Solidity dilinin, Ethereum Virtual Machine (EVM) üzerinde çalışan akıllı sözleşmeleri yazabilme yeteneği, onu blockchain geliştirmede vazgeçilmez bir araç haline getirmiştir. EVM, Ethereum ağı üzerinde dağıtılan ve çalıştırılan akıllı sözleşmeleri yöneten sanal makinedir. Solidity, EVM ile doğrudan etkileşimde bulunarak, geliştiricilere Ethereum ağı üzerinde merkeziyetsiz uygulamaların temel yapı taşlarını oluşturma fırsatı sunar.

Solidity'nin güçlü özellikleri ve kullanımı, yalnızca finansal uygulamalarla sınırlı değildir. Merkeziyetsiz finans (DeFi), oyunlar, dijital koleksiyonlar, kimlik doğrulama, tedarik zinciri yönetimi ve daha pek çok sektörde uygulanabilen akıllı sözleşmeler için güçlü bir dil olarak popülerliğini artırmıştır. Geliştiriciler, Solidity'yi kullanarak blockchain üzerinde kurallara dayalı uygulamaları hayata geçirebilir ve bu uygulamaların güvenli, değiştirilemez ve şeffaf bir şekilde çalışmasını sağlayabilir.

Solidity, aslında bir çeşit kontrat dili olarak da görülebilir. Çünkü akıllı sözleşmeler, esasen bir tür dijital kontrat işlevi görür. Bu sözleşmeler, iki taraf arasında belirli bir şartın sağlanması durumunda belirli işlemlerin gerçekleşmesini garanti eder. Örneğin, bir DeFi platformunda borç verme işlemi yapıldığında, Solidity dilinde yazılmış bir akıllı sözleşme, borç verenin ve borç alanın sağladığı koşullara göre işlemin tamamlanıp tamamlanmayacağını denetler.

Solidity'nin güçlü yönlerinden biri, Ethereum blockchain'inin sunduğu olanaklarla entegre olarak çalışabilmesidir. Ethereum, akıllı sözleşmelerin dağıtımı ve işlemleri için gereken hesaplama kaynaklarını sağlar ve Solidity dilindeki kodlar, bu kaynaklar üzerinde işlem gerçekleştirmek için optimize edilir. Böylece geliştiriciler, Ethereum blockchain’i üzerinde güvenli, izlenebilir ve merkeziyetsiz uygulamalar inşa edebilir.

Solidity’nin Tasarım ve Özellikleri

Solidity, JavaScript, Python ve C++ gibi popüler programlama dillerinden izler taşır. Bu, özellikle yazılımcıların Solidity'yi öğrenmesini ve kullanmasını kolaylaştırır. Solidity'nin tasarımında, özellikle güvenlik, verimlilik ve kullanıcı dostu olma gibi faktörler ön planda tutulmuştur.

1. Sözde Yüksek Seviye Dil Yapısı
Solidity, geleneksel yüksek seviyeli dillerin sunduğu soyutlamaları kullanır. Bu özellik, geliştiricilerin karmaşık blockchain uygulamaları oluştururken, daha kısa ve anlaşılabilir kodlar yazmalarına yardımcı olur. Solidity, geliştiricilerin blockchain üzerinde daha etkili ve verimli bir şekilde işlem yapmalarını sağlayacak araçlar sunar. Akıllı sözleşmeler, Solidity dilinde tanımlanan fonksiyonlarla merkeziyetsiz ağ üzerinde etkin bir şekilde çalışır. Ayrıca, Solidity, Ethereum ağındaki akıllı sözleşmeleri derleyip çalıştırabilen Ethereum Virtual Machine (EVM) ile uyumlu bir dil olarak tasarlanmıştır.


2. Güvenlik ve Hata Yönetimi
Blockchain üzerinde çalışan akıllı sözleşmelerin güvenliği, Solidity'nin en kritik özelliklerinden biridir. Akıllı sözleşmelerin yazılması ve dağıtılması sürecinde, potansiyel güvenlik açıklarını önceden tespit etmek ve düzeltmek büyük önem taşır. Solidity, yazılımcılara hata yönetimi, güvenlik denetimleri ve denetim araçları konusunda kapsamlı destek sunar. Solidity'nin tasarımında, kod güvenliği ve hatalı işlem yapma olasılıklarını minimize etmek adına çeşitli güvenlik mekanizmaları bulunmaktadır. Örneğin, "reentrancy" (yeniden çağırma) gibi saldırılara karşı güvenlik önlemleri almak, Solidity geliştiricilerinin öncelikli görevlerinden biridir. Bu tür önlemler, akıllı sözleşmelerin blockchain üzerinde güvenli bir şekilde çalışmasını sağlar.


3. Veri Yapıları ve Değişkenler
Solidity, Ethereum blockchain’inin ihtiyaçlarına göre özel veri yapıları ve değişkenler sunar. Solidity'deki veri türleri, özellikle blockchain üzerinde çalışan sözleşmelerin verimli bir şekilde işlem yapabilmesini sağlamak için tasarlanmıştır. Bu dilde, int (tam sayı), bool (mantıksal değer), address (adres), string (metin), byte (bayt dizisi) gibi temel veri türlerinin yanı sıra, kullanıcı tanımlı veri yapılarına da (structs) yer verilmektedir. Solidity, Ethereum blockchain'inde depolama alanı kullanımı konusunda da oldukça verimlidir. Akıllı sözleşmelerdeki veri işlemleri, genellikle yüksek maliyetlere ve zaman alıcı işlemlere yol açar, bu yüzden verimli veri yapıları kullanmak büyük önem taşır.


4. EVM (Ethereum Virtual Machine) ile Uyum
Solidity'nin Ethereum Virtual Machine (EVM) ile uyumlu olması, onu Ethereum platformu üzerinde kullanılabilir kılar. EVM, Ethereum blockchain’inde dağıtılan her akıllı sözleşmeyi çalıştıran ve kontrol eden sanal bir makinedir. EVM, Solidity tarafından yazılan akıllı sözleşmeleri çalıştırarak işlemlerin Ethereum ağı üzerinde gerçekleşmesini sağlar. Bu, Ethereum ağındaki tüm işlemleri koordine eden merkeziyetsiz bir işlem birimidir. Solidity ile yazılmış akıllı sözleşmeler, EVM üzerinde işleme alınır ve EVM, sözleşmeleri blockchain üzerinde kaydeder. Bu da sözleşmelerin geri dönüşü olmayan şekilde güvenli ve şeffaf bir biçimde çalışmasını sağlar.


5. Veri Depolama ve Blockchain İlişkisi
Solidity ile yazılan akıllı sözleşmeler, Ethereum blockchain'inde veri saklamak için kullanılır. Ancak, blockchain üzerinde veri depolamak pahalı bir işlem olabilir. Ethereum ağındaki işlem maliyetleri (gas fees) nedeniyle, geliştiricilerin verimli veri depolama stratejileri kullanması önemlidir. Solidity, akıllı sözleşme geliştiren kişilere, verileri ne zaman depolayacaklarını ve nasıl sorgulayacaklarını belirleme özgürlüğü verir. Blockchain’de veri depolamak, yalnızca değiştirilemez ve güvenli bilgilerin saklanmasını değil, aynı zamanda merkeziyetsiz uygulamalarda şeffaflık ve denetim sağlamak için kritik öneme sahiptir.
Solidity'nin Tarihçesi

Giriş

Solidity, Ethereum platformunun temel bileşenlerinden biri olarak, blockchain teknolojisinin evrimiyle birlikte gelişen önemli bir programlama dilidir. Ethereum'un ortaya çıkışı, merkeziyetsiz uygulamalar (DApp’ler) ve akıllı sözleşmelerin gelecekteki potansiyelini açığa çıkarırken, Solidity de bu potansiyelin gerçeğe dönüşmesine olanak tanımıştır. Bu bölümde, Solidity'nin doğuşu, evrimi ve önemli kilometre taşlarına odaklanarak, dilin blockchain ekosistemindeki rolünü keşfedeceğiz.

Ethereum'un Kuruluşu ve Akıllı Sözleşmelerin İhtiyacı

Solidity'nin tarihçesi, Ethereum'un vizyonuyla başlamaktadır. Ethereum, 2013 yılında Vitalik Buterin tarafından ortaya atılan bir proje olarak, blockchain teknolojisinin çok daha ötesine geçerek akıllı sözleşmelerin çalıştırılabileceği bir platform olmayı hedefliyordu. Akıllı sözleşmeler, dijital varlıkların güvenli ve şeffaf bir şekilde taşınması, takas edilmesi ve yönetilmesi için gerekli olan protokollerdi. Ancak bu akıllı sözleşmeleri yazmak için bir programlama diline ihtiyaç vardı. Bu gereksinim, Solidity'nin doğmasına yol açtı.

Vitalik Buterin, Ethereum'un geliştirilmesinde önemli bir rol oynadı ve akıllı sözleşmelerin Ethereum ağında çalıştırılabilmesi için uygun bir dil tasarlama fikrini de ortaya koydu. Ethereum’un tasarımında, akıllı sözleşmelerin merkeziyetsiz bir ağda koşullara dayalı olarak otomatik çalışabilmesi amaçlanıyordu. Ancak o dönemde, Ethereum ağında bu tür sözleşmeleri yazabilecek yerleşik bir dil mevcut değildi.

Solidity'nin Doğuşu (2014)

Solidity’nin doğuşu, Ethereum’un yaratılmasının hemen ardından geldi. Ethereum’un kurucusu Vitalik Buterin ve diğer Ethereum geliştiricileri, akıllı sözleşmelerin Ethereum blockchain üzerinde çalışabilmesi için bir dil geliştirmeye başladılar. 2014 yılında, Ethereum'un ilk teknik belgeleri yayımlandığında, akıllı sözleşmelerin yazılması için Solidity’nin temelleri atılmaya başlandı.

Solidity, başlangıçta Ethereum’un sanal makinesi (EVM) ile uyumlu olacak şekilde tasarlandı. Bu, yazılımın Ethereum ağında çalıştırılabilir olmasını sağlamak için önemli bir adımdı. Solidity’nin tasarımında, JavaScript gibi popüler dillerden esinlenilmişti, çünkü bu diller yazılımcılar tarafından iyi biliniyor ve anlaşılabiliyordu. Böylece, yazılımcıların hızlıca Solidity diline adapte olmaları hedeflendi.

İlk başlarda, Solidity’nin geliştirilmesi daha çok Ethereum'un kendi iç ekipleri tarafından yapılıyordu. Ancak zamanla, Ethereum topluluğu ve açık kaynak geliştiricilerinin katkılarıyla dil hızla büyüdü.

Solidity'nin Gelişimi ve Yaygınlaşması (2015-2016)

Solidity, Ethereum ağının testnet'lerinde çalışmaya başladıktan sonra, daha geniş bir geliştirici topluluğu tarafından benimsenmeye başlandı. 2015 yılında Ethereum'un mainnet'i başlatıldığında, Solidity de akıllı sözleşmeleri yazmak için temel dil haline gelmişti. Bu dönemde, Solidity'nin daha güçlü ve esnek hale gelmesi için önemli güncellemeler yapıldı. Geliştiriciler, Solidity’nin kolay öğrenilebilirliğini ve güçlü özelliklerini takdir etmeye başladı.

Ethereum’un büyümesi ve blockchain teknolojisinin daha geniş kitleler tarafından kabul edilmesiyle birlikte, Solidity de hızla yayıldı. 2016 yılı, DeFi (Merkeziyetsiz Finans) uygulamaları, token satışları (ICO'lar) ve dijital koleksiyonlar gibi yeni blockchain tabanlı uygulamalar için temel bir yıl oldu. Solidity, bu uygulamaların merkezinde yer aldı. DeFi uygulamaları, Ethereum blockchain'inin sunduğu güvenli ve şeffaf altyapıyı kullanarak finansal işlemleri otomatikleştirdi. Solidity, bu tür uygulamaların geliştirilmesinde önemli bir araç haline geldi.

Bu dönemde, Solidity'nin daha verimli çalışabilmesi ve geliştiricilerin daha güvenli kod yazabilmesi için yeni özellikler eklenmeye başlandı. Ayrıca, Solidity'nin güvenlik açıklarını minimize etmek amacıyla daha fazla güvenlik önlemi geliştirilmeye başlandı.

Eğitim ve Geliştirici Araçları (2017-2018)

Solidity’nin 2017-2018 yılları arasındaki evrimi, geliştiriciler için daha erişilebilir ve kullanıcı dostu bir platform haline gelmesi açısından kritik bir dönüm noktasıydı. Bu dönemde, Solidity dilinin öğrenilmesini kolaylaştıracak birçok kaynak ve eğitim platformu ortaya çıkmaya başladı. Ethereum topluluğu, Solidity için kapsamlı dökümantasyonlar, eğitim videoları ve online kurslar sunarak, dille ilgili bilgiye erişimi arttırmaya başladı.

Ayrıca, Solidity için geliştirilmiş IDE’ler (Integrated Development Environments – Entegre Geliştirme Ortamları) ve araçlar da yaygınlaşmaya başladı. Bu araçlar, yazılımcıların daha verimli bir şekilde kod yazmasını sağladı. Truffle gibi geliştirme araçları, akıllı sözleşmelerin test edilmesi, dağıtılması ve yönetilmesi için gerekli tüm araçları sağlamaya başladı. Bu sayede, geliştiriciler Solidity ile daha hızlı ve güvenli bir şekilde projeler geliştirmeye başladılar.

Solidity'nin Güvenliği ve Zorluklar (2018-2020)

Solidity'nin güvenliği, Ethereum platformunun genel güvenliğini etkileyen kritik bir konu olmuştur. 2017'deki DAO saldırısı gibi olaylar, akıllı sözleşmelerdeki güvenlik açıklarının ne kadar tehlikeli olabileceğini gözler önüne serdi. DAO saldırısı, Ethereum’un blockchain üzerinde devreye giren hatalı bir akıllı sözleşme nedeniyle büyük bir güvenlik açığına yol açmış ve milyonlarca dolar değerinde Ether’in kaybına sebep olmuştu.

Bu tür olaylar, Solidity dilinin geliştirilmesinde güvenlik önlemlerinin daha fazla ön plana çıkmasına neden oldu. Ethereum geliştirme topluluğu, bu tür saldırıları önlemek amacıyla daha sıkı güvenlik önlemleri ve denetim süreçleri geliştirdi. Solidity, daha güvenli akıllı sözleşmeler yazmak için çeşitli özellikler ve güvenlik denetim araçları sunarak bu sorunu aşmaya çalıştı.

2020 yılı itibariyle Solidity, yalnızca Ethereum değil, aynı zamanda diğer blockchain platformlarında da yaygın olarak kullanılmaya başlandı. Solidity’nin güçlü yapısı ve Ethereum ağındaki başarısı, diğer blockchain projelerinin de benzer dilleri geliştirmelerine ilham verdi.

Solidity’nin Bugünü ve Geleceği

Bugün, Solidity, Ethereum ekosisteminin merkezinde yer almakta ve merkeziyetsiz uygulamalar (DApp’ler) geliştiren her seviyedeki geliştirici için temel bir araç haline gelmiştir. Ethereum’un yanı sıra, Binance Smart Chain, Avalanche ve Polygon gibi platformlar da Solidity’yi kullanarak akıllı sözleşmeleri desteklemektedir. Ayrıca, Solidity, DeFi, NFT’ler, oyunlar ve dijital varlık yönetimi gibi pek çok alanda uygulanmaktadır.

Solidity'nin geleceği, Ethereum'un daha da gelişmesi ve Ethereum 2.0’a geçişle birlikte şekillenecektir. Ethereum 2.0 ile birlikte, ağı daha verimli ve güvenli hale getirmek için önemli değişiklikler yapılacak. Bu, Solidity'yi kullanan geliştiriciler için yeni fırsatlar yaratacak ve blockchain teknolojisinin daha geniş bir kitleye ulaşmasına olanak sağlayacaktır.

Solidity'nin gelecekteki evrimi, yalnızca Ethereum ile sınırlı kalmayacak; blockchain ekosistemindeki diğer platformlar da Solidity'yi benimsedikçe, bu dilin önemi daha da artacaktır.
Solidity’nin Temel Özellikleri

Solidity, Ethereum blockchain’inde akıllı sözleşmelerin yazılması için tasarlanmış güçlü ve esnek bir programlama dilidir. Bu dilin popülerliği, Ethereum platformundaki uygulamaların hızla büyümesiyle doğru orantılı olarak arttı. Solidity'nin sağlam temeller üzerine inşa edilmiş özellikleri, onu blockchain geliştirme dünyasında vazgeçilmez bir araç haline getirmiştir. Bu bölümde, Solidity'nin sunduğu temel özellikleri ve bu özelliklerin nasıl çalıştığını ele alacağız.

1. Yüksek Seviye Programlama Dili

Solidity, yüksek seviyeli bir dil olarak tasarlanmıştır, bu da yazılımcıların daha az karmaşık ve daha anlaşılır kodlar yazmasına olanak tanır. Yüksek seviyeli diller, geliştiricilerin doğrudan makine kodlarıyla uğraşmalarını gerektirmez; bunun yerine, dil daha soyut bir düzeyde çalışır. Solidity, özellikle Ethereum Virtual Machine (EVM) üzerinde çalışan uygulamalar için optimize edilmiştir. Bu sayede, geliştiriciler karmaşık blockchain uygulamaları yazarken daha verimli bir süreç yaşar.

Solidity'nin yazılımcılar için kolaylık sağlayan dil yapısı, popüler programlama dillerinden (JavaScript, Python, C++) esinlenmiştir. Bu benzerlik, programcıların Solidity diline adapte olmasını kolaylaştırır. Ethereum blockchain'inde çalışan bir akıllı sözleşmenin yazılması için Solidity, işlem ve mantık kodlarının verimli bir şekilde bir araya gelmesini sağlar. Yüksek seviyeli dil yapısı, geliştiricilerin Ethereum üzerinde akıllı sözleşmeler yazarken daha az hata yapmalarını ve daha hızlı geliştirme yapmalarını sağlar.

2. Solidity ile Akıllı Sözleşme Yazma

Solidity’nin temel özelliklerinden biri, Ethereum blockchain’inde çalışabilen akıllı sözleşmeler yazma yeteneğidir. Akıllı sözleşmeler, iki taraf arasındaki anlaşmaların dijital ve otomatik bir şekilde yerine getirilmesini sağlayan programlardır. Bu sözleşmeler, belirli koşullar yerine getirildiğinde otomatik olarak işlem yapar, bu da güvenlik, şeffaflık ve hız açısından büyük avantajlar sağlar.

Solidity ile yazılmış bir akıllı sözleşme, bir dizi şart ve işlem içerir. Bu sözleşmeler, Ethereum ağı üzerindeki herkes tarafından erişilebilir olup, sözleşmeye yazılan koşullar sağlandığında otomatik olarak uygulanır. Örneğin, bir DeFi (merkeziyetsiz finans) platformunda borç verme ve alma işlemleri, Solidity ile yazılmış akıllı sözleşmeler sayesinde güvenli ve hızlı bir şekilde gerçekleşebilir. Bu, blockchain’in sunduğu merkeziyetsiz yapının güvenliğini kullanarak, taraflar arasındaki işlemlerin izlenebilir ve değiştirilemez olmasını sağlar.

3. Ethereum Virtual Machine (EVM) ile Uyum

Solidity'nin en önemli özelliklerinden biri, Ethereum Virtual Machine (EVM) ile tam uyumlu olmasıdır. EVM, Ethereum ağındaki akıllı sözleşmeleri çalıştıran sanal bir makinedir. Solidity, bu sanal makinede çalışacak şekilde tasarlanmıştır. Akıllı sözleşmeler, EVM üzerinde derlenip çalıştırılabilir ve Ethereum ağına dahil edilebilir. EVM, Ethereum ağındaki tüm işlemleri koordine eder ve Solidity ile yazılmış akıllı sözleşmelerin doğru bir şekilde çalışmasını sağlar.

EVM ile uyumlu olmak, Solidity’nin Ethereum ekosisteminde etkin bir şekilde çalışmasını sağlar. Bu uyum, Ethereum’daki tüm akıllı sözleşmelerin EVM üzerinde işleme alınmasını garanti eder ve bu da uygulamaların güvenli bir şekilde çalışmasını sağlar. Solidity'nin yazdığı kodlar, EVM üzerinde derlendikten sonra, Ethereum blockchain'ine yerleştirilir ve işlem gerçekleştirilir.

4. Gas (İşlem Ücreti) Yönetimi

Ethereum blockchain'inde gerçekleştirilen her işlem için bir işlem ücreti (gas fee) ödenir. Gas, Ethereum ağında işlem yapmanın maliyetini belirler ve bu ücretler, akıllı sözleşmelerin doğru bir şekilde çalışmasını sağlamak için gereklidir. Solidity, gas maliyetlerini optimize etmek için çeşitli teknikler sunar. Akıllı sözleşme geliştiricileri, Solidity’nin sunduğu araçları kullanarak, sözleşmelerinin gas maliyetlerini düşürmeye çalışabilirler.

Solidity dilinde yazılmış akıllı sözleşmelerde, işlem gerçekleştirmek için gereken gas miktarının doğru şekilde hesaplanması önemlidir. Bu hesaplamalar, Ethereum ağının verimli bir şekilde işlemesini sağlar ve işlemlerin ağda gerçekleşmesi için gerekli olan ücretlerin doğru şekilde belirlenmesine yardımcı olur. Bu özellik, geliştiricilerin daha verimli ve ekonomik sözleşmeler yazmalarını sağlar.

5. Değişkenler ve Veri Tipleri

Solidity, Ethereum blockchain’inde çalışacak akıllı sözleşmeler için zengin bir veri tipi yelpazesi sunar. Temel veri türlerinin yanı sıra, Solidity geliştiricileri kendi veri yapıları ve tiplerini de tanımlayabilirler. Solidity’deki veri türleri şunları içerir:

uint (Unsigned Integer): Tam sayılar, pozitif değerler alabilir.

int (Integer): Tam sayılar, negatif ve pozitif değerler alabilir.

address: Ethereum adreslerini tutmak için kullanılır.

bool (Boolean): Mantıksal değerler (true veya false).

string: Metin verilerini saklamak için kullanılır.

bytes: İkili verileri saklamak için kullanılır.

array: Verilerin sıralı dizileri.

mapping: Anahtar-değer çiftlerini depolayan veri yapısıdır.


Bu veri yapıları, akıllı sözleşmelerde değişkenlerin nasıl saklanacağını, işleneceğini ve manipüle edileceğini tanımlar. Solidity’nin sunduğu veri tipleri, geliştiricilerin blockchain üzerinde verimli ve güvenli kodlar yazmalarına olanak tanır.

6. Olaylar (Events)

Solidity, akıllı sözleşmelerde olaylar (events) oluşturmayı destekler. Olaylar, bir sözleşme çalışırken belirli bir eylemin gerçekleştiğini bildirmek için kullanılır. Ethereum blockchain’inde bir işlem gerçekleştirildiğinde, bu işlemle ilgili veriler blockchain’e kaydedilir. Olaylar, dış dünyadaki uygulamalara bu verileri bildirmek için kullanılır. Bu özellik, akıllı sözleşmelerin dış uygulamalarla etkileşimde bulunmasını sağlar.

Örneğin, bir token transferi gerçekleştirildiğinde, bu işlem bir "Transfer" olayı ile dış dünya tarafından dinlenebilir. Bu, merkeziyetsiz uygulamaların (DApp'ler) akıllı sözleşmelerle gerçek zamanlı olarak etkileşimde bulunmalarını sağlar.

7. Güvenlik Önlemleri

Solidity, güvenlik önlemleri konusunda birçok özellik ve mekanizma sunar. Akıllı sözleşmeler, blockchain üzerindeki tüm işlemleri kaydettikleri için, hatalı kod ve güvenlik açıkları büyük sorunlara yol açabilir. Solidity dilinde, geliştiricilerin bu tür hatalardan kaçınmalarına yardımcı olmak için çeşitli güvenlik araçları ve en iyi uygulamalar bulunmaktadır.

Örneğin, Solidity, reentrancy (yeniden çağırma) gibi güvenlik açıklarına karşı koruma sağlar. Ayrıca, doğru bir şekilde işlem yapan sözleşmelerin oluşturulmasına yardımcı olacak araçlar sunar. Akıllı sözleşmelerin güvenliği, blockchain uygulamalarının güvenliği için kritik bir unsurdur ve Solidity, bu güvenliği sağlamak için bir dizi mekanizma ve kontrol sunar.


---

Sonuç

Solidity, Ethereum blockchain üzerinde akıllı sözleşmelerin yazılması için en önemli araçlardan biridir ve sunduğu güçlü özellikler, geliştiricilerin merkeziyetsiz uygulamalar (DApp'ler) ve DeFi platformları oluşturmasını sağlar. Yüksek seviyeli dil yapısı, gas yönetimi, olaylar, veri yapıları, güvenlik önlemleri ve EVM ile uyumlu çalışma gibi temel özellikleri, Solidity’yi blockchain geliştirme sürecinde vazgeçilmez bir dil haline getirmiştir. Solidity'nin sunduğu olanaklar, merkeziyetsiz finans ve diğer blockchain tabanlı uygulamaların gelişimini hızlandırmakta ve Ethereum ağını daha güçlü kılmaktadır.

// SPDX-License-Identifier: MIT<br>pragma solidity ^0.8.0;<br><br>contract StateVariableExample {<br> uint256 public myNumber; // State değişkeni (blok zincirinde saklanır)<br><br> function setNumber(uint256 _newNumber) public {<br> myNumber = _newNumber; // Değer blockchain üzerinde güncellenir<br> }<br>}<br>

Yukarıdaki örnekte myNumber adlı bir state değişkeni tanımlanmıştır. setNumber fonksiyonu çağrıldığında, myNumber değeri güncellenir ve bu değer blockchain üzerinde kalıcı olarak saklanır.


Özellikler:


  • Blockchain’de saklanır ve değişmezlik ilkesi geçerlidir.
  • Akıllı sözleşmeye bağlıdır ve sözleşme silinmedikçe değişken kalır.
  • Gas ücreti gerektirir (blok zincirine veri yazıldığı için).



1.2. Local (Yerel) Değişkenler


Yerel değişkenler, yalnızca fonksiyonlar içinde tanımlanır ve blockchain üzerinde saklanmaz.


Örnek:


contract LocalVariableExample {<br> function calculateSum(uint256 a, uint256 b) public pure returns (uint256) {<br> uint256 sum = a + b; // Yerel değişken (blockchain'de saklanmaz)<br> return sum;<br> }<br>}<br>

Bu örnekte sum değişkeni yalnızca calculateSum fonksiyonunun içinde kullanılır ve fonksiyon tamamlandıktan sonra bellekten silinir.


Özellikler:


  • Blockchain’de saklanmaz, işlem ücretlerini düşürür.
  • Fonksiyon çağrıldığında çalışır, fonksiyon tamamlandığında kaybolur.
  • Daha düşük gas maliyeti sunar.



1.3. Global Değişkenler


Solidity, Ethereum blockchain’i ile etkileşim kurabilmek için çeşitli global değişkenler sunar. Bu değişkenler, işlem bilgilerini, blok detaylarını ve adresleri içerebilir.


Örnek:


contract GlobalVariableExample {<br> function getBlockInfo() public view returns (uint256, address) {<br> uint256 blockNumber = block.number; // Mevcut blok numarasını alır<br> address sender = msg.sender; // İşlemi gerçekleştiren adresi alır<br> return (blockNumber, sender);<br> }<br>}<br>

Önemli Global Değişkenler:


  • block.number: Mevcut blok numarası
  • block.timestamp: Blok madenciliği zaman damgası
  • msg.sender: Fonksiyonu çağıran adres
  • msg.value: İşlemde gönderilen ETH miktarı
  • tx.gasprice: İşlem ücretinin gas fiyatı



2. Veri Türleri


Solidity’de değişkenler farklı veri türleriyle saklanabilir. Temel veri türleri şunlardır:


  1. Tam Sayılar (Integer)
  2. Boolean
  3. Adresler (Address)
  4. Diziler (Array)
  5. Mapping
  6. Struct
  7. Enum
  8. Bytes ve String



2.1. Tam Sayılar (Integer)


Tam sayılar uint (pozitif sayılar) ve int (pozitif & negatif sayılar) olarak ikiye ayrılır.


Örnek:


contract IntegerExample {<br> uint256 public positiveNumber = 100; // 0 ile 2^256-1 arasında değer alabilir<br> int256 public negativeNumber = -50; // -2^255 ile 2^255-1 arasında değer alabilir<br>}<br>

Tam sayı türleri, bit büyüklüğüne göre uint8, uint16, uint256 gibi farklı boyutlarda olabilir.


Not: Büyük bit değerleri daha fazla gas harcar. uint8 gibi küçük türler daha verimli olabilir.




2.2. Boolean (Mantıksal Değerler)


Boolean değişkenler true veya false değerlerini alır.


Örnek:


contract BooleanExample {<br> bool public isContractActive = true; // Varsayılan değer false olabilir<br>}<br>

Boolean türü genellikle koşullu ifadelerde kullanılır:


contract Example {<br> function checkEven(uint256 _num) public pure returns (bool) {<br> return _num % 2 == 0; // Çift sayı kontrolü<br> }<br>}<br>



2.3. Adresler (Address)


Ethereum adresleri, 20 byte uzunluğunda olup, kullanıcı ve sözleşme adreslerini temsil eder.


Örnek:


contract AddressExample {<br> address public owner; // Ethereum adresi<br><br> constructor() {<br> owner = msg.sender; // Sözleşmeyi oluşturan adresi saklar<br> }<br>}<br>

Önemli Metotlar:


  • balance: Bir adresin ETH bakiyesini döndürür.
  • transfer(): Adrese ETH gönderir.

contract EtherTransfer {<br> function sendEther(address payable _recipient) public payable {<br> _recipient.transfer(msg.value); // ETH transferi<br> }<br>}<br>



2.4. Diziler (Arrays)


Diziler, aynı türden birden fazla veriyi saklamak için kullanılır.


Sabit Boyutlu Dizi:


contract FixedArray {<br> uint256[3] public numbers = [1, 2, 3];<br>}<br>

Dinamik Dizi:


contract DynamicArray {<br> uint256[] public numbers;<br><br> function addNumber(uint256 _num) public {<br> numbers.push(_num);<br> }<br>}<br>



2.5. Mapping (Haritalama)


Mapping, anahtar-değer (key-value) çiftleri saklamak için kullanılır.


Örnek:


contract MappingExample {<br> mapping(address =&gt; uint256) public balances;<br><br> function setBalance(uint256 _amount) public {<br> balances[msg.sender] = _amount;<br> }<br><br> function getBalance() public view returns (uint256) {<br> return balances[msg.sender];<br> }<br>}<br>

Mapping, belirli bir adres için değer saklamak için kullanılır (örneğin, token bakiyesi).




2.6. Struct (Yapılar)


Struct, farklı veri türlerini bir arada saklamak için kullanılır.


Örnek:


contract StructExample {<br> struct Person {<br> string name;<br> uint256 age;<br> }<br><br> Person public person1 = Person("Alice", 30);<br>}<br>



2.7. Enum (Numaralandırma)


Enum, sınırlı sayıda seçenek belirlemek için kullanılır.


Örnek:


contract EnumExample {<br> enum Status { Pending, Shipped, Delivered }<br> Status public orderStatus = Status.Pending;<br>}<br>



Sonuç


Solidity’de değişkenler ve veri türleri, akıllı sözleşmelerin temel yapı taşlarını oluşturur. Veri türlerinin doğru kullanımı, gas maliyetlerini düşürerek verimli ve güvenli akıllı sözleşmeler yazmayı sağlar.

5. Solidity’de Fonksiyonlar ve Akıllı Sözleşme Mantığı

Solidity'de fonksiyonlar, akıllı sözleşmelerin temel yapı taşlarını oluşturur. Akıllı sözleşmeler, fonksiyonlar aracılığıyla blockchain üzerinde işlem yapar ve kullanıcılarla etkileşime girer. Bu bölümde, Solidity'de fonksiyon türlerini, erişim belirteçlerini (visibility modifiers), işlevsel özellikleri ve fonksiyonlara dair önemli kavramları detaylı bir şekilde inceleyeceğiz.


---

1. Solidity’de Fonksiyon Türleri

Solidity’de fonksiyonlar dört temel kategoriye ayrılır:

1. Public (Genel) Fonksiyonlar


2. Private (Özel) Fonksiyonlar


3. Internal (Dahili) Fonksiyonlar


4. External (Harici) Fonksiyonlar




---

1.1. Public (Genel) Fonksiyonlar

Public fonksiyonlar, akıllı sözleşmenin içinden ve dışından çağrılabilir. Tüm kullanıcılar ve diğer akıllı sözleşmeler bu fonksiyonlara erişebilir.

Örnek:

contract PublicFunctionExample {
uint256 public data;

function setData(uint256 _data) public {
data = _data;
}
}

Bu fonksiyonu çağıran herhangi bir adres, data değişkenini değiştirebilir.

Özellikler:

Hem akıllı sözleşme içinden hem de dışından çağrılabilir.

Gas ücreti gerektirir (state değişkeni değiştiriliyorsa).



---

1.2. Private (Özel) Fonksiyonlar

Private fonksiyonlar yalnızca sözleşme içinde kullanılabilir. Dış dünyadan erişim mümkün değildir.

Örnek:

contract PrivateFunctionExample {
uint256 private data;

function setData(uint256 _data) private {
data = _data;
}

function callSetData(uint256 _data) public {
setData(_data); // Yalnızca bu sözleşme içinden çağrılabilir
}
}

Burada setData fonksiyonu sadece callSetData fonksiyonu içinden çağrılabilir.

Özellikler:

Başka sözleşmeler ve dış kullanıcılar erişemez.

Kod tekrarını azaltmak için kullanılır.

Daha güvenli sözleşmeler yazmaya yardımcı olur.



---

1.3. Internal (Dahili) Fonksiyonlar

Internal fonksiyonlar, sadece aynı sözleşme veya türetilmiş (miras alınan) sözleşmeler tarafından çağrılabilir.

Örnek:

contract InternalFunctionExample {
uint256 internal data;

function setData(uint256 _data) internal {
data = _data;
}
}

contract ChildContract is InternalFunctionExample {
function updateData(uint256 _newData) public {
setData(_newData); // Üst sınıfın internal fonksiyonu çağrılabilir
}
}

Burada setData, ChildContract içinde çağrılabilir çünkü internal olarak tanımlanmıştır.

Özellikler:

Miras alınan (inheritance) sözleşmeler tarafından kullanılabilir.

Solidity’de nesne yönelimli programlama (OOP) mantığını destekler.



---

1.4. External (Harici) Fonksiyonlar

External fonksiyonlar, yalnızca dışarıdan çağrılabilir. Sözleşme içinden doğrudan çağrı yapılamaz.

Örnek:

contract ExternalFunctionExample {
uint256 public data;

function setData(uint256 _data) external {
data = _data;
}
}

setData fonksiyonu, yalnızca sözleşme dışından çağrılabilir.

Özellikler:

Dış dünyaya açık olup, sözleşme içinden çağrılamaz.

Daha düşük gas maliyeti sunar.



---

2. Solidity Fonksiyonlarının Ekstra Özellikleri

Solidity fonksiyonları, çeşitli belirteçlerle özelleştirilebilir.

2.1. View ve Pure Fonksiyonlar

view fonksiyonları, blockchain verisini okur ama değiştirmez.
pure fonksiyonları, blockchain verisine erişmez ve sadece hesaplama yapar.

Örnek:

contract ViewPureExample {
uint256 public storedNumber = 10;

function getNumber() public view returns (uint256) {
return storedNumber; // Sadece okuma yapar, değiştirmez
}

function addNumbers(uint256 a, uint256 b) public pure returns (uint256) {
return a + b; // Blockchain verisi kullanmaz
}
}

Özellikler:

view: State değişkenlerini okuyabilir ama değiştiremez.

pure: Blockchain’deki herhangi bir veriyi okumaz ve değiştirmez.

Bu fonksiyonlar gas ücreti gerektirmez.



---

2.2. Payable Fonksiyonlar

Ethereum transferlerini kabul eden fonksiyonlar payable olarak tanımlanır.

Örnek:

contract PayableExample {
address public owner;

constructor() {
owner = msg.sender;
}

function deposit() public payable {} // ETH alabilir

function getBalance() public view returns (uint256) {
return address(this).balance;
}
}

Bu sözleşmeye ETH göndermek için deposit() fonksiyonu kullanılabilir.

Özellikler:

ETH ve token transferlerini mümkün kılar.

msg.value kullanılarak işlemde gönderilen miktar alınabilir.



---

2.3. Fonksiyon Modifier'ları

Modifier'lar, fonksiyonlara özel kurallar eklemek için kullanılır.

Örnek:

contract ModifierExample {
address public owner;

constructor() {
owner = msg.sender;
}

modifier onlyOwner() {
require(msg.sender == owner, "Yetkiniz yok!");
_;
}

function changeOwner(address newOwner) public onlyOwner {
owner = newOwner;
}
}

Burada onlyOwner modifier’ı, sadece sözleşme sahibinin changeOwner fonksiyonunu çağırmasına izin verir.

Özellikler:

Güvenlik kontrollerini kolaylaştırır.

Tekrar eden kodları azaltır.



---

3. Solidity’de Fonksiyon Çağrıları

Solidity’de fonksiyonlar farklı yöntemlerle çağrılabilir:

1. Doğrudan Çağrı (Internal Call)

function example() public {
anotherFunction();
}


2. Dış Sözleşme Çağrısı (External Call)

function callAnotherContract(address _contract) public {
AnotherContract(_contract).externalFunction();
}


3. Low-Level Call (Gelişmiş Çağrı)

function sendEther(address payable _to) public payable {
(bool success, ) = _to.call{value: msg.value}("");
require(success, "Transfer basarisiz!");
}




---

Sonuç

Solidity fonksiyonları, akıllı sözleşmelerin en temel yapı taşlarından biridir. public, private, internal ve external erişim türleri sayesinde farklı senaryolara u
ygun çözümler sunulabilir. payable fonksiyonlarla ETH transferi yapılabilir, modifier yapıları güvenliği artırabilir ve view ile pure fonksiyonlar gas ücretlerini optimize edebilir.

6. Solidity’de Miras (Inheritance) ve Çoklu Kalıtım

Solidity, nesne yönelimli programlamayı (OOP) destekleyen bir dildir ve miras (inheritance) özelliği sayesinde kod tekrarını önleyerek daha modüler ve sürdürülebilir akıllı sözleşmeler yazmaya olanak tanır. Miras yapısı, bir sözleşmenin başka bir sözleşmeden özellik ve fonksiyonları devralmasını sağlar.

Bu bölümde, miras yapısının temellerini, çoklu kalıtımın nasıl çalıştığını ve super, override, virtual gibi anahtar kelimeleri detaylı bir şekilde inceleyeceğiz.


---

1. Solidity’de Mirasın Temelleri

Bir sözleşmenin başka bir sözleşmeden türetilmesi için is anahtar kelimesi kullanılır.

Örnek:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Parent {
string public name = "Parent Contract";

function getName() public view returns (string memory) {
return name;
}
}

contract Child is Parent {
function getParentName() public view returns (string memory) {
return getName(); // Parent sözleşmesinden fonksiyon çağırma
}
}

Burada Child sözleşmesi, Parent sözleşmesini miras alır. getParentName fonksiyonu, üst sınıftaki getName fonksiyonunu çağırabilir.

Özellikler:

Child sözleşmesi, Parent sözleşmesindeki tüm public ve internal değişkenleri ve fonksiyonları miras alır.

private fonksiyonlar ve değişkenler miras alınamaz.



---

2. Çoklu Kalıtım (Multiple Inheritance)

Solidity, birden fazla sözleşmeyi miras almayı destekler.

Örnek:

contract A {
function foo() public pure returns (string memory) {
return "A'dan çağırıldı";
}
}

contract B {
function bar() public pure returns (string memory) {
return "B'den çağırıldı";
}
}

contract C is A, B {
function getFunctions() public pure returns (string memory, string memory) {
return (foo(), bar());
}
}

Burada C sözleşmesi, hem A hem de B sözleşmelerini miras alır ve her ikisinin fonksiyonlarına erişebilir.

Dikkat Edilmesi Gerekenler:

Eğer iki ebeveyn sözleşmesinde aynı isimde bir fonksiyon varsa, Solidity Diamond Problem (Elmas Problemi) yaşanmaması için açıkça hangi ebeveynden miras alınacağını belirtmeyi gerektirir.



---

3. virtual ve override Kullanımı

Miras alınan bir fonksiyonun değiştirilebilir (override edilebilir) olması için virtual olarak tanımlanması gerekir.

Örnek:

contract Parent {
function greet() public pure virtual returns (string memory) {
return "Merhaba, ben Parent";
}
}

contract Child is Parent {
function greet() public pure override returns (string memory) {
return "Merhaba, ben Child";
}
}

Burada Parent sözleşmesindeki greet fonksiyonu virtual olarak tanımlandığı için, Child sözleşmesi bunu override edebilir.


---

4. super Anahtar Kelimesi

super anahtar kelimesi, miras alınan sözleşmelerde üst sınıfın fonksiyonlarını çağırmak için kullanılır.

Örnek:

contract Parent {
function greet() public pure virtual returns (string memory) {
return "Merhaba, ben Parent";
}
}

contract Child is Parent {
function greet() public pure override returns (string memory) {
return string(abi.encodePacked(super.greet(), " ve ben Child"));
}
}

Bu kodda, super.greet() üst sınıftaki greet fonksiyonunu çağırarak çıktıya ekler.


---

5. Miras Hiyerarşisi ve Çakışmalar

Solidity’de birden fazla ebeveyn sözleşmesinden miras alırken, sıralama önemlidir.

Yanlış Kullanım:

contract A {
function sayHello() public pure virtual returns (string memory) {
return "A";
}
}

contract B is A {
function sayHello() public pure virtual override returns (string memory) {
return "B";
}
}

contract C is A, B {
function sayHello() public pure override(A, B) returns (string memory) {
return super.sayHello();
}
}

Burada C sözleşmesi A ve B'yi miras alıyor. Ancak miras alma sırası B önce olmalıdır. Doğru kullanım:

contract C is B, A {
function sayHello() public pure override(A, B) returns (string memory) {
return super.sayHello();
}
}

Solidity, en son miras alınan sözleşmeyi öncelikli olarak kabul eder. Bu yüzden B önce tanımlanmalıdır.


---

6. Abstract Sözleşmeler ve Arayüzler (Interfaces)

6.1. Abstract Sözleşmeler

Abstract sözleşmeler, tamamlanmamış fonksiyonlar içeren ve doğrudan örneği oluşturulamayan sözleşmelerdir.

Örnek:

abstract contract AbstractContract {
function getValue() public view virtual returns (uint256);
}

contract ConcreteContract is AbstractContract {
function getValue() public view override returns (uint256) {
return 100;
}
}

Özellikler:

İçinde virtual fonksiyonlar olabilir.

Doğrudan deploy edilemez, miras alınarak tamamlanmalıdır.



---

6.2. Arayüzler (Interfaces)

Arayüzler, sadece fonksiyon imzalarını (signature) içeren ve state değişkeni barındırmayan sözleşmelerdir.

Örnek:

interface IExample {
function getNumber() external view returns (uint256);
}

contract Example is IExample {
function getNumber() public pure override returns (uint256) {
return 42;
}
}

Özellikler:

Sadece external fonksiyonlar içerir.

State değişkenleri tanımlanamaz.

is anahtar kelimesiyle uygulanır.



---

Sonuç

Solidity’de miras yapısı, kod tekrarını önlemek ve modüler akıllı sözleşmeler yazmak için büyük bir avantaj sağlar.

is anahtar kelimesiyle miras alınır.

virtual i
le fonksiyonlar override edilebilir hale getirilir.

super ile üst sınıftaki fonksiyonlar çağrılabilir.

Çoklu miras dikkatli yönetilmelidir (Diamond Problem).

Abstract sözleşmeler ve arayüzler (interfaces) ile esnek yapılar oluşturulabilir.


7. Solidity’de Hata Yönetimi ve Güvenlik Önlemleri


Solidity, akıllı sözleşmelerin güvenliğini sağlamak için çeşitli hata yönetimi mekanizmaları sunar. Blockchain üzerindeki işlemler geri döndürülemez olduğu için akıllı sözleşmelerin dikkatli bir şekilde yazılması gereklidir.


Bu bölümde hata yönetimi stratejilerini, güvenlik önlemlerini ve Solidity’de güvenli akıllı sözleşmeler geliştirmek için en iyi uygulamaları ele alacağız.




1. Solidity’de Hata Yönetimi Mekanizmaları


Solidity, hataları ele almak için üç temel mekanizma sunar:


  1. require()
  2. assert()
  3. revert()

Bu mekanizmalar, hataları kontrol ederek sözleşmelerin beklenmeyen durumlara karşı korunmasını sağlar.




1.1. require() Fonksiyonu


require(), belirli bir koşulun sağlanıp sağlanmadığını kontrol eder. Eğer koşul sağlanmazsa, işlem geri alınır (revert edilir) ve hata mesajı döndürülür.


Örnek:


contract RequireExample {<br> function checkValue(uint256 _value) public pure returns (string memory) {<br> require(_value &gt; 10, "Deger 10'dan buyuk olmali");<br> return "Gecerli deger";<br> }<br>}<br>

Burada _value 10’dan küçükse, işlem geri alınır ve hata mesajı görüntülenir.


Özellikler:


  • Kullanıcı girişlerini doğrulamak için kullanılır.
  • İşlem geçerli değilse geri döndürür ve gas ücretlerinin bir kısmı iade edilir.



1.2. assert() Fonksiyonu


assert(), dahili hataları tespit etmek için kullanılır. Çalışma zamanında (runtime) yanlış olmaması gereken durumları test etmek için kullanılır.


Örnek:


contract AssertExample {<br> uint256 public number = 10;<br><br> function testAssert() public view {<br> assert(number == 10);<br> }<br>}<br>

Eğer number değişkeni 10 değilse, işlem geri alınır.


Özellikler:


  • Programın mantığında hata olup olmadığını test etmek için kullanılır.
  • Gas ücreti geri ödenmez.



1.3. revert() Fonksiyonu


revert(), belirli bir hata durumunda işlemi manuel olarak geri almak için kullanılır.


Örnek:


contract RevertExample {<br> function checkCondition(uint256 _value) public pure {<br> if (_value &lt; 10) {<br> revert("Deger cok kucuk!");<br> }<br> }<br>}<br>

Burada _value 10’dan küçükse, işlem geri alınır.


Özellikler:


  • if blokları içinde hata yönetimi yapmak için kullanılır.
  • Geri dönüş mesajı özelleştirilebilir.



2. Solidity’de Güvenlik Önlemleri


Akıllı sözleşmeler birçok saldırı türüne maruz kalabilir. Güvenli bir sözleşme geliştirmek için aşağıdaki önlemler alınmalıdır:


2.1. Yeniden Giriş (Reentrancy) Saldırıları ve Önleme


Yeniden giriş saldırısı, bir saldırganın sözleşmeden tekrar tekrar fonksiyon çağırarak bakiyeyi boşaltmasıdır.


Tehlikeli Örnek:


contract VulnerableContract {<br> mapping(address =&gt; uint256) public balances;<br><br> function withdraw() public {<br> uint256 amount = balances[msg.sender];<br> require(amount &gt; 0, "Bakiye yetersiz");<br><br> (bool success, ) = msg.sender.call{value: amount}("");<br> require(success, "Transfer basarisiz");<br><br> balances[msg.sender] = 0; // Güvenlik açığı: Önce güncellenmeli!<br> }<br>}<br>

Burada fonksiyon, para transferi yaptıktan sonra bakiyeyi sıfırlıyor. Ancak saldırgan, çağrıyı manipüle ederek tekrar para çekebilir.


Çözüm:
Bakiyeyi önce sıfırlayıp, sonra ödeme yapmak gerekir.


contract SecureContract {<br> mapping(address =&gt; uint256) public balances;<br><br> function withdraw() public {<br> uint256 amount = balances[msg.sender];<br> require(amount &gt; 0, "Bakiye yetersiz");<br><br> balances[msg.sender] = 0; // Önce güncelle!<br><br> (bool success, ) = msg.sender.call{value: amount}("");<br> require(success, "Transfer basarisiz");<br> }<br>}<br>

Alternatif Koruma:


  • transfer() ve send() kullanmak
  • ReentrancyGuard kütüphanesi kullanmak



2.2. Integer Overflow ve Underflow


Eski Solidity sürümlerinde, uint256 değerleri maksimum sınırı aşarsa (overflow) veya sıfırın altına düşerse (underflow), hatalara neden olur.


Örneğin:


contract OverflowExample {<br> uint8 public max = 255;<br><br> function increment() public {<br> max += 1; // Overflow hatası!<br> }<br>}<br>

Solidity 0.8.x sürümünde bu tür hatalar varsayılan olarak engellenmiştir. Ancak, eski sürümler için SafeMath kütüphanesi kullanılır.


import "@openzeppelin/contracts/utils/math/SafeMath.sol";<br><br>contract SafeExample {<br> using SafeMath for uint256;<br> uint256 public max = 255;<br><br> function increment() public {<br> max = max.add(1); // Güvenli artış<br> }<br>}<br>



2.3. Kullanıcı Girdilerini Doğrulama


Kullanıcının girdiği verileri kontrol etmek önemlidir.


contract InputValidation {<br> function setAge(uint256 _age) public pure {<br> require(_age &gt; 0 &amp;&amp; _age &lt; 150, "Gecersiz yas");<br> }<br>}<br>

Önlemler:


  • require() kullanarak girişleri doğrulamak
  • Kısıtlamaları net bir şekilde tanımlamak



2.4. Access Control (Erişim Kontrolü)


Önemli fonksiyonların sadece yetkili kişiler tarafından çağrılmasını sağlamak için erişim kontrol mekanizmaları kullanılmalıdır.


contract AccessControl {<br> address public owner;<br><br> constructor() {<br> owner = msg.sender;<br> }<br><br> modifier onlyOwner() {<br> require(msg.sender == owner, "Yetkiniz yok!");<br> _;<br> }<br><br> function sensitiveFunction() public onlyOwner {<br> // Sadece owner çağırabilir<br> }<br>}<br>

Önlemler:


  • onlyOwner gibi modifier’lar kullanmak
  • OpenZeppelin Ownable sözleşmesini kullanmak



3. Güvenlik Açıklarından Kaçınma


Güvenli bir akıllı sözleşme yazmak için aşağıdaki kurallara dikkat edilmelidir:


Denetlenmiş Kütüphaneleri Kullan


  • OpenZeppelin gibi güvenilir kütüphaneler tercih edilmelidir.

Dış Sözleşme Çağrılarını Kontrol Et


  • Dış sözleşmelerin kötü amaçlı olabileceği unutulmamalıdır.

İşlem Sırasına Dikkat Et


  • Önce state güncellenmeli, sonra işlem yapılmalıdır.

Fonksiyonları Varsayılan Olarak Private Tut


  • Sadece gerektiğinde public veya external yapılmalıdır.

Hata Yönetimi Kullanın


  • require(), assert(), revert() mekanizmalarını etkili kullanın.



Sonuç


Solidity’de hata yönetimi ve güvenlik, akıllı sözleşmelerin en kritik konularından biridir. require(), assert() ve revert() kullanılarak hatalar önlenebilir. Ayrıca, yeniden giriş saldırıları, integer overflow ve erişim kontrolü gibi konulara dikkat edilmelidir.


8. Solidity’de Etkinlikler (Events) ve Loglama Mekanizmaları


Solidity’de events (etkinlikler), blockchain üzerinde gerçekleşen olayları izlemek ve dış uygulamalar (örneğin, frontend arayüzleri) ile etkileşim kurmak için kullanılan güçlü bir mekanizmadır. Ethereum’da smart contract’ler doğrudan dış dünyaya mesaj gönderemez, ancak etkinlikler kullanılarak belirli olaylar dış dünyaya duyurulabilir.


Bu bölümde etkinliklerin nasıl tanımlandığını, nasıl kullanıldığını ve blockchain üzerindeki performans avantajlarını ele alacağız.




1. Solidity’de Etkinliklerin (Events) Tanımlanması


Etkinlikler, Solidity’de event anahtar kelimesiyle tanımlanır ve emit komutu ile tetiklenir.


Temel Event Kullanımı:


// SPDX-License-Identifier: MIT<br>pragma solidity ^0.8.0;<br><br>contract EventExample {<br> event ValueChanged(address indexed sender, uint256 oldValue, uint256 newValue);<br><br> uint256 public value;<br><br> function updateValue(uint256 _newValue) public {<br> uint256 oldValue = value;<br> value = _newValue;<br><br> emit ValueChanged(msg.sender, oldValue, _newValue);<br> }<br>}<br>

Açıklamalar:


  • Event Tanımlama: event ValueChanged(address sender, uint256 oldValue, uint256 newValue);
  • Emit Kullanımı: emit ValueChanged(msg.sender, oldValue, _newValue); ile etkinlik tetiklenir.
  • Indexed Parametreler: indexed anahtar kelimesi, etkinliğin filtrelenmesini kolaylaştırır (Ethereum logları için önemlidir).



2. Etkinliklerin Kullanım Amaçları


Etkinlikler, blockchain üzerindeki işlemleri takip etmek ve daha etkin bir kullanıcı deneyimi sunmak için kullanılır.


Kullanım Senaryoları:


  1. Blockchain Üzerinde Log Tutma → Sözleşmenin durumu hakkında bilgi almak.
  2. Dış Uygulamalara Bilgi Gönderme → Web uygulamalarına veri göndermek için.
  3. Önemli Olayları Kaydetme → Token transferleri, değişiklikler ve hata durumları gibi kritik işlemleri takip etmek.



3. Event’lerin Blockchain Performansına Etkisi


3.1. Gas Ücretleri Açısından Avantajı


Etkinlikler, storage değişkenlerine kıyasla daha az gas tüketir. Çünkü loglar, blockchain’de depolanmaz, yalnızca olaylar için özel bir log alanında tutulur.


event DataStored(uint256 data); // Gas dostu <br><br>uint256 public storedData; // Daha pahalı<br>

  • Event’ler log olarak saklanır ve storage alanına göre daha ucuzdur.
  • Akıllı sözleşmeler event’leri doğrudan okuyamaz.



3.2. Event’leri Filtreleme ve indexed Kullanımı


Indexed parametreleri, loglar arasında hızlı arama yapmayı sağlar.


event Transfer(address indexed from, address indexed to, uint256 value);<br>

  • indexed ile belirtilen alanlar Ethereum’un log mekanizmasında arama yapılabilir hale gelir.
  • En fazla üç indexed parametre kullanılabilir.

Filtreleme Örneği:
Örneğin, bir frontend uygulaması, Transfer event’ini yalnızca belirli bir adrese göre dinleyebilir:


contractInstance.Transfer({ to: userAddress }, (error, event) =&gt; {<br> console.log(event);<br>});<br>



4. Örnek: Token Transferlerinde Event Kullanımı


Bir ERC-20 token sözleşmesinde, transfer işlemlerini takip etmek için Transfer etkinliği kullanılır.


contract Token {<br> mapping(address =&gt; uint256) public balances;<br> <br> event Transfer(address indexed from, address indexed to, uint256 value);<br><br> function transfer(address _to, uint256 _value) public {<br> require(balances[msg.sender] &gt;= _value, "Yetersiz bakiye");<br> <br> balances[msg.sender] -= _value;<br> balances[_to] += _value;<br> <br> emit Transfer(msg.sender, _to, _value);<br> }<br>}<br>

Çıktı Örneği:
Bir transfer işlemi gerçekleştiğinde aşağıdaki log kaydedilir:


Transfer(msg.sender: 0x123..., to: 0x456..., value: 100)<br>

Frontend uygulamalar bu logları kullanarak işlemleri anlık olarak takip edebilir.




5. Event Loglarının Okunması ve Kullanımı


Blockchain üzerindeki etkinlikleri görmek ve okumak için farklı yöntemler vardır:


5.1. Ethereum RPC ile Log Okuma


Ethereum node’ları, etkinlik loglarını okumak için JSON-RPC arayüzü sağlar.


Örnek RPC çağrısı:


{<br> "jsonrpc": "2.0",<br> "method": "eth_getLogs",<br> "params": [{<br> "fromBlock": "0x0",<br> "toBlock": "latest",<br> "topics": ["0xddf252ad..."] <br> }],<br> "id": 1<br>}<br>

Burada topics değeri, Transfer etkinliğinin hashlenmiş imzasıdır.




5.2. Web3.js ile Event Takibi


Web3.js kullanarak belirli bir etkinliği dinleyebiliriz.


const contract = new web3.eth.Contract(abi, contractAddress);<br><br>contract.events.Transfer({<br> filter: { to: '0x456...' }, <br> fromBlock: 'latest'<br>}, (error, event) =&gt; {<br> console.log("Transfer Gerçekleşti:", event.returnValues);<br>});<br>

Bu kod, sadece belirli bir adrese yapılan transferleri dinler.




5.3. Hardhat veya Truffle ile Test Etme


Hardhat veya Truffle kullanarak event’lerin tetiklendiğini test edebiliriz.


it("Transfer event should be emitted", async () =&gt; {<br> let result = await token.transfer(accounts[1], 100);<br> truffleAssert.eventEmitted(result, 'Transfer');<br>});<br>

Bu test, transfer işlemi sırasında Transfer etkinliğinin oluştuğunu doğrular.




6. Event’leri Kullanırken Dikkat Edilmesi Gerekenler


Blockchain’e fazla veri yazmaktan kaçının.


  • Event’ler gas tasarrufu sağlar, ancak yine de gereksiz veri eklemekten kaçının.

Güvenlik için event log’larına güvenmeyin.


  • Sözleşmeler logları doğrudan okuyamaz, sadece dış uygulamalar kullanabilir.

Indexed parametreleri verimli kullanın.


  • Arama ve filtreleme performansı için indexed alanlarını dikkatli seçin.



Sonuç


Etkinlikler, Solidity’de önemli olayları dış dünyaya duyurmanın en iyi yoludur. Gas tasarrufu sağlar, ancak yalnızca dış uygulamalar tarafından okunabilir.


Özet:


Event’ler, blockchain üzerindeki işlemleri takip etmeyi sağlar.
Emit komutu, event’leri tetiklemek için kullanılır.
Indexed parametreler, logları filtrelemeyi kolaylaştırır.
Frontend uygulamaları event’leri Web3.js veya RPC ile dinleyebilir.
Blockchain’e veri yazarken dikkatli olun ve gereksiz event kullanmayın.


9. Solidity’de Modüler Sözleşme Yapısı ve Kütüphaneler

Solidity’de modüler sözleşme yapısı, kod tekrarını azaltarak daha okunabilir, güvenli ve yönetilebilir akıllı sözleşmeler yazmayı sağlar. Bu yapı, miras (inheritance), kütüphaneler (libraries) ve arayüzler (interfaces) gibi farklı bileşenlerden oluşur.

Bu bölümde Solidity’de modüler yapı kullanmanın avantajlarını, miras yapısını, kütüphaneleri ve en iyi uygulamaları inceleyeceğiz.


---

1. Solidity’de Modüler Yapının Önemi

✔ Kod Tekrarını Önler → Aynı kodu farklı sözleşmelerde tekrar yazmaya gerek kalmaz.
✔ Bakım ve Güncellemeyi Kolaylaştırır → Sözleşme bileşenleri bağımsız olduğu için değişiklik yapmak daha kolaydır.
✔ Güvenliği Artırır → Akıllı sözleşmelerde hataları azaltır ve test edilebilirliği artırır.
✔ Gas Maliyetini Düşürür → Kütüphaneler sayesinde fonksiyonlar tekrar kullanılabilir hale gelir.


---

2. Solidity’de Miras (Inheritance) Kullanımı

Miras (inheritance), bir sözleşmenin başka bir sözleşmenin fonksiyonlarını ve değişkenlerini miras almasını sağlar.

2.1. Temel Miras Kullanımı

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Parent {
uint256 public data;

function setData(uint256 _data) public {
data = _data;
}
}

// Child, Parent sözleşmesini miras alır
contract Child is Parent {
function getData() public view returns (uint256) {
return data;
}
}

Açıklamalar:

Child sözleşmesi Parent sözleşmesini miras alır.

Child, setData fonksiyonuna erişebilir ve data değişkenini kullanabilir.



---

2.2. virtual ve override Kullanımı

Alt sınıflar, üst sınıfların fonksiyonlarını ezerek (override) kendi versiyonlarını tanımlayabilirler.

contract Parent {
function sayHello() public pure virtual returns (string memory) {
return "Merhaba, ben Parent";
}
}

contract Child is Parent {
function sayHello() public pure override returns (string memory) {
return "Merhaba, ben Child";
}
}

Özellikler:

virtual: Bir fonksiyonun alt sınıflar tarafından değiştirilebilir olduğunu belirtir.

override: Alt sınıfta fonksiyonu ezmek için kullanılır.



---

3. Solidity’de Kütüphane (Library) Kullanımı

Kütüphaneler, Solidity’de tekrar kullanılabilir fonksiyonlar içeren modüllerdir. Bir sözleşmenin içinde belirli işlemleri gerçekleştirmek için kullanılır.

3.1. Kütüphane Tanımlama ve Kullanımı

library Math {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
}

contract Calculator {
using Math for uint256;

function calculate(uint256 x, uint256 y) public pure returns (uint256) {
return x.add👍;
}
}

Özellikler:

Kütüphaneler state değişkeni içeremez.

Kendi başlarına deploy edilmez, sözleşmelere bağlı çalışırlar.

using ... for ile belirli veri türlerine uygulanabilirler.



---

3.2. Kütüphaneler ile Güvenli İşlemler

Örneğin, eski Solidity sürümlerinde integer overflow hatalarını önlemek için SafeMath kütüphanesi kullanılırdı.

library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
require(a + b >= a, "Overflow hatasi!");
return a + b;
}
}

Bu kütüphane, a + b işleminin taşma (overflow) yapmasını engeller.


---

3.3. Kütüphanelerin Bağımsız Deploy Edilmesi

Bazı büyük kütüphaneler ayrı bir sözleşme olarak deploy edilebilir ve farklı akıllı sözleşmeler tarafından kullanılabilir.

Örnek:

library ExternalLib {
function multiply(uint256 x, uint256 y) external pure returns (uint256) {
return x * y;
}
}

Başka bir sözleşmede bunu kullanmak için:

contract TestContract {
function testMultiply(uint256 x, uint256 y) public pure returns (uint256) {
return ExternalLib.multiply(x, y);
}
}

Bu yöntem, farklı akıllı sözleşmelerin aynı kütüphaneyi kullanmasını sağlar ve gas maliyetlerini düşürür.


---

4. Solidity’de Arayüzler (Interfaces) Kullanımı

Arayüzler, bir sözleşmenin dış dünyaya sunduğu fonksiyonları tanımlamak için kullanılır.

4.1. Arayüz Tanımlama

interface IToken {
function transfer(address to, uint256 amount) external returns (bool);
}

contract MyContract {
IToken token;

constructor(address _tokenAddress) {
token = IToken(_tokenAddress);
}

function sendTokens(address _to, uint256 _amount) public {
token.transfer(_to, _amount);
}
}

Özellikler:
✔ Arayüzlerde değişken tanımlanamaz.
✔ Fonksiyonlar yalnızca external olabilir.
✔ Arayüzler implement edilen sözleşmenin tüm fonksiyonlarını barındırmalıdır.




5. Modüler Yapı ile ERC-20 Token Yazma

ERC-20 token sözleşmesi yazarken modüler yapı kullanılır.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC20 {
function transfer(address recipient, uint256 amount) external returns (bool);
}

library SafeTransfer {
function safeSend(IERC20 token, address to, uint256 amount) internal {
require(token.transfer(to, amount), "Transfer basarisiz!");
}
}

contract TokenSender {
using SafeTransfer for IERC20;

function sendTokens(IERC20 token, address to, uint256 amount) public {
token.safeSend(to, amount);
}
}

Burada:
✔ IERC20 arayüzü token standardını belirler.
✔ SafeTransfer kütüphanesi güvenli transfer işlemleri için kullanılır.
✔ TokenSender sözleşmesi, token gönderme işlemini gerçekleştirir.



6. Modüler Yapı Kullanırken Dikkat Edilmesi Gerekenler

✅ Kod Tekrarını Azaltın:

Kütüphaneleri ve miras yapısını kullanarak tekrar eden kodları önleyin.


✅ Güvenliği Artırın:

Kütüphaneler ve arayüzler kullanarak güvenli işlemler gerçekleştirin.


✅ Gas Ücretlerini Optimize Edin:

Depolama yerine event’leri ve kütüphaneleri kullanarak maliyetleri azaltın.


✅ Sözleşme Yönetimini Kolaylaştırın:

Modüler yapı sayesinde farklı bileşenleri ayrı ayrı güncelleyebilirsiniz.





Sonuç

Solidity’de modüler yapı, akıllı sözleşmeleri daha okunabilir, güvenli ve esnek hale g
etirir. Miras, kütüphaneler ve arayüzler, büyük ve kompleks projelerde kod tekrarını önleyerek gas maliyetlerini düşürür.


10. Solidity’de Proxy Sözleşmeler ve Akıllı Sözleşme Yükseltme (Upgradeability)

Akıllı sözleşmeler deploy edildikten sonra değiştirilemez. Ancak bazı durumlarda, akıllı sözleşmelerin güncellenmesi gerekir. Örneğin:
✔ Hata düzeltmeleri ve güvenlik açıklarının giderilmesi,
✔ Yeni özelliklerin eklenmesi,
✔ Gas ücretlerinin optimize edilmesi gibi sebeplerle sözleşmelerin yükseltilmesi (upgrade) gerekebilir.

Bu bölümde Solidity’de proxy sözleşmeler kullanarak akıllı sözleşme yükseltme yöntemlerini ele alacağız.


---

1. Akıllı Sözleşmelerin Değiştirilemezlik Sorunu

Solidity’de akıllı sözleşmeler blockchain’e deploy edildikten sonra kodları değiştirilemez.

Örneğin, aşağıdaki gibi bir sözleşme deploy edildiğinde:

contract Example {
uint256 public value;

function setValue(uint256 _value) public {
value = _value;
}
}

Bu sözleşmede bir hata olursa veya yeni bir fonksiyon eklenmesi gerekirse, sözleşme yeniden deploy edilmelidir. Ancak eski veriler kaybolur ve sözleşmeyi kullanan kullanıcılar için uyumsuzluk yaşanabilir.

Bu sorunu aşmak için Proxy Pattern kullanılır.


---

2. Proxy Sözleşmelerin Mantığı

Proxy yapısı iki ana bileşenden oluşur:

1. Proxy Sözleşmesi (Storage Sahibi) → Kullanıcılar proxy adresi üzerinden etkileşime girer.


2. Implementation Sözleşmesi (Mantık İçeren Kısım) → İşlevlerin tanımlandığı asıl sözleşme.



Proxy mekanizması sayesinde kullanıcılar hep aynı adresi kullanarak etkileşime girer, ancak arka planda mantık güncellenebilir.


---

3. Proxy Pattern ile Akıllı Sözleşme Yükseltme

3.1. Proxy Kullanarak Delegatecall ile Yönlendirme

Proxy, delegatecall fonksiyonunu kullanarak çağrıları implementation sözleşmesine yönlendirir.

// Proxy Sözleşmesi (Yönlendirici)
contract Proxy {
address public implementation;

constructor(address _implementation) {
implementation = _implementation;
}

fallback() external payable {
(bool success, bytes memory data) = implementation.delegatecall(msg.data);
require(success, "Delegatecall basarisiz!");
}
}

fallback() fonksiyonu gelen çağrıları implementation sözleşmesine yönlendirir.

delegatecall sayesinde proxy’nin depolama alanı kullanılır, ancak iş mantığı implementation sözleşmesinde çalıştırılır.



---

3.2. Implementation Sözleşmesi (Mantık İçeren Sözleşme)

Proxy sözleşmesi yalnızca bir yönlendirme mekanizmasıdır. Gerçek iş mantığı aşağıdaki implementation sözleşmesinde bulunur.

contract LogicV1 {
uint256 public value;

function setValue(uint256 _value) public {
value = _value;
}
}

Burada value değişkeni proxy’nin depolama alanına yazılır, ancak fonksiyonlar bu sözleşmede tanımlıdır.




3.3. Yeni Versiyonun Deploy Edilmesi

Yeni bir özellik eklemek için LogicV2 adlı bir sözleşme oluşturulabilir:

contract LogicV2 {
uint256 public value;

function setValue(uint256 _value) public {
value = _value;
}

function doubleValue() public {
value = value * 2;
}
}

Bu yeni versiyon deploy edildikten sonra proxy’nin yönlendirdiği implementation adresi güncellenerek yeni kod kullanılabilir.

Proxy güncelleme fonksiyonu ekleyelim:

contract Proxy {
address public implementation;
address public owner;

constructor(address _implementation) {
implementation = _implementation;
owner = msg.sender;
}

function upgrade(address _newImplementation) public {
require(msg.sender == owner, "Sadece owner guncelleyebilir");
implementation = _newImplementation;
}

fallback() external payable {
(bool success, bytes memory data) = implementation.delegatecall(msg.data);
require(success, "Delegatecall basarisiz!");
}
}

Proxy’nin güncellenmesi:

proxy.upgrade(address(newLogicV2));

Bu işlem sonucunda proxy yeni implementation sözleşmesine yönlendirilecek ve doubleValue() gibi yeni fonksiyonlar kullanılabilir hale gelecektir.




4. OpenZeppelin Transparent Proxy Kullanımı

OpenZeppelin, güvenli bir proxy yapısı sunar.

// OpenZeppelin Transparent Proxy Kullanımı
import "@openzeppelin/contracts/proxy/TransparentUpgradeableProxy.sol";

contract MyProxy is TransparentUpgradeableProxy {
constructor(
address _logic,
address admin_,
bytes memory _data
) TransparentUpgradeableProxy(_logic, admin_, _data) {}
}

Bu yapı sayesinde proxy yöneticisi sözleşmeyi güvenli bir şekilde yükseltebilir.




5. Proxy Kullanımının Avantajları ve Dezavantajları



6. Proxy ile Güncellenebilir ERC-20 Token Örneği

Aşağıdaki kod, proxy ile yükseltilebilir bir ERC-20 token oluşturmayı gösterir.

6.1. İlk Token Sözleşmesi (LogicV1)

contract TokenV1 {
mapping(address => uint256) public balances;

function mint(address _to, uint256 _amount) public {
balances[_to] += _amount;
}
}

6.2. Güncellenmiş Token Sözleşmesi (LogicV2)

contract TokenV2 {
mapping(address => uint256) public balances;

function mint(address _to, uint256 _amount) public {
balances[_to] += _amount;
}

function burn(address _from, uint256 _amount) public {
require(balances[_from] >= _amount, "Yetersiz bakiye!");
balances[_from] -= _amount;
}
}

Proxy kullanılarak TokenV1’den TokenV2’ye geçiş yapılabilir:

proxy.upgrade(address(TokenV2));

Bu sayede varolan kullanıcılar adres değiştirmeden yeni token özelliklerinden yararlanabilir.




7. Proxy Kullanırken Dikkat Edilmesi Gerekenler

✅ Storage Slot Uyumluluğu:

Yeni versiyonlar eski versiyonlarla uyumlu olmalıdır.


✅ Güvenlik Önlemleri:

Güncelleme işlemlerinin sadece yetkili kişiler tarafından yapılmasını sağlayın.


✅ Gas Optimizasyonu:

Proxy maliyetleri artırabileceği için gereksiz proxy kullanmaktan kaçının.



Sonuç

Proxy sözleşmeler, akıllı sözleşmelerin güncellenebilir olmasını sağlayarak büyük avantajlar sunar. Ancak delegatecall, storage uyumluluğu ve güvenlik açıkları dikkate alınmalıdır.

Özet:

✔ Proxy’ler, kullanıcıların hep aynı adresi kullanmasını sağlar.
✔ Yükseltilebilir akıllı sözleşmeler oluştu
rmayı mümkün kılar.
✔ Storage uyumluluğuna dikkat edilmelidir.
✔ Güvenlik önlemleri alınmazsa proxy’ler saldırıya açık olabilir.

Bir sonraki bölümde Solidity’de Gas Optimizasyonu ve Maliyet Düşürme Teknikleri konusunu ele alacağız.


11. Solidity’de Gas Optimizasyonu ve Maliyet Düşürme Teknikleri

Ethereum üzerinde akıllı sözleşmeler çalıştırılırken gas ücretleri ödenir. Gas ücretlerini optimize etmek, daha düşük maliyetle akıllı sözleşme geliştirmek açısından kritik öneme sahiptir.

Bu bölümde Solidity’de gas optimizasyonu için en iyi uygulamaları inceleyeceğiz.




1. Gas Nedir ve Neden Önemlidir?

Ethereum ağında her işlem belirli bir hesaplama gücü gerektirir ve bu gücün maliyeti gas birimiyle ölçülür.

✔ Gas Ücreti Hesaplama Formülü:

Toplam Maliyet = Gas Kullanımı × Gas Fiyatı

Örneğin:

Basit bir ETH transferi → ~21,000 gas

Bir ERC-20 token transferi → ~50,000 - 100,000 gas

Karmaşık bir DeFi işlemi → 1,000,000+ gas


Gas ücretlerini düşürmek için akıllı sözleşme optimizasyonları gereklidir.




2. Solidity’de Gas Optimizasyonu İçin En İyi Teknikler

2.1. Depolama Kullanımını Azaltın (Storage Optimization)

Ethereum'da depolama işlemleri (SSTORE, SLOAD) en fazla gas tüketen işlemler arasındadır.

Kötü Örnek: Her Seferinde Depolamayı Güncellemek

contract BadStorage {
uint256 public counter;

function increment() public {
counter += 1; // Her çağrıda storage güncellenir → Pahalıdır
}
}

✔ Çözüm: Değişkeni önce memory’de tutup, sonra storage’a yazın.

contract OptimizedStorage {
uint256 public counter;

function increment() public {
uint256 temp = counter; // Memory kullanımı → Daha ucuz
temp += 1;
counter = temp; // Storage’a sadece 1 kere yazılır
}
}

✔ Sonuç: SSTORE maliyeti %50+ oranında düşer.


2.2. Değişkenleri Doğru Veri Tipinde Tanımlayın

Solidity’de uint256 varsayılan veri tipidir ancak bazen gereğinden fazla gas harcar.

Kötü Örnek: Gereksiz Büyük Veri Tipleri Kullanmak

contract BadVariables {
uint256 public largeNumber; // Her zaman uint256 gerekli değildir
}

✔ Çözüm: Eğer büyük sayılar gerekmiyorsa, uint8, uint16, uint32 gibi küçük veri tipleri kullanın.

contract OptimizedVariables {
uint32 public smallNumber; // Daha düşük gas maliyeti
}

✔ Sonuç: Küçük veri tipleri stack kullanımını optimize eder, gas tasarrufu sağlar.



2.3. Döngü (Loop) Kullanımını Optimize Edin

Döngüler Ethereum’da yüksek maliyetlidir çünkü her adım gas tüketir.

Kötü Örnek: Gereksiz Döngüler Kullanmak

contract BadLoop {
uint256[] public numbers;

function sum() public view returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < numbers.length; i++) {
total += numbers; // Her adım gas harcar
}
return total;
}
}

✔ Çözüm: Mapping kullanımı ve önceden hesaplama yaparak maliyeti azaltın.

contract OptimizedLoop {
mapping(address => uint256) public balances;
uint256 public totalBalance;

function deposit(uint256 amount) public {
balances[msg.sender] += amount;
totalBalance += amount; // Döngü kullanmadan toplam hesaplanır
}
}

✔ Sonuç: Döngüler yerine mapping ve state değişkenleri kullanarak gas tasarrufu sağlanır.




2.4. Gereksiz İşlev Çağrılarını Azaltın

Her fonksiyon çağrısı ek maliyet getirir. Özellikle iç içe fonksiyon çağrılarından kaçınılmalıdır.

Kötü Örnek: Fonksiyonları Zincirleme Çağırmak

contract BadCalls {
function add(uint256 a, uint256 b) public pure returns (uint256) {
return sum(a, b);
}

function sum(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
}

✔ Çözüm: Tek bir fonksiyon içinde hesaplamaları yapın.

contract OptimizedCalls {
function add(uint256 a, uint256 b) public pure returns (uint256) {
return a + b; // Gereksiz çağrıları önler
}
}

✔ Sonuç: Daha düşük gas maliyetiyle aynı işlevi gerçekleştirir.




2.5. constant ve immutable Kullanımı

Eğer bir değişken sözleşme oluşturulduktan sonra değişmeyecekse, constant veya immutable olarak tanımlanabilir.

Kötü Örnek: Değişkenleri Normal Tanımlamak

contract BadConstants {
uint256 public fee = 100; // Storage’de saklanır, pahalıdır
}

✔ Çözüm: constant veya immutable kullanın.

contract OptimizedConstants {
uint256 public constant FEE = 100; // Storage yerine bytecode’da saklanır
}

✔ Sonuç: Gas maliyetini %50+ oranında azaltır.



2.6. events Kullanarak Log Tutma

Depolama maliyetinden kaçınmak için verileri direkt olarak blockchain’e yazmak yerine event kullanın.

Kötü Örnek: Depolamayı Log Tutmak İçin Kullanmak

contract BadLogging {
string[] public logs;

function addLog(string memory message) public {
logs.push(message); // Storage kullanır → Pahalıdır
}
}

✔ Çözüm: Event kullanarak daha az maliyetle log tutun.

contract OptimizedLogging {
event LogAdded(string message);

function addLog(string memory message) public {
emit LogAdded(message); // Blockchain’e yazılır, storage yerine event kullanır
}
}

✔ Sonuç: Event kullanımı storage’den çok daha ucuzdur.



3. Gas Optimizasyonu İçin En İyi Pratikler (Özet)




Sonuç

Gas optimizasyonu, Ethereum’da maliyetleri düşürerek daha verimli akıllı sözleşmeler oluşturmayı sağlar.

✔ Storage yerine memory kullanarak maliyeti düşürün.
✔ Gere
ksiz döngülerden kaçının.
✔ constant ve immutable değişkenleri kullanın.
✔ Mapping ve event kullanımını artırın.


12. Solidity’de Güvenlik Uygulamaları ve En Yaygın Hatalar

Akıllı sözleşmeler değiştirilemez olduğu için bir hata veya güvenlik açığı, geri döndürülemez kayıplara yol açabilir. Bu nedenle, Solidity’de güvenli kod yazmak hayati önem taşır.

Bu bölümde, Solidity’de en yaygın güvenlik açıklarını, saldırı türlerini ve güvenlik önlemlerini inceleyeceğiz.


---

1. Akıllı Sözleşmelerde Güvenlik Neden Önemlidir?

✔ Ethereum’da milyonlarca dolar değerinde varlık akıllı sözleşmelerde kilitli
✔ Kod hataları projelerin çökmesine ve kullanıcıların fonlarını kaybetmesine neden olabilir
✔ Birçok büyük hack olayı, Solidity güvenlik açıkları nedeniyle yaşandı

Örnek: The DAO Saldırısı (2016)

150 milyon dolarlık Ethereum çalındı.

Nedeni: Reentrancy Attack (Yeniden Giriş Saldırısı)


Bu tür olaylardan kaçınmak için akıllı sözleşmeler çok dikkatli test edilmeli ve güvenlik önlemleri alınmalıdır.


---

2. En Yaygın Güvenlik Açıkları ve Çözümleri

2.1. Reentrancy Attack (Yeniden Giriş Saldırısı)

✔ Tanım: Saldırgan, fon çekme işlemi sırasında tekrar tekrar aynı fonksiyonu çağırarak bakiyeyi sıfırlanmadan önce birden fazla kez para çeker.

Kötü Örnek: Güvenlik Açığı Olan Fon Çekme Kodu

contract Vulnerable {
mapping(address => uint256) public balances;

function deposit() public payable {
balances[msg.sender] += msg.value;
}

function withdraw() public {
require(balances[msg.sender] > 0, "Yetersiz bakiye!");
(bool success, ) = msg.sender.call{value: balances[msg.sender]}("");
require(success, "Transfer basarisiz!");
balances[msg.sender] = 0; // **Gecikmeli güncelleme → Açık var!**
}
}

Sorun: balances[msg.sender] = 0; işlemi en sona bırakıldığı için saldırgan, call() fonksiyonunu kullanarak tekrar withdraw çağırabilir ve para çekme işlemini tekrar edebilir.

✔ Çözüm: Önce bakiyeyi sıfırlayın, sonra transfer yapın!

contract Secure {
mapping(address => uint256) public balances;

function deposit() public payable {
balances[msg.sender] += msg.value;
}

function withdraw() public {
uint256 amount = balances[msg.sender];
require(amount > 0, "Yetersiz bakiye!");

balances[msg.sender] = 0; // **Önce bakiyeyi sıfırla!**
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer basarisiz!");
}
}

✔ Sonuç: Saldırganın tekrar tekrar withdraw çağırmasını engeller.

✅ Ekstra Önlem: Reentrancy Guard kullanın!

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract SecureWithGuard is ReentrancyGuard {
function withdraw() public nonReentrant {
// Kod burada
}
}


---

2.2. Integer Overflow & Underflow (Sayı Taşması ve Taşma Problemleri)

✔ Tanım: Sayılar maksimum veya minimum sınırlarını aştığında beklenmedik davranışlar oluşur.

Kötü Örnek: Güvenlik Açığı İçeren Çarpma İşlemi

contract Vulnerable {
uint256 public maxSupply = 2**256 - 1;

function multiply(uint256 a, uint256 b) public pure returns (uint256) {
return a * b; // **Overflow olabilir!**
}
}

Saldırgan büyük sayılar girerek overflow yaratabilir ve beklenmedik sonuçlar elde edebilir.

✔ Çözüm: SafeMath Kütüphanesi Kullanımı

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

contract Secure {
using SafeMath for uint256;

function multiply(uint256 a, uint256 b) public pure returns (uint256) {
return a.mul(b); // **Güvenli işlem yapar**
}
}

✔ Sonuç: Matematiksel taşmaları önler.

✅ Not: Solidity 0.8 ve sonrası otomatik overflow korumasına sahiptir, ancak ekstra önlemler alınması önerilir.


---

2.3. Access Control (Yetkilendirme Açıkları)

✔ Tanım: Yalnızca yetkili adreslerin belirli işlemleri yapmasına izin verilmelidir.

Kötü Örnek: Admin Kontrolü Olmayan Fonksiyon

contract Vulnerable {
address public owner;

function setOwner(address newOwner) public {
owner = newOwner; // **Herkes admin olabilir!**
}
}

✔ Çözüm: OnlyOwner Modifiyeri Kullanımı

contract Secure {
address public owner;

constructor() {
owner = msg.sender;
}

modifier onlyOwner() {
require(msg.sender == owner, "Yetkiniz yok!");
_;
}

function setOwner(address newOwner) public onlyOwner {
owner = newOwner;
}
}

✔ Sonuç: Sadece admin yetkisi olan kullanıcılar işlemleri gerçekleştirebilir.

✅ Alternatif: OpenZeppelin Ownable Kütüphanesi Kullanımı

import "@openzeppelin/contracts/access/Ownable.sol";

contract SecureWithOwnable is Ownable {
function setOwner(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
}


---

2.4. Timestamp Manipülasyonu

✔ Tanım: Madenciler block.timestamp değerini manipüle edebilir.

Kötü Örnek: Rastgele Sayı Üretiminde Timestamp Kullanımı

contract Vulnerable {
function random() public view returns (uint256) {
return uint256(block.timestamp) % 100; // **Manipüle edilebilir!**
}
}

Madenciler block.timestamp değerini değiştirerek sonucu tahmin edebilirler.

✔ Çözüm: Chainlink VRF (Gerçek Rastgele Sayı Üretimi) Kullanımı

import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";

contract SecureRNG is VRFConsumerBase {
function getRandomNumber() public {
// Chainlink VRF ile güvenli rastgele sayı alınır
}
}

✔ Sonuç: Manipülasyona karşı güvenli bir rastgele sayı oluşturulur.


---

3. En Yaygın Solidity Güvenlik Açıkları ve Çözümleri (Özet)


---

Sonuç

✔ Güvenli akıllı sözleşmeler yazmak için en iyi uygulamaları kullanın.

Testler ve güvenlik denetimleri (audit) yaptırın.
✔ OpenZeppelin güvenlik kütüphanelerinden yararlanın.

13. Solidity’de Gelişmiş Veri Yapıları ve Optimizasyon Teknikleri

Solidity'de verileri doğru bir şekilde yapılandırmak ve depolamak, hem gas maliyetlerini optimize etmek hem de işlemlerin verimliliğini artırmak için kritik öneme sahiptir. Bu bölümde, Solidity’deki gelişmiş veri yapılarını ve optimizasyon tekniklerini detaylı bir şekilde inceleyeceğiz.


---

1. Solidity’de Veri Yapıları

Solidity, çeşitli veri yapıları sunar ve bu yapılar farklı senaryolarda verimli bir şekilde kullanılabilir. Verilerin doğru bir şekilde organize edilmesi, akıllı sözleşmelerin güvenli ve ekonomik olmasını sağlar.

1.1. Temel Veri Yapıları

1.1.1. Arrays (Diziler)

Diziler, Solidity'deki temel veri yapılarını oluşturur. Dizilerdeki öğelere sıralı bir şekilde erişilir ve dizilerin boyutları değiştirilebilir (dynamic arrays) veya sabit (fixed-size arrays) olabilir.

Örnek: Dinamik Dizi

uint[] public numbers;

function addNumber(uint number) public {
numbers.push(number);
}

function getNumber(uint index) public view returns (uint) {
return numbers[index];
}

Diziler, sıralı veri saklama ve okuma için idealdir ancak çok büyük diziler gas maliyetini artırabilir.

1.1.2. Mappings (Haritalar)

mapping Solidity’deki en verimli veri yapılarından biridir ve genellikle anahtar-değer çiftlerini saklamak için kullanılır. Mapping, daha hızlı arama ve değişiklikler sağlar ancak diziler gibi iterasyon yapmaya uygun değildir.

Örnek: Mapping Kullanımı

mapping(address => uint256) public balances;

function deposit() public payable {
balances[msg.sender] += msg.value;
}

function withdraw(uint256 amount) public {
require(balances[msg.sender] >= amount, "Yetersiz bakiye");
balances[msg.sender] -= amount;
}

Bu yapı, özellikle kullanıcı bakiyelerini takip etmek için idealdir.

1.1.3. Structs (Yapılar)

Struct, farklı türlerdeki verileri bir arada tutabilen özel bir veri yapısıdır. Structlar, verileri daha düzenli bir şekilde saklamaya olanak tanır.

Örnek: Struct Kullanımı

struct User {
string name;
uint256 age;
}

mapping(address => User) public users;

function setUser(string memory _name, uint256 _age) public {
users[msg.sender] = User(_name, _age);
}

function getUser(address _user) public view returns (string memory, uint256) {
return (users[_user].name, users[_user].age);
}

Struct’lar, verilerin daha anlamlı bir şekilde gruplandırılmasını sağlar. Ancak, büyük struct’lar gas maliyetlerini artırabilir.


---

2. Veri Yapılarını Optimize Etme Teknikleri

2.1. Veri Yapılarında En Verimli Seçim

Akıllı sözleşmelerde kullanılan veri yapıları, gas maliyetleri üzerinde büyük bir etkiye sahiptir. Optimizasyon yapmak için, kullanım amacına göre en uygun veri yapısını seçmek çok önemlidir.

2.1.1. Arrays vs Mappings

Diziler genellikle daha fazla gas maliyeti gerektirir çünkü sıralama ve işlem yapma gereksinimi vardır. Mappings ise anahtar-değer çiftlerini doğrudan erişmek için optimize edilmiştir. Eğer sıralı bir veri yapısına ihtiyacınız yoksa, mapping kullanmak daha verimli olabilir.

Örnek: Mapping vs Array

// Array kullanımı
uint[] public numbers;

function addNumber(uint number) public {
numbers.push(number);
}

// Mapping kullanımı
mapping(uint => uint) public numberMapping;

function addNumber(uint number) public {
numberMapping[block.timestamp] = number;
}

Sonuç: Mapping kullanımı genellikle daha verimli ve gas tasarrufu sağlar.

2.1.2. Struct ve Dynamic Arrays

Büyük struct’lar kullanmak, gas maliyetlerini artırabilir. Bu nedenle, struct’lar küçük ve sadece gerekli veri öğelerini içerecek şekilde yapılandırılmalıdır.

Optimizasyon İpucu: Eğer struct’lar birden fazla veri öğesi içeriyorsa, sadece gereksiz alanları depolamak yerine, sadece gerekli bilgileri saklamak daha iyi bir yaklaşımdır.


---

2.2. Storage ve Memory Kullanımı

Solidity’de storage, memory ve stack olmak üzere üç farklı veri alanı bulunur. Her biri farklı maliyetlere sahiptir.

2.2.1. Storage vs Memory

Storage, blockchain üzerinde kalıcı olarak saklanır ve gas maliyeti yüksektir.

Memory, yalnızca işlem sırasında geçici olarak saklanır ve daha ucuzdur.

Stack, çok küçük veri elemanlarını geçici olarak tutar ve en hızlı olanıdır.


Memory Kullanımının Avantajı:

contract Optimized {
function optimize() public pure {
uint; // Memory'de veri saklama
tempArray[0] = 5;
}
}

Sonuç: Veriyi memory'de tutarak storage'a göre daha az gas harcanır. Ancak, büyük veri yapıları için memory kullanımı da sınırlıdır.

2.2.2. Storage Kullanımı ve Sıralama

Storage üzerindeki veri değişiklikleri çok pahalıdır. Bu yüzden, verilerin sırasını azaltmak ve gereksiz veri yazımını engellemek önemlidir.

Optimizasyon İpucu:

Fazla yazma işlemleri yerine veri güncelleme yapılmalı, böylece her değişiklikte storage güncellenmez.

Struct’lar ve dizilerde gereksiz alanlardan kaçınılmalıdır.



---

2.3. Gas Tasarrufu Sağlayan Veri Yapıları

2.3.1. Bitwise Operasyonlar Kullanımı

Bitwise işlemleri, veri saklama ve karşılaştırma işlemleri için kullanışlıdır ve genellikle gas tasarrufu sağlar.

Örnek:

contract BitwiseExample {
uint256 public data;

function setBit(uint256 position) public {
data |= (1 << position); // Bitwise OR ile veri ekler
}

function clearBit(uint256 position) public {
data &= ~(1 << position); // Bitwise AND ile veri siler
}
}

Sonuç: Bitwise işlemleri, çok düşük maliyetli ve verimli veri yönetimi sağlar.

2.3.2. Packed Structs Kullanımı

Eğer struct'larda veri türleri küçükse, bunları packed struct şeklinde düzenlemek gas tasarrufu sağlar.

Örnek:

struct Packed {
uint8 a; // 1 byte
uint16 b; // 2 byte
uint8 c; // 1 byte
}

contract PackedStruct {
Packed public packedData;

function setPackedData(uint8 _a, uint16 _b, uint8 _c) public {
packedData = Packed(_a, _b, _c);
}
}

Sonuç: Packing, veri depolama alanını optimize eder ve daha az gas harcar.


---

3. Sonuç: En İyi Veri Yapıları ve Optimizasyon Teknikleri

✔ Mapping ve memory kullanımı genellikle daha düşük gas maliyetleri ile sonuçlanır.
✔ Struct’ları optimize edin ve gereksiz veri öğelerinden kaçının.
✔ Bitwise işlemler ve packed struct gibi gelişmiş tekniklerle gas tasar
rufu sağlayın.
✔ Storage yerine memory kullanarak veri işlemleri daha hızlı ve ucuz hale gelir.

Bugün uzun bir sürenin ardından, Solidity hakkında yazdığımız makalenin 13 bölümünü sizlerle paylaşıyorum. Saatler süren bir çalışma sonucu hazırladım ve umarım sizler için faydalı olur. Geri bildirimlerinizi bekliyorum

Makalenin ikinci kısmını yarın getireceğim, o zaman kalan bölümleri de detaylı bir şekilde tamamlayacağım.

Hep birlikte daha çok şey öğrenmek ve paylaşmak dileğiyle.
 

Forum istatistikleri

Konular
14.097
Mesajlar
70.342
Kullanıcılar
7.049
Son üye
slhttnkndk
Geri
Üst