Yeni Başlayanlar için Solidity – Akıllı Sözleşme Geliştirme Hızlandırılmış Kursu
  1. Anasayfa
  2. Blok Zinciri

Yeni Başlayanlar için Solidity – Akıllı Sözleşme Geliştirme Hızlandırılmış Kursu

Akıllı Sözleşme Geliştirme Hızlandırılmış Kursu

0

Yeni Başlayanlar için Solidity

Bugün size bir blockchain geliştiricisi olabilmeniz için Solidity ile programlamaya nasıl başlayacağınızı anlatan, bir seri paylaşacağım. Yeni başlayan biri olarak Solidity ile ilk Ethereum akıllı sözleşmelerinizi nasıl yazacağınızı göstereceğim! Bu eğitime başlamak için dil hakkında hiçbir şey bilmiyorsunuz. Hatta tüm programlamayı web tarayıcınızın içinde yapacağız, böylece herhangi bir geliştirme aracı veya benzeri bir şey yüklemeniz gerekmeyecek.

Solidity Programlama Diline Giriş – Yeni Başlayanlar için Ethereum Blockchain Geliştirici Eğitimi

Yeni Başlayanlar için Solidity

İşte ele alacağımız şeylerin bir özeti:

  • Solidity’e Giriş
  • Veri Tipleri ve Veri Yapıları
  • İşlev Görünürlüğü, Değiştiriciler ve Zaman
  • Eter Gönderme ve Olaylar
  • Akıllı Sözleşme Etkileşimi ve Kalıtım

Solidity’e Giriş

Bu adım adım tanıtımla birlikte takip etmek için yukarıdaki videoyu izleyin!

Solidity, Ethereum blok zinciri için akıllı sözleşmeler yazmak için ana programlama dilidir. Sözleşme odaklı bir dildir; bu, akıllı sözleşmelerin blok zinciri ile işlem yapan tüm programlama mantığını depolamaktan sorumlu olduğu anlamına gelir. JavaScript, Python ve C++’a çok benzeyen üst düzey bir programlama dilidir. Blok zincirine bağlı Ethereum Düğümlerinde barındırılan Ethereum Sanal Makinesi (EVM) üzerinde çalışacak şekilde tasarlanmıştır. Statik olarak yazılmıştır ve kalıtımı, kitaplıkları ve daha fazlasını destekler! Kısacası, endüstriyel güçlü blok zinciri uygulamaları oluşturmak için ihtiyacınız olan tüm yeteneğe sahiptir.

Solidity’e Giriş

Bu eğitimdeki tüm kodu yazmak için Remix‘i kullanacağız. Remix, akıllı sözleşmeler yazmanıza, derlemenize ve dağıtmanıza izin veren tarayıcı tabanlı bir IDE’dir! Kalıcı dosya depolama gibi birçok güzel özelliği var! Başlamak için herhangi bir geliştirici aracı indirmemize veya herhangi bir şey yüklememize gerek kalmaması için Remix’i kullanacağız. Bu öğreticiyi takip etmek için yeni bir sekmede Remix‘e gidin.

Biraz Solidity kodu yazmak için yeni bir dosya oluşturarak başlayalım. Bunu ekranın sol tarafındaki dosya tarayıcısında yapabilirsiniz.

MyContract.sol adında yeni bir dosya oluşturalım. Bu dosyanın ilk satırında, kullanmak istediğimiz Solidity programlama dilinin sürümünü bildireceğiz:

pragma solidity ^0.4.24;

Şimdi akıllı sözleşmeyi şu şekilde ilan edebiliriz:

pragma solidity ^0.4.24;
contract MyContract {
    // ...
}

Devam etmeden önce birkaç şeyi açıklayayım. Akıllı sözleşme, Ethereum blok zincirinde yürütülen bir kod parçasıdır. Web üzerinde herkesin erişebileceği bir API mikro hizmeti gibi çalışır. Akıllı sözleşmenin tüm kodu herkese açıktır ve ağa bağlı herkesin akıllı sözleşmedeki işlevleri aramasına izin verebiliriz.

Şimdi bu akıllı sözleşmeyi oluşturmaya devam edelim. İlk olarak, şunları yapabilecek basit bir “depolama” akıllı sözleşmesi programlayacağız:

  • Değer depolamak
  • Bu değeri almak

Bunun gibi akıllı sözleşmede bir dize değeri depolamanın bir yolunu oluşturarak başlayacağız. Bunu “value” adında bir değişkenle yapacağız. Solidity statik olarak yazılmış bir dildir, bu nedenle değişkeni şu şekilde bildirirken önce veri türünü belirtmeliyiz:

pragma solidity ^0.4.24;
contract MyContract {
    string value;

}

Bu değişkene “durum değişkeni” adı verilir, çünkü aslında verileri blok zincirinde tutar. Bu değeri ne zaman ayarlasak, dizi blok zincirine kaydedilecektir! Depoya değil, belleğe yazılır. Bu değişkenin ayrıca özel bir kapsamı vardır, çünkü yalnızca işlevlerin içinde erişilebilen ve işlev çağrıldıktan sonra kalıcı olmayan yerel bir değişkenin aksine akıllı sözleşmenin tamamına erişilebilir. Bu öğretici ile devam ederken bunun daha fazla örneğini göreceğiz.

Şimdi bu değeri depodan okuyacak bir fonksiyon oluşturalım. Aşağıdaki gibi function anahtar sözcüğüyle get() adlı bir işlev bildirerek başlayacağız:

function get() {
    // ...
}

Şimdi, şunun gibi return anahtar sözcüğüyle durum değişkeninden değeri döndüreceğiz:

function get() {
    return value;
}

Şimdi bu işlevin “görünürlüğünü” herkese açık hale getireceğiz, böylece blok zincirine bağlı herkes onu çağırabilir (sadece akıllı sözleşme kodunun içinden değil):

function get() public view {
    return value;
}

Son olarak, işlev için string dönüş değerini belirteceğiz:

function get() public view returns(string) {
    return value;
}

Mükemmel! Şimdi bu değeri akıllı sözleşmeden okumanın bir yolu var. Bunu biraz derledikten sonra nasıl yapacağınızı göstereceğim. Oraya varmadan önce, bu değeri akıllı sözleşmenin dışından ayarlamak için bir yol oluşturalım. Bunun gibi bir set işlevi oluşturacağız:

function set(string _value) public {
    // ...
}

Basitçe, string tipinde bir _value argümanını kabul eden bir fonksiyon yarattık. Bu işlev aynı zamanda herkesin görebileceği şekilde blok zincirine bağlı herkesin onu çağırabilmesidir. Şimdi akıllı sözleşme değerini şu şekilde güncelleyelim:

function set(string _value) public {
    value = _value;
}

Burada basitçe iletilen değeri _value olarak atadık ve onu değer durumu değişkenine atadık. Başına bir alt çizgi eklenen _value‘nun yalnızca yerel bir değişken olduğuna dikkat edin. Bu, Solidity kodunun yanı sıra diğer dilleri yazarken yaygın bir kuraldır.

Şimdi değer durumu değişkeni için varsayılan bir değer belirleyelim. Bunu akıllı sözleşme yapıcı işlevi içinde şöyle yapacağız:

constructor() public {
    value = "myValue";
}

İlk önce yapıcı işlevini yapıcı anahtar sözcüğü ile bildiririz. Bu işlev, akıllı sözleşme dağıtıldığında yalnızca bir kez çalıştırılır. Kamusal görünürlüğe de sahip olmalıdır.

Şimdi bu tam kaynak kodu! Bu akıllı sözleşmeyi nasıl derleyip dağıtabileceğimizi görelim. Öncelikle tarayıcınızın sağ tarafında derleyici sürümünü ayarlayacağız. Bu kodu derlemek için 0.4.25 sürümünü seçeceğiz.

Şimdi ortamı seçelim. Tarayıcımızın içinde bize simüle edilmiş bir blok zinciri verecek olan JavaScript sanal makinesini seçeceğim.

Şimdi bunu tek bir tuşa basarak kolayca dağıtabiliriz!

Mükemmel! Az önce akıllı sözleşmeyi dağıttınız. Akıllı sözleşmenin arayüzüne dayalı olarak oluşturulan form ile aşağıdaki işlevlerini çağırarak akıllı sözleşme ile etkileşime girebilirsiniz.

Önce değeri okuyalım. get() fonksiyonuna tıklayalım. Yapıcıda ayarlanan varsayılan “myValue” değerini görmelisiniz.

Şimdi set() fonksiyonu ile değeri güncelleyelim. Form alanına yeni bir değer ekleyin, şunun gibi tırnak işaretleri içine aldığınızdan emin olun: “New Value”. Şimdi çalıştırın! Şimdi değeri tekrar okuyun. “New Value” olarak değiştirilmelidir!

Metin düzenleyicinin altındaki bu işlem penceresini fark etmiş olabilirsiniz. Bu, bu sanal blok zincirindeki tüm işlemlerin tam listesidir. Unutmayın, Etherum blok zinciri, halka açık defteri oluşturmak için “birbirine zincirlenmiş” “bloklar” adı verilen kayıt demetlerinden oluşur. Tüm bu blokların temel birimleri işlemlerdir. Bunları aşağıda listelenmiş olarak görüyorsunuz. Makbuzun tüm ayrıntılarını görmek için “aşağı” oku tıklayabilirsiniz.

Tamam bu kadar! 🎉 Az önce Solidity programlama diliyle ilk Ethereum akıllı sözleşmenizi yazdınız! Bu kodu geliştireceğimiz ve dil hakkında daha fazlasını öğreneceğimiz bir sonraki bölüme geçelim!

Veri Tipleri ve Veri Yapıları

Yeni Başlayanlar için Solidity – Akıllı Sözleşme Geliştirici Eğitimi #2

Devam etmeden önce, akıllı sözleşmemizdeki kodu, Solidity’nin bir başka sürümüyle uyumlu olacak şekilde güncelleyelim. Akıllı sözleşme kodundaki ilk satırı şu şekilde değiştirebiliriz:

pragma solidity ^0.5.1;

Bunu yapmak, ileriye dönük Solidity’nin mevcut sürümü için en iyi uygulamaları öğrenmemize yardımcı olacak! Şimdi solidity’nin yeni versiyonu için uyarıları ele alalım. İlk önce get() işlevini şöyle görünecek şekilde değiştirin:

function get() public view returns(string memory) {
    return value;
}

Bellek ayrımına dikkat edin. Aynısını set() işlevi için de yapacağız:

function set(string memory _value) public {
    value = _value;
}

Harika! Artık güncel olduğumuza göre, bunları kendi Ethereum akıllı sözleşmelerinize uygulamaya başlayabilmeniz için temel veri türleri ve veri yapıları hakkında konuşalım. Bunu önce değişen veri türlerinden durum değişkenleri oluşturarak yapacağız. İlk olarak, Solidity tarafından sağlanan durum değişkenlerinin bazı güzel özelliklerine bakalım. Şu anda, sadece değer durumu değişkenini ilan ediyoruz ve değerini ayarlamak için get() işlevini kullanıyoruz. Solidity’de bunu çok daha kolay hale getiren bir kısayol var. Bunu basitçe yapabiliriz:

string public value;

Bu durum değişkeninin görünürlüğünü public olarak ayarlar, bu da akıllı sözleşmenin dışındaki herkesin değerini okuyabileceği anlamına gelir. Bunu yaptığımızda, Solidity ücretsiz olarak bir value() işlevi sağlar! Artık get() işlevine ihtiyacımız yok! Durum değişkenine şu şekilde varsayılan bir değer de atayabiliriz:

string public value = "myValue";

Artık bunu yapıcı işlevinde de ayarlamamız gerekmiyor! Bu, yazmamız gereken kod miktarını gerçekten azaltır. Bu değeri asla değişmeyecek bir sabit olarak da ayarlayabiliriz:

string public constant value = "myValue";

Artık bunu yaptığımıza göre set() fonksiyonunu kaldırmalıyız çünkü Solidity bu değeri bir sabit olduğu için güncellememize izin vermeyecektir.

Bu, Solidity’nin durum değişkenleri için sağladığı kısayollara genel bir bakış. Şimdi Solidity’de bulunan bazı farklı veri türlerini incelemek için biraz daha durum değişkeni oluşturalım. Dize durum değişkeni gibi, her zaman veri türünü, ardından değişken adını bildirmeden önce görünürlüğü bildiririz. İlk olarak, şöyle bir boolean durum değişkeni oluşturabiliriz:

bool public myBool = true;

Bu, doğru veya yanlış olabilir. Şimdi bunun gibi bir işaretsiz tamsayı oluşturabiliriz:

Şimdi şöyle bir tamsayı oluşturabiliriz:

int public myInt = 1;

Tamsayılar pozitif veya negatif, yani işaretli olabilir. Bir sayının negatif olmasını istemiyorsanız, aşağıdaki gibi işaretsiz bir tamsayı oluşturabilirsiniz:

uint public myUint = 1;

Sayı için bit sayısını belirtebiliriz. Yukarıdaki örnek varsayılan olarak 256 bit’tir. Şu şekilde açık olabiliriz:

uint256 public myUint256 = 9999;

Ayrıca değeri şu şekilde 8 bit ile sınırlayabiliriz:

uint8 public myUint8 = 8;

Enum // Numaralandırmalar

Şimdi solidity’de bazı temel veri yapılarını gözden geçirelim. İlk olarak, Solidity’de numaralandırılmış listeleri takip etmenin bir yolu olan Enum veri yapısına bakalım. Akıllı sözleşmeler yazarken bu listeyi kontrol edebiliriz. Akıllı sözleşmede şöyle bir numaralandırma oluşturalım:

enum State { Waiting, Ready, Active }

Bir örnek olarak, bu, Waiting, Ready ve Active seçeneklerini sağlayarak akıllı sözleşmenin aktif durumunu takip etmemize yardımcı olacaktır. Akıllı sözleşmenin mevcut durumunu şu şekilde kontrol edebiliriz:

State public state;

Şimdi, yapıcıda varsayılan durumu ayarlayabiliriz:

constructor() public {
    state = State.Waiting;
}

Şimdi, yapıcıda varsayılan durumu ayarlayabiliriz:

constructor() public {
    state = State.Waiting;
}

Mevcut durumu şu şekilde active olarak güncelleyebiliriz:

function activate() public {
    state = State.Active;
}

Ve son olarak, durumun şu anda şu şekilde aktif olup olmadığını görmek için enum listesine bakabiliriz:

function isActive() public view returns(bool) {
    return state == State.Active;
}

Şimdi son akıllı sözleşme kodu şöyle görünmelidir:

pragma solidity 0.5.1;

contract MyContract {
    enum State { Waiting, Ready, Active }
    State public state;

    constructor() public {
        state = State.Waiting;
    }

    function activate() public {
        state = State.Active;
    }

    function isActive() public view returns(bool) {
        return state == State.Active;
    }
}

Bu, durumu izlemek için akıllı sözleşmelerinizde numaralandırmaları nasıl kullanabileceğinize bir örnek! Başka bir örnek olarak, bu, open veya close olan bir kitlesel satış ICO akıllı sözleşmesinin durumunu izlemek için çok kullanışlıdır.

Yapılar

Solidity, structs ile kendi veri türlerinizi tanımlamanıza olanak tanır. Temel olarak, istediğiniz her türlü veriyi, değişen veri türlerinin keyfi nitelikleriyle modelleyebilirsiniz. Bir people yapısı oluşturarak bunun nasıl çalıştığına bakalım:

struct Person {
    string _firstName;
    string _lastName;
}

Burada _firstName ve _lastName olan bir kişiyi modelledik. İstediğimiz herhangi bir veri türünü belirleyebileceğimize dikkat edin! Burada her iki nitelik için de dizeler kullandık. Buraya herhangi bir veri türüyle 17’ye kadar farklı nitelik ekleyebiliriz. Şimdilik, basit tutalım ve kişiyi modellemek için sadece iki özniteliği kullanalım.

Diziler

Şimdi bu kişi yapısını saklayacak bir yere ihtiyacımız var. Bunun için bir dizi kullanalım! People dizisini şu şekilde ilan edebiliriz:

Person[] public people;

Dizi içindeki türü, yani Person‘ı bildirdiğimize dikkat edin. Ayrıca görünürlüğü public olarak ayarladık ve bunu people adlı bir durum değişkenine atadık. Bu bize bu dizinin içindeki kişilere erişmemizi sağlayacak bir işlev sağlayacaktır. Yine de şunu belirtmeliyim ki, people() işlevini akıllı sözleşme dışında çağırmak tüm diziyi döndürmez. Bunun yerine, people() işlevi, sıfır tabanlı olan bu dizine dayalı olarak dizi içindeki kişiye başvurmamıza izin verecek bir dizin argümanını kabul edecektir. Örneğin, insanlar dizisindeki ilk kişiye şu şekilde erişebiliriz:

people(0)

Şimdi bu diziye bir kişi eklemenin bir yolunu oluşturalım. Bunun gibi bir addPerson() işlevi oluşturacağız:

function addPerson(string memory _firstName, string memory _lastName) public {
    people.push(Person(_firstName, _lastName));
    peopleCount += 1;
}

Bu işlev, kişi yapısı öznitelikleri için argümanları kabul edecek, ardından yeni bir kişiyi somutlaştıracak ve onu push işleviyle people dizisine ekleyecektir. Ayrıca peopleCount durum değişkenini 1 artırır. Bu durum değişkenini akıllı sözleşmede şu şekilde uygulayabiliriz:

uint256 public peopleCount;

Bu değeri bir sayaç önbelleği olarak kullanacağız. People() işleviyle tüm people dizisini döndüremeyeceğinizi nasıl söylediğimi hatırlıyor musunuz? Bu dizinin içinde kaç kişinin olduğunu bilmek, her bir kişiyi almak için people() işlevini kaç kez çağırmamız gerektiğini bilmemize yardımcı olacaktır.

Şimdi tamamlanan akıllı sözleşme kodu şöyle görünmelidir:

pragma solidity 0.5.1;

contract MyContract {
    Person[] public people;

    uint256 public peopleCount;

    struct Person {
        string _firstName;
        string _lastName;
    }

    function addPerson(string memory _firstName, string memory _lastName) public {
        people.push(Person(_firstName, _lastName));
        peopleCount += 1;
    }
}

Eşlemeler // Mappings

Solidity, anahtar/değer çiftlerini saklamamıza izin veren eşleme adı verilen bir veri yapısı sağlar. Bu yapı, diğer işlevlerde bir ilişkisel dizi veya karma tablo gibi davranır. Akıllı temasta şöyle bir eşleme bildirebiliriz:

mapping(uint => Person) public people;

Bu, person yapılarını depoladığımız bir eşleme olacaktır. Önceki örnekte kullandığımız people dizisinin yerini alacak. Anahtar işaretsiz bir tamsayı olacak ve değer bir kişi yapısı olacaktır. Anahtarı bir veritabanı kimliği gibi ele alacağız. Bu kimliği aşağıdaki gibi takip etmek için kişi yapısını güncelleyebiliriz:

struct Person { uint _id; string _firstName; string _lastName; }

Şimdi, şu şekilde eşlenen kişileri güncellemek için addPerson() işlevini değiştirebiliriz:

function addPerson(string memory _firstName, string memory _lastName) public {
    peopleCount += 1;
    people[peopleCount] = Person(peopleCount, _firstName, _lastName);
}

Bu, person için bir kimlik oluşturmak için peopleCount sayaç önbelleğini kullanır. Ardından, id ve geçirilen niteliklerle yeni bir person yapısını başlatır. Daha sonra bunu kişi eşlemeye ekler. Tamamlanan akıllı sözleşme kodu şöyle görünmelidir:

pragma solidity 0.5.1;

contract MyContract {
    uint256 peopleCount = 0;

    mapping(uint => Person) public people;

    struct Person {
        uint _id;
        string _firstName;
        string _lastName;
    }

    function addPerson(string memory _firstName, string memory _lastName) public {
        peopleCount += 1;
        people[peopleCount] = Person(peopleCount, _firstName, _lastName);
    }
}

Yaşasın! Artık Solidity’deki temel veri türleri ve veri yapılarına ilişkin bir genel bakış gördünüz.

İşlev Görünürlüğü, Değiştiriciler ve Zaman

Solidity Crash Course – Akıllı Sözleşme Geliştirici Eğitimi

Şimdi fonksiyon görünürlüğü hakkında konuşalım. Son bölümlerde, akıllı sözleşme işlevlerinin ağa bağlı hesaplar tarafından akıllı sözleşme dışında çağrılabilmesi için public işlevi görünürlüğünü birkaç kez kullandık. Ya yalnızca akıllı sözleşmede kullanılan işlevler oluşturmak istersek? Bunu interval görünürlük ile yapabiliriz. Bunu, peopleCount‘u şu şekilde kendi dahili işlevine yükselten iş mantığıyla gerçekleştirelim:

function incrementCount() internal {
    peopleCount += 1;
}

Bu işleve, diğer hesaplar için genel arayüz tarafından değil, yalnızca akıllı sözleşme içinde erişilebilir. Şimdi bu işlevi addPerson() işlevi içinde şu şekilde çağırabiliriz:

function addPerson(string memory _firstName, string memory _lastName) public {
    incrementCount()
    people[peopleCount] = Person(peopleCount, _firstName, _lastName);
}

Şimdi bu, diğer işlev türlerinin gözle görülür şekilde bir örneğidir. Fonksiyon değiştiriciler hakkında konuşalım. Bunlar, izinleri eklemek gibi işlevlerimize özel davranışlar eklememize izin verecek. Yalnızca bir yöneticinin veya “sahibin” addPerson() işlevini çağırmasına izin veren ve diğer herkesin bu işlevi çağırmasını kısıtlayan bir değiştirici oluşturalım.

İlk olarak, bu akıllı sözleşmenin sahibini saklamanın bir yolunu oluşturacağız. Bunu şöyle bir durum değişkeni ile yapabiliriz:

address owner;

Şimdi işlevi çağıran kişinin sahip olup olmadığını kontrol eden bir değiştirici oluşturalım:

modifier onlyOwner() {
    require(msg.sender == owner);
    _;
}

Bu kodu açıklayayım:

İlk olarak, değiştiriciyi değiştirici anahtar sözcüğüyle, ardından değiştirici adını onlyOwner ile bildiririz.
Ardından msg.sender ile fonksiyonu çağıran cari hesaba ulaşıyoruz. Solidity bu değeri msg global değişkeni içinde sağlar, tıpkı önceki bölümlerde gördüğümüz msg.sender gibi işlemin mevcut etheri gibi.
Ardından, işlevi çağıran hesabın sahip olduğunu kontrol etmek için require() kullanırız. require() işlevine iletilen ifadenin sonucu true olarak değerlendirilirse, kod yürütmeye devam eder. Değilse, bir hata atar. Bu durumda fonksiyonu çağıran hesap sahibi değilse Solidity hata verecektir.

Artık akıllı sözleşmenin içindeki sahibi, akıllı sözleşmeyi şu şekilde dağıtan hesap olarak ayarlayabiliriz:

constructor() public {
    owner = msg.sender;
}

Şimdi değiştiriciyi addPerson() işlevine ekleyebiliriz, böylece yalnızca sahibi onu çağırabilir. Buradayken, fonksiyonlar büyümeye başladığında, birçok argüman, değiştirici, görünürlük vb. ile Solidity kodumu nasıl biçimlendirdiğimi göstereceğim.

function addPerson(
    string memory _firstName,
    string memory _lastName
)
    public
    onlyOwner
{
    incrementCount()
    people[peopleCount] = Person(peopleCount, _firstName, _lastName);
}

Şimdi, yalnızca sahibin herhangi bir hata olmadan işlevi başarıyla çağırıp çağıramayacağını görmek için kodunuzu çalıştırmayı deneyin! Bu noktada tam akıllı sözleşme kodunuz şöyle görünmelidir:

pragma solidity 0.5.1;

contract MyContract {
    uint256 public peopleCount = 0;
    mapping(uint => Person) public people;

    address owner;

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    struct Person {
        uint _id;
        string _firstName;
        string _lastName;
    }

    constructor() public {
        owner = msg.sender;
    }

    function addPerson(
        string memory _firstName,
        string memory _lastName
    )
        public
        onlyOwner
    {
        incrementCount()
        people[peopleCount] = Person(peopleCount, _firstName, _lastName);
    }

    function incrementCount() internal {
        peopleCount += 1;
    }
}

Şimdi zamandan bahsedelim. Solidity‘de zamanın bir kullanım durumunu göstermek için zamanı kullanan yeni bir değiştirici oluşturabiliriz. onlyWhileOpen adlı yeni bir değiştirici oluşturacağız ve bu, blok zincirindeki geçerli zamanın bizim belirlediğimiz bir zamanı geçip geçmediğini kontrol edecek. Bu, “açılış zamanı” olan ICO crowdsale akıllı sözleşmeleri oluştururken yaygın bir uygulamadır. Çoğu zaman, bu akıllı sözleşmeler, kitle satışı başlamadan önce yapılan yatırımcı katkılarını reddeder. Açılış süresi geçene kadar addPerson() işlevine erişimi kısıtlayarak benzer davranışı modelleyebiliriz. İlk önce açılış saatini saklamak için bir durum değişkeni oluşturalım:

uint256 startTime;

startTime‘ı bu durum değişkeniyle saniyeler içinde saklayabiliriz, çünkü Solidity’de zaman damgalarını bu şekilde ifade ederiz. Aslında, zaman damgaları, 1 Ocak 1970 Perşembe gününden bu yana geçen saniye sayısı olan unix zamanı olarak ifade edilir. Bu zaman kuralı hakkında daha fazla bilgiyi Wikipedia‘da okuyabilirsiniz.

Şimdi kurucuda başlangıç zamanını şu şekilde ayarlayacağım:

constructor() public {
    startTime = 1544668513;
}

Bu makaleyi okuduğunuzda, o zaman damgası geçmiş olacak. Bu web sitesini gelecekte kendi amaçlarınız için bir unix zaman damgası oluşturmak için kullanabilirsiniz! Şimdi başlangıç zamanının şu şekilde geçtiğini kontrol etmek için bir değiştirici oluşturalım:

modifier onlyWhileOpen() {
    require(block.timestamp >= startTime);
    _;
}

Bu kodu açıklayayım:

  • İlk olarak, son örnekte yaptığımız gibi değiştiriciyi ilan ediyoruz.
  • Daha sonra, tıpkı son örnekte olduğu gibi, özel koşula ihtiyacımız var.
  • Şimdi, mevcut bloğun zaman damgasını block.timestamp ile kontrol ederek başlangıç zamanını “şimdi” ile karşılaştırıyoruz. Solidity’de “şimdi”yi bu şekilde elde ederiz!

Artık değiştiriciyi *addPerson() işlevine ekleyebiliriz. Bu kodu çalıştırmayı deneyin ve gelecekte erişimi bir süre kısıtlayıp kısıtlayamayacağınıza bakın! Yine, gelecekte bir zaman damgası oluşturmak için yukarıdaki internet sitesini kullanabilirsiniz. Bu değeri yapıcı işlevinde güncellediğinizden emin olun! Tam akıllı sözleşme kodu şöyle görünmelidir:

pragma solidity 0.5.1;

contract MyContract {
    uint256 public peopleCount = 0;
    mapping(uint => Person) public people;

    uint256 startTime;

    modifier onlyWhileOpen() {
        require(block.timestamp >= startTime);
        _;
    }

    struct Person {
        uint _id;
        string _firstName;
        string _lastName;
    }

    constructor() public {
        startTime = 1544668513; // Update this value
    }

    function addPerson(
        string memory _firstName,
        string memory _lastName
    )
        public
        onlyWhileOpen
    {
        people[peopleCount] = Person(peopleCount, _firstName, _lastName);
    }

    function incrementCount() internal {
        peopleCount += 1;
    }
}

Eter Gönderme ve Olaylar

Adım Adım Solidity – Akıllı Sözleşme Geliştirici Eğitimi

Şimdi Ether kabul eden bir fonksiyon yazalım. Bunu göstermek için buyToken() işleviyle ico benzeri bir sözleşme oluşturacağım. Bu, bir hesabın Ether ile belirteçler için ödeme yapması için eter göndermesine izin verecektir. Akıllı sözleşme, jetonların verilmesinden, hesabın bakiyesinin izlenmesinden ve ayrıca Ether fonlarının başka bir cüzdan adresine aktarılmasından sorumlu olacaktır. Yine, bu bir sözde ico örneğidir.

İlk önce, aşağıdaki gibi token bakiyelerini izlemek için bir eşleme oluşturacağız:

mapping(address => uint256) public balances;

Şimdi, bakiyeyi şu şekilde artıracak buyToken() işlevini oluşturacağım:

function buyToken() public {
    balances[msg.sender] += 1;
}

Şimdi, bir hesap jeton satın aldığında ether fonlarının gönderileceği bir cüzdan ilan edeceğim:

address wallet;

Artık buyToken() işlevi şu şekilde çağrıldığında cüzdana para aktarabiliriz:

function buyToken() public payable {
    balances[msg.sender] += 1;
    wallet.transfer(msg.value);
}

Şimdi bu kodu açıklayayım:

  • wallet.transfer() numaralı telefonu arayarak etheri doğrudan cüzdana aktarabiliriz.
  • Fonksiyon çağıran tarafından gönderilen Ether’in değerini msg.sender gibi msg.value ile alabiliriz.
  • Hesapların işlevi çağırırken Ether gönderebilmesi için payable (ödenebilir) değiştiriciyi de kullanmalıyız.

Benzer şekilde, Solidity 0.5.1’e güncellemek için, cüzdanın payable (ödenebilir) olduğunu da açıkça beyan etmeliyiz:

address payable wallet;

Şimdi cüzdan adresini sözleşmenin yapıcı işlevi içinde ayarlayalım (burada ödenebilir değiştiriciyi de kullanacağız):

constructor(address payable _wallet) public {
    wallet = _wallet;
}

Mükemmel! Şimdi, Remix’in içinde bu işlevle Ether’in nasıl gönderileceğini gösterdiğim için yukarıdaki videoyu izleyin. Akıllı sözleşme kodunu tamamladığınız bu noktaya kadar şöyle görünmelidir:

contract MyContract {
    mapping(address => uint256) public balances;
    address payable wallet;

    constructor(address payable _wallet) public {
        wallet = _wallet;
    }

    function buyToken() public payable {
        balances[msg.sender] += 1;
        wallet.transfer(msg.value);
    }
}

Şimdi size Solidity içinde varsayılan veya “yedek” bir fonksiyonun nasıl oluşturulacağını göstereceğim. Bu, bir hesap Ether’i akıllı bir sözleşmeye gönderdiğinde çağrılacak bir işlevdir. Bu, Ether’i akıllı bir sözleşmeye gönderdiğiniz ve bir işlevi yerine getirdiği ICO akıllı sözleşmeleri için çok yaygın bir kalıptır. Burada yapacağımız şey tam olarak bu. buyTokens() işlevini tamamlayan bir geri dönüş işlevi bildireceğiz. Bir hesap akıllı sözleşmeye Ether gönderdiğinde jeton satın alacaktır. Bunu şu şekilde yapabiliriz:

function() external payable {
    buyToken();
}

Mükemmel! Şimdi, Remix içindeki akıllı sözleşmeye Ether’in nasıl gönderileceğini gösterdiğim için yukarıdaki videoyu izleyin.

Şimdi Etkinlikler hakkında konuşalım. Olaylar, blok zincirinin asenkron doğasıyla başa çıkmanın bir yoludur. Harici tüketiciler tarafından abone olunabilecek olayları akıllı sözleşmeler içinde ilan edebiliriz. Bu tüketiciler, akıllı sözleşmede bir şeyler olduğunu bilmek için bu olayları dinleyebilecekler. Akıllı sözleşmenin en üstünde şöyle bir Purchase (satın alma) olayı ilan edeceğiz:

event Purchase(
    address _buyer,
    uint256 _amount
);

Bu olay, alıcıyı ve jeton tutarını günlüğe kaydeder. Bu olayı buyToken() işlevi içinde şu şekilde tetikleyebileceğiz:

function buyToken() public payable {
    balances[msg.sender] += 1;
    wallet.transfer(msg.value);
    emit Purchase(msg.sender, 1);
}

Bu etkinlik, bu akıllı sözleşme kapsamında herhangi bir jeton satın alındığında bunu bilmemizi sağlayacaktır. Peki ya yalnızca hesabımızla alakalı olayları dinlemek istersek? İyi haberler! Solidity, dizine alınmış değerlere göre filtreleme olaylarına abone olmamızı sağlar. Olay içindeki _buyer‘ı şu şekilde indeksleyebiliriz:

event Purchase(
    address indexed _buyer,
    uint256 _amount
);

Mükemmel! Artık Solidity içindeki olaylarla nasıl çalışacağınızı biliyorsunuz. Bu noktada tam akıllı sözleşme kodunuz şöyle görünmelidir:

contract MyContract {
    mapping(address => uint256) public balances

    event Purchase(
        address indexed _buyer,
        uint256 _amount
    );

    constructor(address payable _wallet) public {
        wallet = _wallet;
    }

    function() external payable {
        buyToken();
    }

    function buyToken() public payable {
        balances[msg.sender] += 1;
        wallet.transfer(msg.value);
        emit Purchase(msg.sender, 1);
    }
}

Olayların döndürdüğü değerleri görmek için işlem makbuzlarını nasıl inceleyeceğinizi öğrenmek için yukarıdaki videoyu izleyebilirsiniz.

Son olarak, Solidity‘de olayları kullanmak için birkaç yaygın kullanım örneğinden bahsedeceğim. Birincisi, daha önce de bahsettiğim gibi, onları doğrudan dinlemek. Bir akıllı sözleşme işlevini çağırmak ve ardından işlev çağrısının tamamlandığını bilmek için bir olayın tetiklenmesini beklemek yaygındır. İkinci olarak, olay akışının tamamını akıllı bir sözleşmeden, yani onun tarafından tetiklenen her olaydan alabilirsiniz. Solidity içinde bir işlev çağrısının tüm geçmişini elde etmenin gerçekten güzel bir yolu.

Akıllı Sözleşme Etkileşimi ve Kalıtım

Solidity Kolaylaştırır – Akıllı Sözleşme Geliştirici Eğitimi

Şimdi size çoklu akıllı sözleşmelerle sağlamlık içinde nasıl çalışacağınızı göstereceğim. İlk olarak, size başka bir akıllı sözleşme içinden akıllı sözleşme işlevlerini nasıl çağıracağınızı göstereceğim. Ardından, bir çocuk akıllı sözleşmesi içindeki bir ebeveyn akıllı sözleşmesinden davranışı nasıl devralacağınızı göstereceğim.

İlk olarak, MyContract kodundan ayrı bir belirteç akıllı sözleşme oluşturmak için önceki örnekteki kodu yeniden değerlendireceğim. Bu, gerçek bir ERC-20 akıllı sözleşmesinin tüm işlevlerini içermeyecek olan sözde bir ERC20 belirteci olacaktır. Şimdilik belirteç sözleşmesini şu şekilde oluşturacağım:

contract ERC20Token {
    string name;
    mapping(address => uint256) public balances;

    function mint() public {
        balances[msg.sender] += 1;
    }
}

Bu, mint() işlevini, name ve balances belirteç sözleşmesiyle dengeler, çünkü bu sorumlulukların bulunması gereken yer burasıdır. Artık *ERC20Token sözleşmesini kullanarak MyContract‘tan jeton basabiliriz. Bunu yapmak için birkaç şeye ihtiyacımız var: jetonun adresi ve mint() işlevini çağırmak için akıllı sözleşme kodu. İlk önce belirteç adresini aşağıdaki gibi bir durum değişkeninde saklayacağım:

contract MyContract {
address public token;
//…
}

Şimdi, yapıcı içindeki belirteç adresinin değerini şu şekilde ayarlayabiliriz:

constructor(address payable _wallet, ERC20Token _token) public {
    wallet = _wallet;
    token = _token;
}

Artık adres elimizde olduğuna göre buyToken() işlevinin içindeki akıllı sözleşme koduna bu şekilde erişebilir ve bunun üzerindeki mint() işlevini şu şekilde çağırabiliriz:

function buyToken() public payable {
    ERC20Token _token = ERC20Token(address(token));
    _token.mint();
    wallet.transfer(msg.value);
}

Devam etmeden önce bir şeye dikkatinizi çekmek istiyorum. Şu anda kişisel hesabınızdan buyToken() işlevini çağıracak olsaydınız, kendiniz için herhangi bir jeton basmazdınız. Nedenmiş!? mint() fonksiyonunu şimdi olduğu gibi tekrar gözden geçirelim:

function mint() public {
    balances[msg.sender] += 1;
}

Hesabınız için jeton basmamasının nedeni, msg.sender‘ın aslında MyContract adresine atıfta bulunmasıdır, bu da işlevi buyToken() işlevinin içinden çağırır! Kendi hesabımız için jeton basmak istiyorsak, blok zincirindeki işlemi başlatan hesaba şu şekilde referans vermek için tx.origin kullanmalıyız:

function mint() public {
    balances[tx.origin] += 1;
}

Buyrun! Artık başka bir akıllı sözleşmeden jeton basabilirsiniz! Bu gösteriyi Remix içinde nasıl çalıştıracağınızı görmek için videoyu izleyin. Önce belirteç akıllı sözleşmesini dağıtmanız, adresini almanız ve ardından ikinci akıllı sözleşmeyi dağıttığınızda bunu bir argüman olarak eklemeniz gerekir. Bu noktada tam akıllı sözleşme kodunuz şöyle görünmelidir:

pragma solidity 0.5.1;

contract ERC20Token {
    string name;
    mapping(address => uint256) public balances;

    function mint() public {
        balances[tx.origin] += 1;
    }
}

contract MyContract {
    address public token;

    address payable wallet;

    constructor(address payable _wallet, address _token) public {
        wallet = _wallet;
        token = _token;
    }

    function buyToken() public payable {
        ERC20Token _token = ERC20Token(address(token));
        _token.mint();
        wallet.transfer(msg.value);
    }
}

Şimdi size belirteç akıllı sözleşmesine başvurmanın başka yollarını göstereceğim. Bunun gibi tek yalanlı bir ifade kullanabiliriz:

function buyToken() public payable {
    ERC20Token(address(token)).mint();
    wallet.transfer(msg.value);
}

Belirteci şu şekilde bir durum değişkeninde saklamak için kodu da yeniden düzenleyebiliriz:

contract MyContract {
ERC20Token public token;
//…
}

Ardından, mint işlevini şu şekilde çağırabiliriz:

function buyToken() public payable {
    token.mint();
    wallet.transfer(msg.value);
}

Şimdi miras hakkında konuşalım. Solidity, birbirinden miras kalan akıllı sözleşmeler oluşturmanıza olanak tanır. Orijinal belirteç akıllı sözleşmemizden miras kalan MyToken adında yeni bir sözde belirteç oluşturalım. Eşsiz bir ad, sembol ve mint işlevi vermek için kalıtımı kullanacağız. Akıllı sözleşmeden şu şekilde miras alabiliriz:

contract MyToken is ERC20Token {
    // ...

}

Şimdi ana akıllı sözleşmede belirteç adını şu şekilde takip edebiliriz:

ragma solidity 0.5.1;

contract ERC20Token {
    string public name;
    mapping(address => uint256) public balances;

    constructor(string memory _name) public {
        name = _name;
    }

    function mint() public {
        balances[tx.origin] ++;
    }
}

Alt simgemizin yapıcısı içindeki üst simgenin adını geçersiz kılabiliriz. Buradayken, çocuk belirteci için bir sembol oluşturacağız ve onu yapıcıya ayarlayacağız. Bunun gibi yeni değerler atarken, ana belirteç sözleşmesi yapıcısını nasıl geçersiz kılacağınızı göstereceğim:

contract MyToken is ERC20Token {
    string public symbol;

    constructor(
        string memory _name,
        string memory _symbol
    )
        ERC20Token(_name)
    public {
        symbol = _symbol;
    }
}

Mükemmel! Şimdi MyToken‘ı özelleştirdik. Şimdi mint() işlevini üst simgenin işlevselliğini geçersiz kılmak için güncelleyelim. İlk olarak, tüm token sahiplerinin adresini saklamanın bir yolunu oluşturalım. Ayrıca tüm sahiplerin sayısını şu şekilde ayarlayacağız:

contract MyToken is ERC20Token {
    address[] public owners;
    uint256 public ownerCount;
    //...
}

Şimdi ana belirteç akıllı sözleşmesinin davranışını korurken bu değerleri kendi mint() işlevimiz içinde güncelleyelim. Bunu super anahtar sözcüğüyle şöyle yapabiliriz:

function mint() public {
    super.mint();
    ownerCount ++;
    owners.push(msg.sender);
}

Mükemmel! Şimdi, ana belirteçten miras alan kendi özel belirtecimizi yarattık. Tam akıllı sözleşme kodunuz şöyle görünmelidir:

pragma solidity 0.5.1;

contract ERC20Token {
    string public name;
    mapping(address => uint256) public balances;

    constructor(string memory _name) public {
        name = _name;
    }

    function mint() public {
        balances[tx.origin] ++;
    }
}

contract MyToken is ERC20Token {
    string public symbol;
    address[] public owners;
    uint256 public ownerCount;

    constructor(
        string memory _name,
        string memory _symbol
    )
        ERC20Token(_name)
    public {
        symbol = _symbol;
    }

    function mint() public {
        super.mint();
        ownerCount ++;
        owners.push(msg.sender);
    }

}

🎉 Adım Adım Solidity makalesi şimdilik bu kadar. Solidity için nitelikli içerikler (kitap, video, podcast vb.) üretmeye devam edeceğiz. Solidity Geliştiricisi olmak isteyenler için TÜrkçe kaynak sayısı yok denecek düzeyde, Ağustos 2022’de Adım Adım Solidity kitabımın taslağını tamamladım, yayına hazır hale getirip, sizlerle buluşturmak için çalışmaya devam ediyorum.

Solidity Developer sayısı dünyada henüz çok az denilebilecek düzeyde, ülkemizde çok daha az sayıda, aynı zamanda Dünya da Solidity Geliştiricisine çokça ihtiyaç duyuluyor, gelir düzeyleri de altı haneli dolar seviyesinde olunca, bu alana işgücü olarak yetişmek / yetiştirmek için üretmeye devam edeceğiz.

Sağlıcakla.

Bu içerik dappuniversity yayınlarından derlenmiştir.

solidity101 - Solidity, 2015 yılında Christian Reitwiessner liderliğinde piyasaya sürülen, büyük harf kullanımına göre ikinci en büyük kripto para piyasası olan Ethereum tarafından oluşturulan yepyeni bir programlama dilidir.

Yazarın Profili
İlginizi Çekebilir

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir