Akıllı Sözleşmelerde Değer Türleri #1

Akıllı Sözleşmelerde Değer Türleri #1

Değer türleri(value types), her zaman bir değer döndüren değişkenlerin türleridir. Bunlar boolean, sayı(integer), adres(address), kontrat(contracts) vb türlerde karşımıza çıkmaktadır. Resmi dökümanda çok kapsamlı ve uzun şekilde anlatıldığı için parçalara bölünmüş şekilde birkaç yazıda akıllı sözleşme türlerini açıklayıp ardından örnekleyeceğim.

Değer Türleri(Value Types)

Değer türleri(value types), her zaman bir değer döndüren değişkenlerin türleridir. Bunlar boolean, sayı(integer), adres(address), kontrat(contracts) vb türlerde karşımıza çıkmaktadır. Resmi dökümanda çok kapsamlı ve uzun şekilde anlatıldığı için parçalara bölünmüş şekilde birkaç yazıda akıllı sözleşme türlerini açıklayıp ardından örnekleyeceğim.

Boolean Değerler

bool değerler true ya da false değerlerini alabilmektedir. [ayr. bkz.] Bir şartın doğru ya da yanlış olduğunu belirtmek için bool değerler kullanılmaktadır.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;


contract BoolValues {
    //Ödeme yapılıp yapılmadığı iki  farklı değer alacağı için (true-false) bool türüyle tanımladık.
    bool odemeYapildiMi;
}
  • !➝ mantıksal olumsuzlama. Doğru ise yanlış, yanlış ise doğru döner.
  • &&➝ mantıksal "ve" bağlacı. İki değerin de "doğru" olması ile "doğru" döner
  • ||➝ mantıksal "ya da" bağlacı. İki değerden biri "doğru" ise doğru döner
  • ==➝ iki değer birbirine eşit mi? Eşitse "doğru" döner
  • != (iki değer birbirine eşit değilse "doğru" döner)
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;


contract BoolValues {
    //iki bool değerin hangi operatorlerle sorgunlandıgını inceleyelim
    function ikiBoolEsitMi(bool x, bool y) pure public returns(bool){
        return x == y;
    }
    
    //x bool değeri true ise doğru olduğunu dönecektir.
    function DogruMu(bool x) pure public returns(bool){
        return x;
    }


    /*x bool değeri true ise doğru olduğu için doğru değil şartı yanlış olacaktır. Bu ! işareti ile sağlanır*/
    function DogruDegilMi(bool x) pure public returns(bool){
        return !x;
    }

Sayı Değişkenleri(Integers)

int ve uint, imzalı(signed) ve imzalanmamış(unsigned) iki sayı değerini belirtir. [ayr. bkz.] Sayı doğrusunun hem artı hem eksi tarafının olduğunu düşünecek olursak int değerleri +, - ve 0 değerlerini alabilirken uint yalnızca 0 ve + değerleri alabilir.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;


contract OrnekSozlesme {
    //Pozitif ve 0 değerler tanımlanabilir.
    uint imzasizDegerler = 0;
    uint imzasizDegerler1 = 88;


    //-88 imzalı bir sayı olduğu için hata dönecektir.
    uint imzasizDegerler2 = -88;


    //Tüm tam sayı değerleri tanımlanabilir.
    int tumTamsayiDegerleri = 2;
    int tumTamsayiDegerleri1 = -888;
    int tumTamsayiDegerleri2 = 0;


    //Değerler tam sayı olmadığı için hata dönecektir.
    uint imzasizDegerler3 = 98.8;
    int tumTamsayiDegerleri4 = 88.8

int8, uint8, int,uint, int256 ve uint256 çeşitli uzunluklarda olabilmektedir. int ve uint için bir uzunluk sınırlaması yokken int8, uint8, int256ve uint256 için belirli bir uzunluk sınırı vardır.

//Doğru değer
int8 yeniSayi1 = 88;


//Hatalı değer
int8 yeniSayi1 = 888;

Operatörler:

  • Karlışatırma operatörleri: <=<==!=>=> (bool değer dönecektir)
  • Bit operatörleri: &|^ (bitwise exclusive or), ~ (bitwise negation)
  • Kaydırma operatörleri: << (sola kaydırma operatörü), >> (sağa kaydırma operatörü)
  • Aritmetik operatörler: +-, unary - (yalnızca signed sayılar için), */% (modül), ** (üs alma operatörü)
contract SayiOperatorleri{
    int256 sayi1 = 2;
    //Sayi1 değerinin 4 üssü alınır. (sayi1 üzeri 4)
    int booldeger1 = sayi1 ** 4;
}

Karşılaştırma Operatörleri(Comparisons)

Herhangi bir programlama dilinde proje geliştirirken kodunuzda yer yer bazı şartlar belirtmeniz gerekir. Örnek olarak, karne notunu girmesini beklediğiniz kişinin not aralığı 0 ile 100 arasında olsun. Bu durumda kişi 105 ya da -5 değerini girememelidir. Bu ve benzeri durumları karşılaştırma operatörleri kullanarak sorgulamanız gerekir.

Bit Operasyonları(Bit operations)

Bilgisayar programlamasında, bit düzeyinde bir işlem, bir bit dizisi, bir bit sayı dizisi veya bir ikili sayı (bir bit dizisi olarak kabul edilir) üzerinde, kendi bitlerinin düzeyinde çalışır. [ayr. bkz.]

Bit operasyonları, Solidity dilinde de kullanılmaktadır.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;


contract BitOperatorleri{


    //Fonksiyon aracılığıyla şart kontrolü yapıyoruz.
    function kontrolFonksiyonu(int x, int y) pure public returns(bool){
        //Bir sayının değilinin değili yine kendisi olacağında x == y şartında bool değer true dönecektir.
        //~(~x) = x
        return ~(~int256(x)) == int256(y);
    }

Kaydırma Operatörleri(Shifts)

Kaydırma operatörleri, sağa kaydırma(right shift) ve sola kaydırma(left shift) olarak ikiye ayrılır. Kaydırma işlemlerinde işlemin uygulandığı bitler sağa ya da sola doğru kaydırılır.

Sağa Kaydırma (Right Shift)

Bir bit bloğu üzerinde sağa kaydırma işlemi uyguladığımız zaman o blok üzerindeki tüm bitler bir sağ pozisyona geçerler. En sağdaki bit kaybolur, en soldan bir adet 0 eklenir. [ayr. bkz.]

'x' harfine 1'lik sağa kaydırma işlemi uygulandığında her bit değeri bir sağa doğru kaydırılır. Yeni bir binary değeri elde edilir.

//Bu kod Solidity için geçerli değildir. Mantığın anlatılması için örneklenmiştir.


char x = 'x';    // 01111000
char y = x >> 1; // 00111100

Sola Kaydırma (Left Shift)

Bir bit bloğu üzerinde sola kaydırma işlemi uyguladığımız zaman o blok üzerindeki tüm bitler bir sol pozisyona geçerler. En soldaki bit kaybolur, en sağdan bir adet 0 eklenir. [ayr. bkz.]
//Bu kod Solidity için geçerli değildir. Mantığın anlatılması için örneklenmiştir.
char x = 'x'; //01111000
char y = x << 1; // 11110000

Solidity için kaydırma operatörlerinin nasıl kullanıldığını gösteren örnek kod;

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;


contract ShiftOperatorleri{
    //Shift operatörleri.


    function soldanShiftOperasyonuUygula(uint256 x, uint256 y) pure public returns(uint256){
        //x << y
        //İşemin sonucu -->  x * 2 ** y (x çarpı 2 üzeri y)
        return x << y;
    }


    function sagdanShiftOperasyonuUygula(uint256 x, uint256 y) pure public returns(uint256){
        //x >> y
        //İşemin sonucu -->  x / 2 ** y (x bölü 2 üzeri y)
        return x >> y;
    }


    //HATALI KULLANIM! --> Bir kaydırma operasyonu unsigned(uint) değerler kullanılmadığında hata fırlatır.
    function sagdanShiftOperasyonuUygula(int x, int y) pure public returns(int){
        //x >> y
        //İşemin sonucu -->  x / 2 ** y (x bölü 2 üzeri y)
        return x >> y;
    
  • x << y bir matematiksel tanım olan x * 2**y'a eşittir..
  • x >> y ise benzer şekilde matematiksel tanım olan x / 2**y 'a eşittir ve sayıyı negatif sonsuza yuvarlamaya yarar.

Modulo

Modulo, bir sayının diğer bir sayıya bölümünden kalanı verir ve %işareti ile gösterilir. İki sayı pozitif olduğunda bölümden kalan bildiğimiz işlemler dahilinde uygulanır. Örneğin, 16 % 4 işleminin sonucu bölme sonrasında kalanın sonucunu yani 0'ı verir. 5 % 4(5 mod 4) işlemi de 1 sonucunu verir.

  • int256(16) % int256(4) == int256(0)
  • int256(5) % int256(4) == int256(1)
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;


contract ModulOperatorleri{
    function modulIslemiYap(int256 x, int256 y) pure public returns(bool){ 
       //Modül işlemi sonucunda kalan yani sonuç 0 ise doğru dönecektir.
       if(int256(x) % int256(y) == int256(0)){
           return true;
       }
       return false;
    }
}

Bir sayının pozitif diğerinin negatif olduğu durumlarda modül alma işlemi değişkenlik gösterir. Solidity dili için inceleyecek olursak, a % b için işlem sonucu a % b == -(-a % b) olacaktır.

  • int256(-5) % int256(2) == int256(-1)
  • int256(5) % int256(-2) == int256(1)
  • int256(-5) % int256(-2) == int256(-1)

Üs Alma(Exponentiation)

Üs alma işlemi yalnızca pozitif sayılar(unsigned) için geçerlidir. Üs alma sonucunda ise sonuç tabanın türündeki değerde yani uint olacaktır.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;


contract UsAlma{
    function usAlmaIslemiYap(uint256 x, uint256 y) pure public returns(uint256){ 
       return x ** y;
    }
}
  • Üs alma işlemi yalnızca uint değerler için geçerlidir.
  • x üzeri 3 matematiksel ifade olarak x ** 3 'e eşittir.
  • 0 üssü 0(0**0), Ethereum Sanal Makinesinde sonucunu 1 olarak verir.

Sabit Sayılar(Fixed Point Numbers)

Adres(Address)

address, 20 byte uzunluğundaki Ethereum adresidir. address payable ise adressden farklı olarak gönderim ve transfer gibi bazı ek özelliklere sahiptir. payableözelliğine sahip olmayan bir address Ethereum transferinden etkilenmez ancak address payable bir Ethereum adresi, işlem sonucunda ETH transfer edebilir. Bu özelliğin payablea bağlı olmasının sebebiyse her akıllı kontrat adresinin ETH transferine ihtiyaç duymamasındandır.

Örneğin, bir akıllı sözleşme yazdığımızı düşünelim. Bu sözleşmenin test sorularını başarılı cevaplayan öğrencilere ödül olarak bir miktar ETH vereceğini düşünelim. Burada her öğrencinin sahip olduğu adresin payable olması gerekir ki ETH ödülünü alabilsin.

Adreslerin Tarafları(Members of Addresses)

Adresler, balance, transfer , code , codehash gibi bazı taraflara sahiptir.

  • balance , bir adreste bulunan ETH miktarını gösteren değerdir,
  • transfer(uint amount) , adrese transfer edilecek Wei miktarı işleminin yapıldığı fonksiyondur,
  • <address>.codehash (bytes32), Ethereum Sanal Makinesinde bir hesabı tanımlayan Keccak-256 karma kodunun değeridir
  • <address>.code, kullanıldığı adresin Ethereum Sanal Makinesi bytecode değerini bytes memory türünde verir.
  • <address payable>.send(uint256 amount) returns (bool) , payable özelliğine sahip bir adrese(hesaba) para gönderme işlemi yapabildiğimiz ve ardından bool türünde dönüt alabildiğimiz fonksiyondur.
// SPDX-License-Identifier: GPL-3.0


pragma solidity >=0.7.0 <0.9.0;


/**
 * @title ParaIslemiSozlesmesi
 */
contract ParaIslemiSozlesmesi {
    function hesabimdanParaTransferEt() public payable {
        address payable gonderilecekHesapAdresi =     payable(0xadasd); //test adresi
        gonderilecekHesapAdresi.transfer(200000000);
    }

Eğer transfer fonksiyonları gönderimi yapacak hesapta yeterli miktarda ETH olmadan çağrılırsa hata dönecektir. Benzer olarak send fonksiyonu ise hata mesajı yerine bool türünde false değeri dönecektir.

Send fonksiyonu kullanırken bazı konulara dikkat etmek gerekir. Gönderim yapacak hesabın yeterli miktarda işlem için gerekli olan asgari miktarın belirtilip belirtilmediği gibi durumların kontrol edilmesi son derece önemlidir.

  • calldelegatecall and staticcall , bytes memory değerini alarak bool ve bytestüründe değer ya da değerler döndüren fonksiyonlardır.
// SPDX-License-Identifier: GPL-3.0


pragma solidity >=0.7.0 <0.9.0;


/**
 * @title OrnekCallFonksiyonu
 */
contract OrnekCallFonksiyonu{


    function callFonksiyonuCagir() public returns(bool success, bytes memory returnData) {
        bytes memory payload = abi.encodeWithSignature("register(string)", "Isminiz");
        return address(0xadasd).call(payload);
    }

Sağlanan gaz değerini {gas: 12321312} değişkeni ile ayarlayabilirsiniz.

address(nameReg).call{gas: 1000000}(abi.encodeWithSignature("register(string)", "MyName"));

Benzer olarak değeri de değişterebilirsiniz.

address(nameReg).call{gas: 1000000, value: 1 ether}(abi.encodeWithSignature("register(string)", "MyName"));
  • delegatecall fonksiyonu da benzer olarak kullanılır. Farkıysa diğer sözleşmelerde depolanan kütüphane kodlarını kullanmasıdır.
  • staticcall fonksiyonu, call fonksiyonundan farklı olarak bir durum değişikliği yaşandığında işlemi geri çevirir.
  • staticcall,delegatecall ve call fonksiyonları Solidity dilinin tür güvenliğini tehdit eden düşük seviyeli fonksiyonlardır(low-level-functions) ve kullanılması zorda kalmadıkça tercih edilmemelidir.

gas değişkeni call,staticcallve delegatecall fonksyionlarında mevcuttur. Ancak value değişkeni yalnızca call fonksiyonunda geçerlidir.

Sözleşme türleri, değişmezler(literals), listeler(enums), fonksiyon türleri(function types), referans türleri(reference types) ve dizilerin(arrays) de dahil olduğu diğer türleri bir sonraki yazımızda açıklayacağım. Görüşmek üzere!

Yorumunu Bırak

Çok hızlısın. Biraz dinlendikten sonra tekrar devam edebilirsin.
Bugünlük gönderebileceğin kadar yorum gönderdin. Lütfen yarın tekrar dene.
Mesajınız bize başarılı bir şekilde ulaştırıldı. Teşekkürler.

Yorumlar

0 Yorum yok

Henüz yorum yapılmamış. İlk yorum yapan sen ol.

Blog Yazarı

Ömer Faruk Coşkun
Yazar
@ofcskn

İstanbul Üniversitesi Bilgisayar Mühendisliği Öğrencisi