Analise smart-contract
07.08.2024

Razumevanje pogostih napak pametnih pogodb ERC-20 v Solidityju

Pametne pogodbe v ekosistemu Ethereum pogosto vsebujejo zapleteno logiko, da zagotovijo varnost in funkcionalnost decentraliziranih aplikacij. Vendar se lahko pojavijo napake zaradi različnih razlogov, kar vodi do neuspelih transakcij in morebitnih ranljivosti. Ta blog objava bo raziskala nekaj pogostih napak, s katerimi se srečujemo pri transakcijah z ERC-20 žetoni, njihove vzroke in rešitve.

1. Pancake: K

Napaka se pojavi, če se krši invarianta "produkt rezerv mora biti stalen". Ta pogoj zagotavlja, da po izvedbi zamenjave nov produkt rezerv (vključno s provizijami) ne bo manjši od starega produkta. Kršitev tega pogoja se lahko zgodi, če:

  1. Žetoni, ki so bili vneseni v bazen (amount0In ali amount1In), ne ustrezajo pričakovanim vrednostim glede na invariante formul. Prišlo je do napake pri izračunu bilanc po zamenjavi.
  2. Nekdo je poskušal manipulirati z bazenom, kar je povzročilo spremembo bilanc žetonov in obšlo standardni postopek zamenjave.
  3. Če ta pogoj ni izpolnjen, se sproži napaka 'Pancake: K', ki signalizira kršitev matematične invariance.

Kršitev invariance pomeni, da eden od osnovnih pogojev, ki zagotavljajo pravilno delovanje sistema, ni več izpolnjen. V kontekstu decentraliziranih borz, kot je PancakeSwap, je invariante običajno povezana z matematično enačbo, ki mora ostati resnična, da se ohrani ravnotežje med rezervami žetonov v likvidnostnem bazenu.


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

Rešitev:
Preverite, ali bazen vsebuje dovolj likvidnosti za izvedbo menjave in da vrednosti ne presegajo rezerv (_reserve0, _reserve1). Nenehno spremljajte rezerv bazena in sprejmite ukrepe za njihovo dopolnitev, če je potrebno.

2. TransferHelper: TRANSFER_FROM_FAILED

Ta napaka označuje neuspešno prenose žetonov z uporabo metode safeTransferFrom, kar je pogost vzorec za varno prenašanje ERC-20 žetonov.


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

Vzrok:

  1. Naslov "from" ni dodelil ali ni dodelil dovolj dovoljenj za naslov "msg.sender" za prenos žetonov (dovoljenje, odobritev).
  2. Naslov "from" nima dovolj žetonov za izvedbo prenosa. To je lahko tudi posledica dejstva, da imajo skrbniki žetonov možnost spreminjati saldo žetonov in ob času umika morda uporabnik, ki je izvedel naložbo, nima dovolj sredstev za izvedbo umika.
  3. Pogodba z žetoni morda ne implementira funkcije transferFrom ali jo implementira nepravilno.
  4. Pogodba z žetoni morda vsebuje dodatne preverbe ali omejitve v funkciji transferFrom, kar lahko povzroči preklic transakcije.
  5. Če ni dovolj plina za izvedbo transakcije, lahko transakcija ne uspe.

Rešitev:

  1. Prepričajte se, da je naslov "from" dodelil dovolj dovoljenj za "msg.sender". To lahko storite z uporabo funkcije allowance pogodbe z žetoni.
  2. Prepričajte se, da naslov "from" ima dovolj žetonov za izvedbo prenosa.
  3. Preverite, ali je naslov pogodbe z žetoni pravilen in ali pogodba izpolnjuje standard ERC-20.
  4. Preverite implementacijo funkcije transferFrom v pogodbi z žetoni. Prepričajte se, da je pravilno implementirana in nima dodatnih omejitev, ki bi lahko povzročile neuspeh.
  5. Poskusite povečati omejitev plina pri klicu transakcije, da se prepričate, da težava ni pomanjkanje plina.

3. INSUFFICIENT_LIQUIDITY

Ta napaka se pojavi, ko poskušate umakniti več likvidnosti, kot je na voljo v rezervah likvidnostnega bazena.


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

Vzrok:

  1. Likvidnostni bazen ne vsebuje dovolj enega ali obeh žetonov za izpolnitev zahtevane zamenjave.
  2. Zahtevana količina žetonov za umik (amount0Out ali amount1Out) presega razpoložljivo število žetonov v bazenu.
  3. Neskladje med rezervami v pogodbi in dejanskim stanjem bazena. Rezervi shranjeni v pogodbi morda ne ustrezajo dejanskemu stanju bilanc žetonov v bazenu zaradi napak ali manipulacij.

Rešitev:

  1. Preverite rezerve bazena in se prepričajte, da so dovolj velike za izpolnitev zahtevane zamenjave. To lahko storite z uporabo funkcije getReserves.
  2. Prepričajte se, da sta parameter amount0Out in amount1Out pravilna in ne presegata razpoložljivega števila žetonov v bazenu.
  3. Prepričajte se, da rezerve v pogodbi ustrezajo dejanskemu stanju bilanc žetonov. Za to lahko dodate preverjanje in posodabljanje rezerv pred izvedbo zamenjave.

INSUFFICIENT_LIQUIDITY

4. APPROVE_FAILED

Napaka `APPROVE_FAILED` se pojavi med izvedbo funkcije `safeApprove`. Ta funkcija je zasnovana za nastavitev količine žetonov, ki jih lastnik dovoli porabniku, da jih uporabi v njihovem imenu.


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

Vzrok:

  1. Pogodba z žetoni morda nima funkcije `approve` ali pa je ta nepravilno implementirana.
  2. Morda je težava z stanjem pogodbe z žetoni, kot so pomanjkanje sredstev ali dovoljenj.
  3. Funkcija `approve` se lahko vrne zaradi varnostnih razlogov, ki so implementirani v pogodbi z žetoni.

Rešitev:

  1. < li> Prepričajte se, da pogodba z žetoni ustreza standardu ERC-20 in vključuje pravilno implementirano funkcijo `approve`.
  2. Preverite stanje pogodbe z žetoni in se prepričajte, da ima račun dovolj žetonov za odobritev.
  3. Preverite, ali sta naslov in količina, posredovana funkciji `safeApprove`, pravilni.
  4. Nadaljujte z odpravljanjem napak tako, da preverite specifično sporočilo o napaki ali razlog za vrnitev v pogodbi z žetoni.

5. Napaka 'ds-math-sub-underflow'

Napaka `ds-math-sub-underflow` se vrže, ko operacija odštevanja preide v negativno število, tj. ko je rezultat odštevanja manjši od nič.


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

Vzrok:
Ta napaka se pojavi, ker operacija odštevanja `x - y` daje negativno število, kar ni dovoljeno za nesignirana cela števila v Solidi.

Rešitev:

  1. Prepričajte se, da je vrednost `y` vedno manjša ali enaka `x` pred izvedbo odštevanja.
  2. Implementirajte preverjanja v vašem kodi, da obravnavate primere, kjer je `y` lahko večji od `x`, in sprejmite ustrezne ukrepe, kot je vrnitev transakcije ali prilagoditev logike.

6. Napaka 'ERC20: znesek prenosa presega dovoljeno količino'

Napaka `ERC20: znesek prenosa presega dovoljeno količino` se pojavi, ko poskušate prenesti žetone v imenu drugega uporabnika, vendar znesek prenosa presega dovoljeno količino, ki jo je lastnik žetona nastavil za porabnika.

Vzrok:
Ta napaka se sproži z metodo `transferFrom` v pogodbi ERC-20, ko je znesek, ki ga je treba prenesti, večji od dovoljene količine, ki jo je lastnik žetona nastavil.

Rešitev:

  1. Prepričajte se, da je lastnik žetona nastavil ustrezno dovoljeno količino za porabnika z uporabo funkcije `approve`.
  2. Preverite trenutno dovoljeno količino pred poskusom operacije `transferFrom`.
  3. Če je potrebno, prosite lastnika žetona, naj poveča dovoljeno količino z uporabo funkcije `approve` z večjo vrednostjo.

7. TRANSFER_FAILED

Ta napaka se pojavi, ko prenos žetonov z enega naslova na drugega ne uspe. Funkcija `_safeTransfer` zagotavlja, da operacija prenosa uspe in da se vrnjeni podatki, če so prisotni, dekodirajo v `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'); }`

Vzrok:

  1. Funkcija `token.call` ne uspe izvršiti (tj. `success` je `false`).
  2. Klic vrne podatke, ki se ne dekodirajo v `true`, kar kaže na neuspeh v funkciji `transfer` pogodbe z žetoni.

Rešitev:

  1. Zagotovite skladnost z ERC-20: Preverite, ali pogodba z žetoni izpolnjuje standard ERC-20, kar vključuje pravilno implementacijo funkcije `transfer`.
  2. Pravilni parametri: Prepričajte se, da je naslov `to` veljaven in da je `value` znotraj dovoljenih meja, ob upoštevanju ravnotežja pošiljatelja in logike pogodbe.
  3. Dodatni pogoji: Preverite, ali pogodba z žetoni zahteva dodatne pogoje, kot so predhodna odobritev zneska porabe (funkcije `approve` in `allowance`).

INSUFFICIENT_LIQUIDITY

8. INSUFFICIENT_OUTPUT_AMOUNT

Ta napaka se pojavi v kontekstu decentralizirane borze, ko je izhodna količina pri zamenjavi žetonov manjša od minimalne količine, ki jo je določil uporabnik. To je zaščita, da se zagotovi, da uporabniki ne prejemajo manj žetonov, kot so pričakovali zaradi zdrsa ali sprememb cen med transakcijo.


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

Vzrok:

  1. Tržna volatilnost vpliva na cene žetonov med začetkom transakcije in njenim izvršenjem.
  2. Visoke nastavitve zdrsa, ki omogočajo pomembne odklone od pričakovanih izhodov.
  3. Nezadostna likvidnost v trgovalnem bazenu, kar povzroča večje vplive na ceno.

Rešitev:

  1. Zagotovite skladnost z ERC-20: Preverite, ali pogodba z žetoni izpolnjuje standard ERC-20, kar vključuje pravilno implementacijo funkcije `transfer`.
  2. Pravilni parametri: Prepričajte se, da je naslov `to` veljaven in da je `value` znotraj dovoljenih meja, ob upoštevanju ravnotežja pošiljatelja in logike pogodbe.
  3. Dodatni pogoji: Preverite, ali pogodba z žetoni zahteva dodatne pogoje, kot so predhodna odobritev zneska porabe (funkcije `approve` in `allowance`).

9. INSUFFICIENT_INPUT_AMOUNT

Ta napaka se pojavi, ko nobeden od vhodnih zneskov za zamenjavo žetonov ni večji od nič. Zagotavlja, da je vsaj eden od vhodnih zneskov (`amount0In` ali `amount1In`) pozitiven, da se lahko nadaljuje z zamenjavo.


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

Vzrok:

  1. Nepravilni vhodni parametri za funkcijo zamenjave.
  2. Nesufficientna sredstva na uporabniškem računu.
  3. Napake v logiki izračuna vhodnih zneskov.

Rešitev:

  1. Preverite vhodne zneske: Prepričajte se, da so vhodni zneski pravilno nastavljeni pred klicem funkcije zamenjave. To vključuje pravilno preverjanje vnosa uporabnika in nastavitev parametrov.
  2. Preverite uporabniške bilance: Preverite, ali ima uporabnik dovolj ravnotežja žetonov, namenjenih zamenjavi. To lahko storite z uporabo funkcije `balanceOf` pogodbe z žetoni.

10. Napaka

Vzrok:

  1. Transakcije ni mogoče izvršiti, ker nima dovolj plina za dokončanje vseh operacij.
  2. Nepravilna logika ali pogoji znotraj pametne pogodbe lahko povzročijo neuspeh izvedbe (na primer, neuspeh klica require ali assert).
  3. Poskus izvršitve transakcije z žetoni ali kriptovalutami, ko stanje računa ni zadostno.
  4. Pri delu z žetoni standardov ERC-20 in ERC-721 lahko transakcija ne uspe zaradi nezadostnih dovoljenj.
  5. Klic pametne pogodbe se lahko vrne zaradi neuspeha pri izpolnjevanju pogojev znotraj nje (npr. z uporabo funkcije revert).

Rešitev:

  1. Povečajte omejitev plina pri pošiljanju transakcije.
  2. Preverite pogoje in logiko znotraj pametne pogodbe.
  3. Prepričajte se, da ima račun dovolj sredstev za dokončanje transakcije.
  4. Pred klicem funkcije transferFrom pokličite funkcijo approve z zadostno vrednostjo.
  5. Preverite pogoje, ki povzročajo vračanje transakcije.
  6. Preverite stanje vašega računa za provizije.

Zaključek

Razumevanje in reševanje teh pogostih napak v pametnih pogodbah ERC-20 zahteva trdno razumevanje programiranja v Soliditiju, standarda ERC-20 in notranjega delovanja decentraliziranih borz. Z natančnim pregledu vzrokov in izvajanjem predlaganih rešitev lahko razvijalci ustvarijo bolj robustne in zanesljive pametne pogodbe, kar zagotavlja brezskrbno izkušnjo za uporabnike v decentraliziranem ekosistemu.

All posts

Connect to a wallet

Metamask