Analise smart-contract
07.08.2024

Izpratne par biežāk sastopamajām ERC-20 viedo līgumu kļūdām Solidity programmatūrā

Viedie līgumi Ethereum ekosistēmā bieži satur sarežģītu loģiku, lai nodrošinātu decentralizētu lietojumprogrammu drošību un funkcionalitāti. Tomēr kļūdas var rasties dažādu iemeslu dēļ, kas noved pie neveiksmīgām darījumiem un potenciālām ievainojamībām. Šajā emuāra ierakstā tiks apskatītas dažas izplatītas kļūdas, ar kurām sastopas ERC-20 tokenu darījumos, to cēloņi un risinājumi.

1. Pancake: K

Kļūda rodas, ja tiek pārkāpts invariants ‘rezervju produkts ir jābūt konstantam’. Šis nosacījums garantē, ka pēc swap veikšanas jaunais rezervju produkts (ieskaitot komisijas) nebūs mazāks par veco produktu. Šī nosacījuma pārkāpums var notikt, ja:

  1. Tokeni, kas ievadīti baseinā (amount0In vai amount1In), neatbilst gaidītajām vērtībām saskaņā ar invarianta formulu. Bija kļūda bilances aprēķinā pēc swap.
  2. Kāds mēģināja manipulēt ar baseinu, kas izraisīja tokenu bilances izmaiņas, apejot standarta swap procesu.
  3. Ja šis nosacījums nav izpildīts, tiek izsviests ‘Pancake: K’ kļūdas paziņojums, kas norāda uz matemātiska invarianta pārkāpumu.

Invarianta pārkāpums nozīmē, ka viens no fundamentālajiem nosacījumiem, kas nodrošina sistēmas pareizu darbību, vairs netiek izpildīts. Decentralizētu biržu, piemēram, PancakeSwap, kontekstā invariants parasti ir saistīts ar matemātisku vienādojumu, kas jāpaliek patiesam, lai uzturētu līdzsvaru starp tokenu rezervēm likviditātes baseinā.


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

Risinājums:
Pārbaudi, vai baseinā ir pietiekami daudz likviditātes, lai veiktu apmaiņu, un vai vērtības nepārsniedz rezervju (_reserve0, _reserve1) līmeni. Nepārtraukti uzraugi baseina rezerves un veic nepieciešamos soļus, lai tās papildinātu, ja nepieciešams.

2. TransferHelper: TRANSFER_FROM_FAILED

Šī kļūda nozīmē, ka tokenu pārskaitījums, izmantojot safeTransferFrom metodi, ir neizdevies, kas ir izplatīts modelis, lai droši pārskaitītu ERC-20 tokenus.


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

Cēlonis:

  1. Adrese from nav piešķīrusi vai nav piešķīrusi pietiekamas atļaujas, lai msg.sender adrese varētu pārskaitīt tokenus (atļauja, approve).
  2. Adrese from nav pietiekami daudz tokenu, lai veiktu pārskaitījumu. Tas var arī būt saistīts ar to, ka tokenu administratori var mainīt tokenu bilanci, un izņemšanas brīdī lietotājam, kurš veicis ieguldījumu, var nebūt pietiekami daudz bilances, lai veiktu izņemšanu.
  3. Tokenu līgums var neīstenot transferFrom funkciju vai īstenot to nepareizi.
  4. Tokenu līgumā var būt papildus pārbaudes vai ierobežojumi transferFrom funkcijā, kas var izraisīt darījuma atcelšanu.
  5. Ja nav pietiekami daudz gāzes darījuma izpildei, darījums var neizdoties.

Risinājums:

  1. Pārliecinies, vai adrese from ir piešķīrusi pietiekamu atļauju msg.sender. To var izdarīt, izsaucot tokenu līguma atļaujas funkciju.
  2. Pārliecinies, vai adrese from ir pietiekami daudz tokenu, lai veiktu pārskaitījumu.
  3. Pārbaudi, vai tokenu līguma adrese ir pareiza un vai līgums atbilst ERC-20 standartam.
  4. Pārbaudi transferFrom funkcijas īstenojumu tokenu līgumā. Pārliecinies, ka tā ir īstenota pareizi un tajā nav nekādu papildus ierobežojumu, kas varētu izraisīt kļūmi.
  5. Mēģini palielināt gāzes limitu, izsaucot darījumu, lai pārliecinātos, ka problēma nav gāzes trūkums.

3. INSUFFICIENT_LIQUIDITY

Šī kļūda rodas, mēģinot izņemt vairāk likviditātes, nekā ir pieejama likviditātes baseina rezervēs.


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

Cēlonis:

  1. Likviditātes baseins nesatur pietiekami daudz viena vai abu tokenu, lai izpildītu pieprasīto apmaiņu.
  2. Pieprasītais tokenu daudzums izņemšanai (amount0Out vai amount1Out) pārsniedz pieejamo tokenu skaitu baseinā.
  3. Nesakritība starp rezervēm līgumā un faktiskā baseina stāvokli. Rezerves, kas uzglabātas līgumā, var neatbilst faktiskajam tokenu bilances stāvoklim baseinā kļūdu vai manipulāciju dēļ.

Risinājums:

  1. Pārbaudi baseina rezerves un pārliecinies, vai tās ir pietiekamas, lai izpildītu pieprasīto apmaiņu. To var izdarīt, izmantojot getReserves funkciju.
  2. Pārliecinies, vai amount0Out un amount1Out parametri ir pareizi un nepārsniedz pieejamo tokenu skaitu baseinā.
  3. Pārliecinies, vai rezerves līgumā atbilst faktiskajai tokenu bilancei. Lai to izdarītu, vari pievienot pārbaudi un atjaunināt rezerves pirms apmaiņas veikšanas.

INSUFFICIENT_LIQUIDITY

4. APPROVE_FAILED

`APPROVE_FAILED` kļūda rodas, izpildot `safeApprove` funkciju. Šī funkcija ir paredzēta, lai noteiktu tokenu daudzumu, kuru īpašnieks ļauj iztērēt viņa vārdā.


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

Cēlonis:

  1. Tokenu līgums varbūt nav īstenojis `approve` funkciju vai arī tā var būt nepareizi īstenota.
  2. Var būt problēma ar tokenu līguma stāvokli, piemēram, nepietiekama bilance vai atļauja.
  3. `approve` funkcija var atgriezt kļūdu drošības iemeslu dēļ, kas īstenoti tokenu līgumā.

Risinājums:

  1. Pārliecinies, ka tokenu līgums atbilst ERC-20 standartam un ietver pareizi īstenotu `approve` funkciju.
  2. Pārbaudi tokenu līguma stāvokli un pārliecinies, ka kontā ir pietiekami daudz tokenu, lai apstiprinātu.
  3. Verificē, vai adrese un summa, kas nodota `safeApprove` funkcijai, ir pareiza.
  4. Veic detalizētāku kļūdas pārbaudi, lai noteiktu konkrētu kļūdas ziņojumu vai iemeslu funkcijas atgriešanai tokenu līgumā.

5. Fail with error 'ds-math-sub-underflow'

`ds-math-sub-underflow` kļūda tiek izmesta, kad atņemšanas operācija ir nepietiekama, t.i., kad atņemšanas rezultāts ir mazāks par nulli.


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

Cēlonis:
Šī kļūda rodas, jo atņemšanas operācija `x - y` rezultātā iegūtais skaitlis ir negatīvs, kas nav atļauts bezzīmju veselos skaitļos Solidity.

Risinājums:

  1. Pārliecinies, ka `y` vērtība vienmēr ir mazāka vai vienāda ar `x` pirms atņemšanas veikšanas.
  2. Ieviesti pārbaudes savā kodā, lai apstrādātu gadījumus, kad `y` var būt lielāks par `x`, un veikt atbilstošas darbības, piemēram, atgriezt darījumu vai pielāgot loģiku.

6. Kļūda 'ERC20: transfer amount exceeds allowance'

Kļūda `ERC20: transfer amount exceeds allowance` rodas, kad tiek mēģināts pārskaitīt tokenus kāda cita lietotāja vārdā, bet pārskaitītā summa pārsniedz atļauju, ko tokenu īpašnieks ir iestatījis tērētājam.

Cēlonis:
Šī kļūda tiek izsviesta ar `transferFrom` funkciju ERC-20 tokenu līgumā, kad pārskaitāmā summa ir lielāka par atļauto limitu, ko ir noteicis tokenu īpašnieks.

Risinājums:

  1. Pārliecinies, ka tokenu īpašnieks ir iestādījis atbilstošu atļauju tērētājam, izmantojot `approve` funkciju.
  2. Pārbaudi pašreizējo atļauju pirms mēģinājuma veikt `transferFrom` operāciju.
  3. Ja nepieciešams, lūdz tokenu īpašniekam palielināt atļauju, izsaucot `approve` funkciju ar lielāku vērtību.

7. TRANSFER_FAILED

Šī kļūda rodas, kad tokenu pārskaitīšana no vienas adreses uz citu neizdodas. `_safeTransfer` funkcija nodrošina, ka pārskaitīšanas operācija veiksmīgi izpildās un atgrieztie dati, ja tādi ir, dekodējas uz `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'); }`

Cēlonis:

  1. `token.call` funkcija neizpildās veiksmīgi (t.i., `success` ir `false`).
  2. Izsaukums atgriež datus, kas dekodējas nevis uz `true`, kas norāda uz kļūmi tokenu līguma `transfer` funkcijā.

Risinājums:

  1. Pārliecinies par ERC-20 atbilstību: Pārbaudi, vai tokenu līgums atbilst ERC-20 standartam, kas ietver pareizu `transfer` funkcijas īstenojumu.
  2. Pareizi parametri: Pārliecinies, vai `to` adrese ir derīga un `value` ir atļauto limitu robežās, ņemot vērā sūtītāja bilanci un līguma loģiku.
  3. Papildu nosacījumi: Pārbaudi, vai tokenu līgums prasa papildu nosacījumus, piemēram, izsniegšanas apstiprinājumu (`approve` un `allowance` funkcijas).

INSUFFICIENT_LIQUIDITY

8. INSUFFICIENT_OUTPUT_AMOUNT

Šī kļūda rodas decentralizēta biržas kontekstā, kad tokenu apmaiņas izejas summa ir mazāka par minimālo summu, ko lietotājs ir noteicis. Tas ir drošības pasākums, lai nodrošinātu, ka lietotāji neiegūst mazāk tokenu nekā gaidīts slīpuma vai cenu izmaiņu dēļ darījuma laikā.


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

Cēlonis:

  1. Tirgus svārstīgums ietekmē tokenu cenas laika posmā no darījuma sākuma līdz izpildei.
  2. Augsti slīpuma iestatījumi, kas ļauj ievērojamas novirzes no gaidītajām izejām.
  3. Nepietiekama likviditāte tirdzniecības baseinā, kas izraisa lielākas cenu ietekmes.

Risinājums:

  1. Pārliecinies par ERC-20 atbilstību: Pārbaudi, vai tokenu līgums atbilst ERC-20 standartam, kas ietver pareizu `transfer` funkcijas īstenojumu.
  2. Pareizi parametri: Pārliecinies, vai `to` adrese ir derīga un `value` ir atļauto limitu robežās, ņemot vērā sūtītāja bilanci un līguma loģiku.
  3. Papildu nosacījumi: Pārbaudi, vai tokenu līgums prasa papildu nosacījumus, piemēram, izsniegšanas apstiprinājumu (`approve` un `allowance` funkcijas).

9. INSUFFICIENT_INPUT_AMOUNT

Šī kļūda rodas, kad neviens no ievades summām tokenu apmaiņai nav lielāks par nulli. Tā nodrošina, ka vismaz viena no ievades summām (`amount0In` vai `amount1In`) ir pozitīva, lai turpinātu apmaiņu.


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

Cēlonis:

  1. Nekorekti ievades parametri apmaiņas funkcijai.
  2. Nepietiekami līdzekļi lietotāja kontā.
  3. Kļūdas loģikā, kas aprēķina ievades summas.

Risinājums:

  1. Validē ievades summas: Pārliecinies, ka ievades summas ir pareizi iestatītas pirms apmaiņas funkcijas izsaukšanas. Tas ietver pareizu lietotāja ievades validāciju un parametru iestatīšanu.
  2. Pārbaudi lietotāja bilances: Verificē, vai lietotājam ir pietiekama bilance tokeniem, kas paredzēti apmaiņai. To var izdarīt, izsaucot `balanceOf` funkciju attiecīgo tokenu līgumos.

10. Kļūda

Cēlonis:

  1. Darījumu nevar izpildīt, jo trūkst pietiekami daudz gāzes visu operāciju izpildei.
  2. Kļūdas loģikā vai nosacījumos viedlīgā līgumā var izraisīt izpildes neizdošanos (piemēram, `require` vai `assert` izsaukums, kas neizdodas).
  3. Mēģinājums izpildīt tokenu vai kriptovalūtas darījumu, kad konta bilance ir nepietiekama.
  4. Strādājot ar ERC-20 un ERC-721 standarta tokeniem, darījums var neizdoties nepietiekamu atļauju dēļ.
  5. Izsaukums uz viedlīgā līguma var tikt at celts, jo neizdevās izpildīt nosacījumus (piemēram, izmantojot `revert` funkciju).

Risinājums:

  1. Paliidziniet gāzes limitu, sūtot darījumu.
  2. Pārbaudi nosacījumus un loģiku viedlīgajā līgumā.
  3. Pārliecinies, ka kontā ir pietiekami daudz līdzekļu, lai pabeigtu darījumu.
  4. Izsauc `approve` funkciju ar pietiekamu vērtību pirms `transferFrom` izsaukšanas.
  5. Pārbaudi nosacījumus, kas izraisa darījuma atcelšanu.
  6. Pārbaudi savu bilanci komisijām.

Secinājums

Izpratne un šo bieži sastopamo kļūdu risināšana ERC-20 viedlīgajos līgumos prasa labas zināšanas par Solidity programmēšanu, ERC-20 standartu un decentralizēto biržu iekšējo darbību. Rūpīgi pārskatot cēloņus un īstenojot ieteiktos risinājumus, izstrādātāji var izveidot stabilākus un uzticamākus viedlīgus līgumus, nodrošinot nevainojamu lietotāja pieredzi decentralizētajā ekosistēmā.

All posts

Connect to a wallet

Metamask