Analise smart-contract
07.08.2024

Memahami Kesalahan Umum Kontrak Cerdas ERC-20 di Solidity

Kontrak pintar dalam ekosistem Ethereum sering kali mengandung logika rumit untuk memastikan keamanan dan fungsionalitas aplikasi terdesentralisasi. Namun, kesalahan dapat terjadi karena berbagai alasan, yang mengarah pada transaksi yang gagal dan potensi kerentanan. Pos blog ini akan membahas beberapa kesalahan umum yang ditemui dalam transaksi token ERC-20, penyebabnya, dan solusinya.

1. Pancake: K

Kesalahan ini terjadi jika invariant ‘produk cadangan harus konstan’ dilanggar. Kondisi ini menjamin bahwa setelah swap dilakukan, produk cadangan baru (termasuk komisi) tidak akan kurang dari produk lama. Pelanggaran kondisi ini dapat terjadi jika:

  1. Token yang dimasukkan ke dalam pool (amount0In atau amount1In) tidak sesuai dengan nilai yang diharapkan menurut rumus invariant. Ada kesalahan dalam perhitungan saldo setelah swap.
  2. Seseorang mencoba memanipulasi pool, yang menyebabkan saldo token berubah, melewati proses swap standar.
  3. Jika kondisi ini tidak terpenuhi, kesalahan ‘Pancake: K’ akan muncul, menandakan pelanggaran invariant matematika.

Pelanggaran invariant berarti salah satu kondisi dasar yang memastikan operasi sistem yang benar tidak lagi terpenuhi. Dalam konteks pertukaran terdesentralisasi seperti PancakeSwap, invariant biasanya terkait dengan persamaan matematika yang harus tetap benar untuk mempertahankan keseimbangan antara cadangan token di pool likuiditas.


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

Solusi:
Periksa apakah pool memiliki likuiditas yang cukup untuk melakukan pertukaran dan bahwa nilai-nilainya tidak melebihi cadangan (_reserve0, _reserve1). Pantau terus cadangan pool dan ambil langkah-langkah untuk mengisinya jika perlu.

2. TransferHelper: TRANSFER_FROM_FAILED

Kesalahan ini menunjukkan kegagalan transfer token menggunakan metode safeTransferFrom, yang merupakan pola umum untuk mentransfer token ERC-20 dengan aman.


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');
  }

Penyebab:

  1. Alamat dari belum memberikan atau belum memberikan izin yang cukup untuk alamat msg.sender untuk mentransfer token (allowance, approve).
  2. Alamat dari tidak memiliki token yang cukup untuk melakukan transfer. Ini juga mungkin disebabkan oleh kenyataan bahwa administrator token memiliki kemampuan untuk mengubah saldo token dan pada saat penarikan, pengguna yang melakukan investasi mungkin tidak memiliki saldo yang cukup untuk melakukan penarikan.
  3. Kontrak token mungkin tidak mengimplementasikan fungsi transferFrom atau mengimplementasikannya dengan tidak benar.
  4. Kontrak token mungkin mengandung pemeriksaan atau pembatasan tambahan dalam fungsi transferFrom, yang dapat menyebabkan transaksi dibatalkan.
  5. Jika tidak ada cukup gas untuk mengeksekusi transaksi, transaksi mungkin gagal.

Solusi:

  1. Pastikan bahwa alamat dari telah memberikan izin yang cukup untuk msg.sender. Ini dapat dilakukan dengan memanggil fungsi allowance dari kontrak token.
  2. Pastikan bahwa alamat dari memiliki token yang cukup untuk melakukan transfer.
  3. Verifikasi bahwa alamat kontrak token benar dan bahwa kontrak tersebut sesuai dengan ERC-20.
  4. Periksa implementasi fungsi transferFrom di kontrak token. Pastikan itu diimplementasikan dengan benar dan tidak memiliki pembatasan tambahan yang dapat menyebabkan kegagalan.
  5. Cobalah meningkatkan batas gas saat memanggil transaksi untuk memastikan bahwa masalahnya bukan karena kekurangan gas.

3. INSUFFICIENT_LIQUIDITY

Kesalahan ini terjadi ketika mencoba menarik lebih banyak likuiditas daripada yang tersedia dalam cadangan pool likuiditas.


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

Penyebab:

  1. Pool likuiditas tidak mengandung jumlah token yang cukup dari satu atau kedua token untuk memenuhi pertukaran yang diminta.
  2. Jumlah token yang diminta untuk penarikan (amount0Out atau amount1Out) melebihi jumlah token yang tersedia di pool.
  3. Ketidakcocokan antara cadangan dalam kontrak dan keadaan aktual pool. Cadangan yang disimpan dalam kontrak mungkin tidak sesuai dengan saldo token aktual di pool karena kesalahan atau manipulasi.

Solusi:

  1. Periksa cadangan pool dan pastikan mereka cukup untuk memenuhi pertukaran yang diminta. Ini dapat dilakukan dengan menggunakan fungsi getReserves.
  2. Pastikan bahwa parameter amount0Out dan amount1Out benar dan tidak melebihi jumlah token yang tersedia di pool.
  3. Pastikan bahwa cadangan dalam kontrak cocok dengan saldo token aktual. Untuk melakukan ini, Anda dapat menambahkan pemeriksaan dan pembaruan cadangan sebelum melakukan pertukaran.

INSUFFICIENT_LIQUIDITY

4. APPROVE_FAILED

Kesalahan `APPROVE_FAILED` terjadi selama eksekusi fungsi `safeApprove`. Fungsi ini dirancang untuk menetapkan jumlah token yang diizinkan oleh pemilik kepada penghabis untuk digunakan atas nama mereka.


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');
}

Penyebab:

  1. Kontrak token mungkin tidak memiliki fungsi `approve` atau fungsi tersebut mungkin diimplementasikan dengan tidak benar.
  2. Mungkin ada masalah dengan status kontrak token, seperti saldo atau allowance yang tidak mencukupi.
  3. Fungsi `approve` bisa saja membalikkan untuk alasan keamanan yang diterapkan di kontrak token.

Solusi:

  1. Pastikan bahwa kontrak token sesuai dengan standar ERC-20 dan mencakup fungsi `approve` yang diimplementasikan dengan benar.
  2. Periksa status kontrak token dan pastikan bahwa akun memiliki cukup token untuk disetujui.
  3. Verifikasi bahwa alamat dan jumlah yang diteruskan ke fungsi `safeApprove` adalah benar.
  4. Debug lebih lanjut dengan memeriksa pesan kesalahan spesifik atau alasan pembalikan dalam kontrak token.

5. Gagal dengan kesalahan 'ds-math-sub-underflow'

Kesalahan `ds-math-sub-underflow` dilemparkan ketika operasi pengurangan mengalami underflow, yaitu ketika hasil pengurangan kurang dari nol.


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

Penyebab:
Kesalahan ini terjadi karena operasi pengurangan `x - y` menghasilkan angka negatif, yang tidak diizinkan untuk bilangan bulat tak bertanda di Solidity.

Solusi:

  1. Pastikan bahwa nilai `y` selalu kurang dari atau sama dengan `x` sebelum melakukan pengurangan.
  2. Implementasikan pemeriksaan dalam kode Anda untuk menangani kasus di mana `y` mungkin lebih besar dari `x` dan ambil tindakan yang sesuai, seperti membatalkan transaksi atau menyesuaikan logika.

6. Gagal dengan kesalahan 'ERC20: jumlah transfer melebihi allowance'

Kesalahan `ERC20: jumlah transfer melebihi allowance` terjadi ketika ada upaya untuk mentransfer token atas nama pengguna lain, tetapi jumlah yang ditransfer melebihi allowance yang telah ditetapkan oleh pemilik token untuk penghabis.

Penyebab:
Kesalahan ini dilemparkan oleh fungsi `transferFrom` dari kontrak token ERC-20 ketika jumlah yang akan ditransfer melebihi batas yang diizinkan yang ditetapkan oleh pemilik token.

Solusi:

  1. Pastikan bahwa pemilik token telah menetapkan allowance yang memadai untuk penghabis menggunakan fungsi `approve`.
  2. Periksa allowance saat ini sebelum mencoba operasi `transferFrom`.
  3. Jika perlu, minta pemilik token untuk meningkatkan allowance dengan memanggil fungsi `approve` dengan nilai yang lebih tinggi.

7. TRANSFER_FAILED

Kesalahan ini terjadi ketika transfer token dari satu alamat ke alamat lain gagal. Fungsi `_safeTransfer` memastikan operasi transfer berhasil dan data yang dikembalikan, jika ada, didekode menjadi `true`.


    `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'); }`

Penyebab:

  1. Fungsi `token.call` tidak berhasil dieksekusi (misalnya, `success` adalah `false`).
  2. Panggilan mengembalikan data yang tidak terdekode menjadi `true`, menunjukkan kegagalan dalam fungsi `transfer` kontrak token.

Solusi:

  1. Pastikan Kepatuhan ERC-20: Verifikasi bahwa kontrak token mematuhi standar ERC-20, yang mencakup implementasi fungsi `transfer` dengan benar.
  2. Parameter yang Benar: Pastikan alamat `to` valid dan `value` berada dalam batas yang diperbolehkan, mengingat saldo pengirim dan logika kontrak.
  3. Kondisi Tambahan: Periksa apakah kontrak token memerlukan kondisi tambahan seperti persetujuan sebelumnya untuk jumlah pengeluaran (`approve` dan fungsi `allowance`).

INSUFFICIENT_LIQUIDITY

8. INSUFFICIENT_OUTPUT_AMOUNT

Kesalahan ini terjadi dalam konteks pertukaran terdesentralisasi ketika jumlah output dari swap token kurang dari jumlah minimum yang ditentukan oleh pengguna. Ini adalah perlindungan untuk memastikan pengguna tidak menerima token lebih sedikit dari yang mereka harapkan akibat slippage atau perubahan harga selama transaksi.


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

Penyebab:

  1. Volatilitas pasar yang mempengaruhi harga token antara waktu transaksi dimulai dan saat dieksekusi.
  2. Pengaturan slippage yang tinggi, yang memungkinkan deviasi signifikan dalam output yang diharapkan.
  3. Likuiditas yang tidak mencukupi dalam pool perdagangan, menyebabkan dampak harga yang lebih besar.

Solusi:

  1. Pastikan Kepatuhan ERC-20: Verifikasi bahwa kontrak token mematuhi standar ERC-20, yang mencakup implementasi fungsi `transfer` dengan benar.
  2. Parameter yang Benar: Pastikan alamat `to` valid dan `value` berada dalam batas yang diperbolehkan, mengingat saldo pengirim dan logika kontrak.
  3. Kondisi Tambahan: Periksa apakah kontrak token memerlukan kondisi tambahan seperti persetujuan sebelumnya untuk jumlah pengeluaran (`approve` dan fungsi `allowance`).

9. INSUFFICIENT_INPUT_AMOUNT

Kesalahan ini terjadi ketika tidak ada dari jumlah input untuk swap token yang lebih besar dari nol. Ini memastikan bahwa setidaknya satu dari jumlah input (`amount0In` atau `amount1In`) adalah positif untuk melanjutkan swap.


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

Penyebab:

  1. Parameter input yang tidak benar untuk fungsi swap.
  2. Saldo yang tidak mencukupi di akun pengguna.
  3. Kesalahan dalam logika yang menghitung jumlah input.

Solusi:

  1. Validasi Jumlah Input: Pastikan bahwa jumlah input sudah diatur dengan benar sebelum memanggil fungsi swap. Ini melibatkan validasi input pengguna dan pengaturan parameter.
  2. Periksa Saldo Pengguna: Verifikasi bahwa pengguna memiliki saldo yang cukup dari token yang dimaksudkan untuk swap. Ini dapat dilakukan dengan memanggil fungsi `balanceOf` dari kontrak token yang bersangkutan.

10. Gagal

Penyebab:

  1. Sebuah transaksi tidak dapat dieksekusi karena kekurangan gas untuk menyelesaikan semua operasi.
  2. Logika atau kondisi yang tidak benar dalam kontrak pintar dapat menyebabkan eksekusi gagal (misalnya, panggilan ke require atau assert yang gagal).
  3. Upaya untuk mengeksekusi transaksi token atau cryptocurrency ketika saldo akun tidak mencukupi.
  4. Dalam kasus bekerja dengan token standar ERC-20 dan ERC-721, transaksi mungkin gagal karena izin yang tidak mencukupi.
  5. Panggilan ke kontrak pintar mungkin dibatalkan karena kegagalan untuk memenuhi kondisi di dalamnya (misalnya menggunakan fungsi revert).

Solusi:

  1. Tambahkan batas gas saat mengirim transaksi.
  2. Periksa kondisi dan logika dalam kontrak pintar.
  3. Pastikan akun memiliki cukup dana untuk menyelesaikan transaksi.
  4. Panggil fungsi approve dengan nilai yang cukup sebelum memanggil transferFrom.
  5. Periksa kondisi yang menyebabkan transaksi dibatalkan.
  6. Periksa saldo Anda untuk komisi.

Kesimpulan

Memahami dan menyelesaikan kesalahan umum dalam kontrak pintar ERC-20 memerlukan pemahaman yang solid tentang pemrograman Solidity, standar ERC-20, dan cara kerja pertukaran terdesentralisasi. Dengan memeriksa penyebab dan menerapkan solusi yang disarankan, pengembang dapat membuat kontrak pintar yang lebih tangguh dan andal, memastikan pengalaman pengguna yang mulus dalam ekosistem terdesentralisasi.

All posts

Connect to a wallet

Metamask