Analise smart-contract
07.08.2024

Yleisten ERC-20-älysopimusvirheiden ymmärtäminen Solidityssä

Älykkäät sopimukset Ethereum-ekosysteemissä sisältävät usein monimutkaista logiikkaa varmistaakseen hajautettujen sovellusten turvallisuuden ja toiminnallisuuden. Virheitä voi kuitenkin esiintyä monista syistä, mikä voi johtaa epäonnistuneisiin transaktioihin ja mahdollisiin haavoittuvuuksiin. Tämä blogikirjoitus käsittelee joitakin yleisiä virheitä, joita esiintyy ERC-20 tokenien transaktioissa, niiden syitä ja ratkaisuja.

1. Pancake: K

Virhe ilmenee, jos invariantti "reservien tuotteen on oltava vakio" rikotaan. Tämä ehto takaa, että vaihdon suorittamisen jälkeen uuden reservien tuotteen (mukaan lukien palkkiot) ei pitäisi olla pienempi kuin vanha tuote. Tämä ehto voi rikkoontua, jos:

  1. Altaaseen syötetyt tokenit (amount0In tai amount1In) eivät vastaa invariantti-formulaa vastaavia odotettuja arvoja. Tapahtui virhe saldojen laskemisessa vaihdon jälkeen.
  2. Joku yritti manipuloida allasta, mikä aiheutti token-saldojen muuttumisen ohittaen tavanomaisen vaihto-prosessin.
  3. Jos tätä ehtoa ei täytetä, 'Pancake: K' virhe ilmenee, mikä merkitsee matemaattisen invariantin rikkomista.

Invariantin rikkominen tarkoittaa, että yksi järjestelmän oikean toiminnan perusedellytyksistä ei enää täyty. Hajautettujen vaihdon yhteydessä, kuten PancakeSwap, invariantti on yleensä matemaattinen yhtälö, jonka on pysyttävä totena säilyttääkseen tasapaino token-reserveissa likviditeetti-altaassa.


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

Ratkaisu:
Tarkista, että altaassa on riittävästi likviditeettiä vaihdon suorittamiseen ja että arvot eivät ylitä reserveja (_reserve0, _reserve1). Seuraa jatkuvasti altaan reserveja ja ryhdy toimiin niiden täyttämiseksi tarvittaessa.

2. TransferHelper: TRANSFER_FROM_FAILED

Tämä virhe tarkoittaa epäonnistunutta token-siirtoa käyttäen safeTransferFrom-menetelmää, joka on yleinen malli ERC-20 tokenien turvalliseen siirtämiseen.


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

Syy:

  1. Alustajakäyttäjä ei ole myöntänyt tai ei ole myöntänyt tarpeeksi oikeuksia msg.sender-osoitteelle tokenien siirtämiseen (allowance, approve).
  2. Alustajakäyttäjällä ei ole riittävästi tokeneita siirron suorittamiseen. Tämä voi myös johtua siitä, että token-hallitsijat voivat muuttaa tokenin saldoa ja noston aikana käyttäjällä ei välttämättä ole tarpeeksi saldoa nostoa varten.
  3. Token-sopimus ei ehkä toteuta transferFrom-funktiota tai se on toteutettu virheellisesti.
  4. Token-sopimus saattaa sisältää lisätarkistuksia tai rajoituksia transferFrom-funktiossa, mikä voi aiheuttaa transaktion peruutuksen.
  5. Jos kaasua ei ole riittävästi transaktion suorittamiseen, transaktio voi epäonnistua.

Ratkaisu:

  1. Varmista, että alustajakäyttäjä on myöntänyt riittävästi allowancea msg.sender-osoitteelle. Tämä voidaan tehdä kutsumalla token-sopimuksen allowance-funktiota.
  2. Varmista, että alustajakäyttäjällä on riittävästi tokeneita siirron suorittamiseen.
  3. Tarkista, että token-sopimuksen osoite on oikea ja että sopimus on ERC-20-yhteensopiva.
  4. Tarkista transferFrom-funktion toteutus token-sopimuksessa. Varmista, että se on toteutettu oikein eikä sisällä lisäehtoja, jotka voisivat aiheuttaa epäonnistumisen.
  5. Yritä nostaa kaasun rajaa kutsuessasi transaktiota varmistaaksesi, ettei ongelma ole kaasun puute.

3. INSUFFICIENT_LIQUIDITY

Tämä virhe ilmenee, kun yritetään nostaa enemmän likviditeettiä kuin mitä on saatavilla likviditeetti-altaan reserveissa.


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

Syy:

  1. Likviditeetti-allas ei sisällä riittävästi yhdestä tai molemmista tokeneista täyttämään pyydettyä vaihtoa.
  2. Pyydetty määrä tokeneita nostoon (amount0Out tai amount1Out) ylittää altaan saatavilla olevien tokenien määrän.
  3. Poikkeama sopimuksen reservejen ja altaan todellisen tilan välillä. Sopimuksessa säilytetyt reserveet eivät välttämättä vastaa altaan todellista token-saldoa virheiden tai manipulaation vuoksi.

Ratkaisu:

  1. Tarkista altaan reserveet ja varmista, että ne ovat riittäviä pyydetyn vaihdon täyttämiseksi. Tämä voidaan tehdä käyttämällä getReserves-funktiota.
  2. Varmista, että amount0Out ja amount1Out -parametrit ovat oikeat eivätkä ylitä altaassa olevien tokenien määrää.
  3. Varmista, että sopimuksen reserveet vastaavat todellista token-saldoa. Voit tehdä tämän lisäämällä tarkistuksia ja päivittämällä reserveet ennen vaihdon suorittamista.

INSUFFICIENT_LIQUIDITY

4. APPROVE_FAILED

`APPROVE_FAILED`-virhe ilmenee `safeApprove`-funktion suorittamisen aikana. Tämä funktio on suunniteltu määrittämään, kuinka monta tokenia omistaja sallii kuluttajan käyttää puolestaan.


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

Syy:

  1. Token-sopimuksessa ei ehkä ole `approve`-funktiota tai se on toteutettu virheellisesti.
  2. Token-sopimuksen tilassa voi olla ongelmia, kuten riittämätön saldo tai allowance.
  3. `approve`-funktio saattaa palauttaa virheen turvallisuussyistä, jotka on toteutettu token-sopimuksessa.

Ratkaisu:

  1. Varmista, että token-sopimus täyttää ERC-20-standardin ja sisältää oikein toteutetun ` approve`-funktion.
  2. Tarkista token-sopimuksen tila ja varmista, että tilillä on tarpeeksi tokeneita hyväksyntää varten.
  3. Varmista, että `safeApprove`-funktiolle annetut osoite ja määrä ovat oikeat.
  4. Debugoi tarkemmin tarkistamalla token-sopimuksen erityinen virheviesti tai syy revert-toimintoon.

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

`ds-math-sub-underflow`-virhe ilmenee, kun vähennyslaskenta alittaa nollan, eli kun vähennyksen tulos on pienempi kuin nolla.


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

Syy:
Tämä virhe ilmenee, koska vähennyslaskenta `x - y` tuottaa negatiivisen numeron, mikä ei ole sallittua epämerkitsemättömille kokonaisluvuille Solidityssä.

Ratkaisu:

  1. Varmista, että `y` on aina pienempi tai yhtä suuri kuin `x` ennen vähennyslaskentaa.
  2. Toteuta tarkistuksia koodissasi käsittelemään tapauksia, joissa `y` voi olla suurempi kuin `x`, ja ota tarvittavat toimet, kuten transaktion palauttaminen tai logiikan säätäminen.

6. Virhe 'ERC20: transfer amount exceeds allowance'

Virhe 'ERC20: transfer amount exceeds allowance' ilmenee, kun yritetään siirtää tokeneita toisen käyttäjän puolesta, mutta siirrettävä määrä ylittää sen sallitun määrän, jonka tokenin omistaja on asettanut käyttäjälle.

Syy:
Tämä virhe ilmenee ERC-20 tokenin `transferFrom`-funktion kautta, kun siirrettävä määrä ylittää tokenin omistajan määrittämän sallitun rajan.

Ratkaisu:

  1. Varmista, että tokenin omistaja on asettanut riittävän sallimisen käyttäjälle `approve`-funktion avulla.
  2. Tarkista nykyinen salliminen ennen `transferFrom`-toiminnon suorittamista.
  3. Tarvittaessa pyydä tokenin omistajaa lisäämään sallimista kutsumalla `approve`-funktiota suuremmalla arvolla.

7. TRANSFER_FAILED

Tämä virhe ilmenee, kun tokenien siirto yhdeltä osoitteelta toiselle epäonnistuu. `_safeTransfer`-funktio varmistaa, että siirto onnistuu ja palautettu data, jos sellaista on, dekoodataan arvoksi `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'); }`

Syy:

  1. `token.call`-funktio ei suoritettu onnistuneesti (ts. `success` on `false`).
  2. Kutsu palauttaa dataa, joka ei dekoodaa `true`-arvoksi, mikä viittaa token-sopimuksen `transfer`-funktion epäonnistumiseen.

Ratkaisu:

  1. Varmista ERC-20-yhteensopivuus: Tarkista, että token-sopimus noudattaa ERC-20-standardeja, mukaan lukien `transfer`-funktion oikea toteutus.
  2. Oikeat parametrit: Varmista, että `to`-osoite on voimassa ja `value` on sallittujen rajoissa ottaen huomioon lähettäjän saldo ja sopimuksen logiikka.
  3. Lisäehdot: Tarkista, vaatiiko token-sopimus lisäehtoja, kuten kulutuksen ennakkohyväksyntää (`approve` ja `allowance` -toiminnot).

INSUFFICIENT_LIQUIDITY

8. INSUFFICIENT_OUTPUT_AMOUNT

Tämä virhe ilmenee hajautetun vaihdon yhteydessä, kun token-vaihdon tulosmääärä on pienempi kuin käyttäjän määrittämä vähimmäismäärä. Tämä on suojatoimenpide varmistaakseen, että käyttäjät eivät saa vähemmän tokeneita kuin he odottivat liukuman tai hintamuutosten vuoksi transaktion aikana.


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

Syy:

  1. Markkinahäiriöt, jotka vaikuttavat tokenin hintoihin sen ajan välillä, kun transaktio käynnistetään ja kun se suoritetaan.
  2. Korkeat liukuman asetukset, jotka sallivat merkittäviä poikkeamia odotetuissa tuloksissa.
  3. Riittämätön likviditeetti kaupankäyntialtaassa, mikä aiheuttaa suurempia hintavaikutuksia.

Ratkaisu:

  1. Varmista ERC-20-yhteensopivuus: Tarkista, että token-sopimus noudattaa ERC-20-standardeja, mukaan lukien `transfer`-funktion oikea toteutus.
  2. Oikeat parametrit: Varmista, että `to`-osoite on voimassa ja `value` on sallittujen rajoissa ottaen huomioon lähettäjän saldo ja sopimuksen logiikka.
  3. Lisäehdot: Tarkista, vaatiiko token-sopimus lisäehtoja, kuten kulutuksen ennakkohyväksyntää (`approve` ja `allowance` -toiminnot).

9. INSUFFICIENT_INPUT_AMOUNT

Tämä virhe ilmenee, kun kumpikaan syötteistä token-vaihdossa ei ole suurempi kuin nolla. Tämä varmistaa, että ainakin yksi syötemääristä (`amount0In` tai `amount1In`) on positiivinen vaihdon jatkamiseksi.


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

Syy:

  1. Virheelliset syöteparametrit vaihto-funktiolle.
  2. Riittämätön saldo käyttäjän tilillä.
  3. Virheitä syötteiden määrien laskennassa.

Ratkaisu:

  1. Tarkista syötemäärät: Varmista, että syötemäärät on asetettu oikein ennen vaihto-funktion kutsumista. Tämä sisältää oikean käyttäjätietojen validoinnin ja parametrien asettamisen.
  2. Tarkista käyttäjän saldot: Varmista, että käyttäjällä on riittävästi tokeneita vaihdettavaksi. Tämä voidaan tehdä kutsumalla vastaavien token-sopimusten `balanceOf`-funktiota.

10. Virhe

Syy:

  1. Transaktiota ei voida suorittaa, koska kaasua ei ole riittävästi kaikkien toimintojen loppuun saattamiseen.
  2. Virheellinen logiikka tai ehdot älykkäässä sopimuksessa voivat aiheuttaa suorittamisen epäonnistuvan (esimerkiksi require- tai assert-kutsu, joka epäonnistuu).
  3. Yrittäminen suorittaa token- tai kryptovaluuttatransaktio, kun tilin saldo on riittämätön.
  4. ERC-20- ja ERC-721-standardeilla toimivissa tokeneissa transaktio voi epäonnistua riittämättömien oikeuksien vuoksi.
  5. Älykäs sopimus voi palautua takaisin epäonnistuneen ehtojen täyttämisen vuoksi (esim. revert-funktion käyttö).

Ratkaisu:

  1. Lisää kaasun raja transaktion lähettämisen yhteydessä.
  2. Tarkista älykkään sopimuksen ehdot ja logiikka.
  3. Varmista, että tilillä on tarpeeksi varoja transaktion loppuun saattamiseen.
  4. Kutsu approve-funktiota riittävällä arvolla ennen transferFrom-kutsua.
  5. Tarkista ehdot, jotka aiheuttavat transaktion palautumisen.
  6. Tarkista saldo komissioiden varalta.

Yhteenveto

Näiden yleisten virheiden ymmärtäminen ja ratkaiseminen ERC-20 älykkäissä sopimuksissa vaatii vahvan ymmärryksen Solidity-ohjelmoinnista, ERC-20 -standardeista ja hajautettujen vaihtojen sisäisestä toiminnasta. Tarkistamalla huolellisesti syyt ja toteuttamalla ehdotetut ratkaisut, kehittäjät voivat luoda kestävämpiä ja luotettavampia älykkäitä sopimuksia, mikä varmistaa saumattoman kokemuksen käyttäjille hajautetussa ekosysteemissä.

All posts

Connect to a wallet

Metamask