Analise smart-contract
07.08.2024

Solidity'de Yaygın ERC-20 Akıllı Sözleşme Hatalarını Anlama

Ethereum ekosistemindeki akıllı sözleşmeler genellikle merkeziyetsiz uygulamaların güvenliğini ve işlevselliğini sağlamak için karmaşık mantıklar içerir. Ancak, çeşitli nedenlerden dolayı hatalar meydana gelebilir ve bu da başarısız işlemler ve potansiyel güvenlik açıklarına yol açabilir. Bu blog yazısında, ERC-20 token işlemlerinde karşılaşılan bazı yaygın hatalar, nedenleri ve çözümleri ele alınacaktır.

1. Pancake: K

Bu hata, 'rezervlerin çarpımı sabit olmalıdır' invariant'ının ihlal edilmesi durumunda ortaya çıkar. Bu koşul, takas gerçekleştirildikten sonra yeni rezerv çarpımının (komisyonlar dahil) eski çarpımdan daha az olmayacağını garanti eder. Bu koşulun ihlal edilmesi şu durumlarda meydana gelebilir:

  1. Havuzdaki tokenler (amount0In veya amount1In), invariant formülüne göre beklenen değerlerle eşleşmiyorsa. Takas sonrası bakiye hesaplamasında bir hata olmuştur.
  2. Birisi havuzu manipüle etmeye çalışmış ve bu, token bakiyelerinin değişmesine neden olmuş ve standart takas sürecini atlamış olabilir.
  3. Bu koşul karşılanmadığında, 'Pancake: K' hatası oluşur ve bu matematiksel invariant ihlalini işaret eder.

Bir invariant ihlali, sistemin doğru şekilde çalışmasını sağlayan temel koşullardan birinin artık yerine getirilmediği anlamına gelir. PancakeSwap gibi merkeziyetsiz borsa bağlamında, invariant genellikle token rezervleri arasındaki dengeyi korumak için geçerli olması gereken bir matematiksel denklemle ilişkilidir.


require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(10000**2), 'Pancake: K');

Çözüm:
Havuzun takası gerçekleştirmek için yeterli likiditeye sahip olduğunu ve değerlerin rezervleri aşmadığını kontrol edin (_reserve0, _reserve1). Havuz rezervlerini sürekli izleyin ve gerekirse bunları yeniden doldurmak için önlemler alın.

2. TransferHelper: TRANSFER_FROM_FAILED

Bu hata, ERC-20 token'larının güvenli bir şekilde transfer edilmesi için yaygın bir desen olan safeTransferFrom yöntemini kullanarak başarısız bir token transferini ifade eder.


function safeTransferFrom(address token, address from, address to, uint value) 
  internal {
    // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
    (bool success, bytes memory data) = 
token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
    require(success && (data.length == 0 || abi.decode(data, (bool))), 
'TransferHelper: TRANSFER_FROM_FAILED');
  }

Neden:

  1. 'from' adresi, 'msg.sender' adresine token transferi yapmak için yeterli izin vermemiş veya yeterli izin vermemiştir (allowance, approve).
  2. 'from' adresinde transfer yapmak için yeterli token bulunmamaktadır. Bu, token yöneticilerinin token bakiyelerini değiştirme yeteneğine sahip olması ve yatırım yaptığı anda kullanıcının çekim yapacak kadar bakiye bulundurmaması gibi nedenlerden kaynaklanabilir.
  3. Token sözleşmesi 'transferFrom' fonksiyonunu uygulamıyor veya hatalı uyguluyor olabilir.
  4. Token sözleşmesi, transfer işlemini iptal edebilecek ek kontroller veya kısıtlamalar içerebilir.
  5. İşlemi gerçekleştirmek için yeterli gaz yoksa, işlem başarısız olabilir.

Çözüm:

  1. 'from' adresinin 'msg.sender' için yeterli izin verdiğinden emin olun. Bu, token sözleşmesinin allowance fonksiyonunu çağırarak yapılabilir.
  2. 'from' adresinin transfer işlemini gerçekleştirmek için yeterli token bulundurduğundan emin olun.
  3. Token sözleşmesi adresinin doğru olduğunu ve sözleşmenin ERC-20 uyumlu olduğunu doğrulayın.
  4. Token sözleşmesindeki 'transferFrom' fonksiyonunun uygulanmasını kontrol edin. Doğru şekilde uygulandığından ve başarısızlığa neden olabilecek ek kısıtlamalar içermediğinden emin olun.
  5. Sorunun gaz eksikliğinden kaynaklanmadığından emin olmak için işlem çağrısında gaz limitini artırmayı deneyin.

3. INSUFFICIENT_LIQUIDITY

Bu hata, bir likidite havuzundan mevcut rezervlerden daha fazla likidite çekmeye çalışırken ortaya çıkar.


(uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
        require(amount0Out < _reserve0 && amount1Out < _reserve1, 'Pancake:
INSUFFICIENT_LIQUIDITY');

Neden:

  1. Likidite havuzu, talep edilen takası karşılamak için yeterli miktarda bir veya iki token içermemektedir.
  2. Çekilmek istenen token miktarı (amount0Out veya amount1Out), havuzdaki mevcut token sayısını aşmaktadır.
  3. Sözleşmedeki rezervlerle havuzun gerçek durumu arasında uyumsuzluk olabilir. Sözleşmede saklanan rezervler, havuzdaki gerçek token bakiyesiyle uyuşmayabilir.

Çözüm:

  1. Havuz rezervlerini kontrol edin ve talep edilen takası gerçekleştirmek için yeterli olduklarından emin olun. Bu, getReserves fonksiyonunu kullanarak yapılabilir.
  2. amount0Out ve amount1Out parametrelerinin doğru olduğundan ve havuzdaki mevcut token sayısını aşmadığından emin olun.
  3. Sözleşmedeki rezervlerin gerçek token bakiyesiyle uyumlu olduğundan emin olun. Bunu yapmak için, takas gerçekleştirmeden önce rezervlerin kontrolünü ve güncellenmesini ekleyebilirsiniz.

INSUFFICIENT_LIQUIDITY

4. APPROVE_FAILED

`APPROVE_FAILED` hatası, `safeApprove` fonksiyonunun yürütülmesi sırasında meydana gelir. Bu fonksiyon, bir sahibinin bir harcayıcıya kendi adına kullanmasına izin verdiği token miktarını belirlemek için tasarlanmıştır.


function safeApprove(address token, address to, uint value) internal {
  (bool success, bytes memory data) = 
token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
  require(success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper: APPROVE_FAILED');
}

Neden:

  1. Token sözleşmesi `approve` fonksiyonuna sahip olmayabilir veya yanlış uygulanmış olabilir.
  2. Token sözleşmesinin durumu ile ilgili bir sorun olabilir, örneğin yetersiz bakiye veya izin.
  3. `approve` fonksiyonu, token sözleşmesinde uygulanan güvenlik nedenleriyle geri dönebilir.

Çözüm:

  1. Token sözleşmesinin ERC-20 standardına uygun olduğundan ve düzgün uygulanmış bir `approve` fonksiyonu içerdiğinden emin olun.
  2. Token sözleşmesinin durumunu kontrol edin ve hesabın yeterli tokena sahip olduğunu doğrulayın.
  3. `safeApprove` fonksiyonuna geçirilen adresin ve miktarın doğru olduğunu doğrulayın.
  4. Token sözleşmesindeki spesifik hata mesajını veya geri dönme nedenini kontrol ederek daha fazla hata ayıklama yapın.

5. 'ds-math-sub-underflow' hatasıyla başar ısızlık

`ds-math-sub-underflow` hatası, bir çıkarma işlemi alt akışa uğradığında, yani çıkarma işleminin sonucu sıfırdan küçük olduğunda ortaya çıkar.


    function sub(uint x, uint y) internal pure returns (uint z) {
      require((z = x - y) <= x, 'ds-math-sub-underflow');
    } 

Neden:
Bu hata, çıkarma işlemi `x - y` negatif bir sayı ürettiğinde meydana gelir ve bu Solidity'de işaretsiz tam sayılar için izin verilmez.

Çözüm:

  1. Çıkarma işleminden önce `y` değerinin her zaman `x` değerinden küçük veya ona eşit olduğundan emin olun.
  2. Kodunuzda `y` değerinin `x` değerinden büyük olabileceği durumları ele almak için kontroller uygulayın ve uygun aksiyonları alın, örneğin işlemi geri almayı veya mantığı ayarlamayı.

6. 'ERC20: transfer amount exceeds allowance' hatasıyla başarısızlık

'ERC20: transfer amount exceeds allowance' hatası, bir kullanıcının adına token transferi yapılmaya çalışıldığında, transfer edilen miktarın token sahibinin harcayıcı için belirlediği izin limitini aştığı durumlarda ortaya çıkar.

Sebep:
Bu hata, ERC-20 token sözleşmesinin `transferFrom` fonksiyonu tarafından, transfer edilecek miktarın token sahibinin belirlediği izin limitinden fazla olduğu durumlarda fırlatılır.

Çözüm:

  1. Token sahibinin harcayıcı için yeterli bir izin ayarladığından emin olun; bunu `approve` fonksiyonunu kullanarak yapabilirsiniz.
  2. `transferFrom` işlemini gerçekleştirmeden önce mevcut izni kontrol edin.
  3. Gerekirse, token sahibinden izin miktarını artırmak için `approve` fonksiyonunu daha yüksek bir değer ile çağırmasını isteyin.

7. TRANSFER_FAILED

Bu hata, bir adresten diğerine token transferi gerçekleştirilemediğinde meydana gelir. `_safeTransfer` fonksiyonu, transfer işleminin başarılı olmasını ve dönen verinin, varsa, `true` olarak çözülmesini sağlar.


    `function _safeTransfer(address token, address to, uint value) private { (bool 
    success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to,
    value)); require(success && (data.length == 0 || abi.decode(data, (bool))),
    'Pancake: TRANSFER_FAILED'); }`

Sebep:

  1. `token.call` fonksiyonu başarılı bir şekilde yürütülmüyor (yani, `success` değeri `false`).
  2. Çağrı, `true` olarak çözümlenmeyen veriler döndürür, bu da token sözleşmesinin `transfer` fonksiyonunda bir başarısızlık olduğunu gösterir.

Çözüm:

  1. ERC-20 Uyumluluğunu Sağlayın: Token sözleşmesinin ERC-20 standartlarına uygun olduğunu doğrulayın, bu da `transfer` fonksiyonunun doğru şekilde uygulanmasını içerir.
  2. Parametreleri Doğru Belirleyin: `to` adresinin geçerli olduğunu ve `value` değerinin izin verilen sınırlar içinde olduğunu, gönderenin bakiyesini ve sözleşmenin mantığını göz önünde bulundurarak doğrulayın.
  3. Ek Koşulları Kontrol Edin: Token sözleşmesinin harcama miktarının önceden onaylanmasını (`approve` ve `allowance` fonksiyonları) gerektirip gerektirmediğini kontrol edin.

INSUFFICIENT_LIQUIDITY

8. INSUFFICIENT_OUTPUT_AMOUNT

Bu hata, merkeziyetsiz bir borsa bağlamında, bir token değişiminde çıkış miktarının kullanıcı tarafından belirtilen minimum miktardan az olması durumunda meydana gelir. Bu, kullanıcıların işlem sırasında kayma veya fiyat değişiklikleri nedeniyle beklediklerinden daha az token almalarını önlemek için bir güvenlik önlemidir.


    `require(amounts[amounts.length - 1] >= amountOutMin,
    'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT');`

Sebep:

  1. İşlemin başlatıldığı ve gerçekleştirildiği zaman arasındaki piyasa volatilitesi token fiyatlarını etkiler.
  2. Yüksek kayma ayarları, beklenen çıkışlarda büyük sapmalara izin verir.
  3. Ticaret havuzunda yetersiz likidite, daha büyük fiyat etkilerine neden olabilir.

Çözüm:

  1. ERC-20 Uyumluluğunu Sağlayın: Token sözleşmesinin ERC-20 standartlarına uygun olduğunu doğrulayın, bu da `transfer` fonksiyonunun doğru şekilde uygulanmasını içerir.
  2. Parametreleri Doğru Belirleyin: `to` adresinin geçerli olduğunu ve `value` değerinin izin verilen sınırlar içinde olduğunu, gönderenin bakiyesini ve sözleşmenin mantığını göz önünde bulundurarak doğrulayın.
  3. Ek Koşulları Kontrol Edin: Token sözleşmesinin harcama miktarının önceden onaylanmasını (`approve` ve `allowance` fonksiyonları) gerektirip gerektirmediğini kontrol edin.

9. INSUFFICIENT_INPUT_AMOUNT

Bu hata, bir token değişiminde giriş miktarlarından hiçbirinin sıfırdan büyük olmadığı durumlarda ortaya çıkar. En az bir giriş miktarının (`amount0In` veya `amount1In`) pozitif olması gerektiğini ve değişimin devam etmesi için bunu doğrular.


    uint amount0In = ...; // Input amount of token0
    uint amount1In = ...; // Input amount of token1
    require(amount0In > 0 || amount1In > 0, 'Pancake: INSUFFICIENT_INPUT_AMOUNT');

Sebep:

  1. Değişim fonksiyonu için yanlış giriş parametreleri.
  2. Kullanıcının hesabında yetersiz bakiye.
  3. Giriş miktarlarını hesaplayan mantık hataları.

Çözüm:

  1. Giriş Miktarlarını Doğrulayın: Giriş miktarlarının doğru bir şekilde ayarlandığından emin olun. Bu, uygun kullanıcı girdi doğrulaması ve parametre ayarlarını içerir.
  2. Kullanıcı Bakiyelerini Kontrol Edin: Kullanıcının değişim için yeterli bakiyeye sahip olduğunu doğrulayın. Bu, ilgili token sözleşmelerinin `balanceOf` fonksiyonunu çağırarak yapılabilir.

10. Başarısızlık

Sebep:

  1. Bir işlem yeterli gaz olmadığı için tamamlanamaz.
  2. Bir akıllı sözleşme içinde yanlış mantık veya koşullar, işlemin başarısız olmasına neden olabilir (örneğin, başarısız bir `require` veya `assert` çağrısı).
  3. Hesap bakiyesi yetersiz olduğunda token veya kripto para işlemi yapılmaya çalışılması.
  4. ERC-20 ve ERC-721 standart token'ları ile çalışırken, işlem yetersiz izinler nedeniyle başarısız olabilir.
  5. Bir akıllı sözleşmeye yapılan çağrı, içindeki koşulları yerine getirmediğinde geri alınabilir (örneğin, `revert` fonksiyonunun kullanılması).

Çözüm:

  1. İşlemi gönderirken gaz limitini artırın.
  2. Akıllı sözleşme içindeki koşulları ve mantığı kontrol edin.
  3. Hesabın işlemi tamamlamak için yeterli fonda sahip olduğundan emin olun.
  4. `transferFrom` fonksiyonunu çağırmadan önce `approve` fonksiyonunu yeterli bir değer ile çağırın.
  5. İşlemi geri almasına neden olan koşulları kontrol edin.
  6. Komisyonlar için bakiyenizi kontrol edin.

Sonuç

ERC-20 akıllı sözleşmelerindeki bu yaygın hataları anlamak ve çözmek, Solidity programlaması, ERC-20 standardı ve merkeziyetsiz borsaların iç işleyişi hakkında sağlam bir bilgi gerektirir. Sebepleri dikkatlice gözden geçirerek ve önerilen çözümleri uygulayarak, geliştiriciler daha sağlam ve güvenilir akıllı sözleşmeler oluşturabilir ve merkeziyetsiz ekosistemde kullanıcılar için sorunsuz bir deneyim sağlayabilirler.

All posts

Connect to a wallet

Metamask