Analise smart-contract
07.08.2024

Porozumění běžným chybám inteligentních smluv ERC-20 v Solidity

Chytré smlouvy v ekosystému Ethereum často obsahují složitou logiku, která zajišťuje bezpečnost a funkčnost decentralizovaných aplikací. Nicméně, chyby mohou vzniknout z různých důvodů, což vede k neúspěšným transakcím a potenciálním zranitelnostem. Tento blogový příspěvek se zaměří na některé běžné chyby, které se vyskytují při transakcích s tokeny ERC-20, jejich příčiny a řešení.

1. Pancake: K

Chyba se vyskytuje, pokud je porušena invariantní podmínka „součin rezerv musí být konstantní“. Tato podmínka zajišťuje, že po provedení výměny nebude nový součin rezerv (včetně provizí) menší než starý součin. K porušení této podmínky může dojít, pokud:

  1. Tokeny vložené do poolu (amount0In nebo amount1In) neodpovídají očekávaným hodnotám podle invariantní formule. Došlo k chybě při výpočtu zůstatků po výměně.
  2. Někdo se pokusil manipulovat s pool, což způsobilo změnu zůstatků tokenů, čímž obešel standardní proces výměny.
  3. Pokud tato podmínka není splněna, je vyvolána chyba „Pancake: K“, což signalizuje porušení matematické invariance.

Porušení invariance znamená, že jedna ze základních podmínek, které zajišťují správný chod systému, již není splněna. V kontextu decentralizovaných burz, jako je PancakeSwap, je invariance obvykle spojena s matematickou rovnicí, která musí zůstat pravdivá, aby se udržela rovnováha mezi rezervami tokenů v likviditním poolu.


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

Řešení:
Zkontrolujte, zda má pool dostatečnou likviditu pro provedení výměny a že hodnoty nepřekračují rezervy (_reserve0, _reserve1). Průběžně monitorujte rezervy poolu a v případě potřeby je doplňte.

2. TransferHelper: TRANSFER_FROM_FAILED

Tato chyba znamená selhání převodu tokenů pomocí metody safeTransferFrom, která je běžným vzorem pro bezpečný převod tokenů ERC-20.


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

Příčina:

  1. Adresa „from“ neposkytla nebo neposkytla dostatečné oprávnění pro adresu „msg.sender“ k převodu tokenů (allowance, approve).
  2. Adresa „from“ nemá dostatek tokenů pro provedení převodu. To může být také způsobeno tím, že správci tokenů mají možnost měnit zůstatek tokenů a v době výběru může mít uživatel, který investici provedl, nedostatečný zůstatek pro provedení výběru.
  3. Smlouva s tokeny nemusí implementovat funkci transferFrom nebo ji může implementovat nesprávně.
  4. Smlouva s tokeny může obsahovat další kontroly nebo omezení ve funkci transferFrom, což může způsobit zrušení transakce.
  5. Pokud není dostatek plynu pro provedení transakce, může transakce selhat.

Řešení:

  1. Ujistěte se, že adresa „from“ poskytla dostatečný limit pro „msg.sender“. To lze provést voláním funkce allowance smlouvy s tokenem.
  2. Ujistěte se, že adresa „from“ má dostatek tokenů pro provedení převodu.
  3. Ověřte, že adresa smlouvy s tokenem je správná a že smlouva je v souladu s ERC-20.
  4. Zkontrolujte implementaci funkce transferFrom ve smlouvě s tokenem. Ujistěte se, že je správně implementována a nemá žádná další omezení, která by mohla způsobit selhání.
  5. Zkuste zvýšit limit plynu při volání transakce, abyste se ujistili, že problém není v nedostatku plynu.

3. INSUFFICIENT_LIQUIDITY

Tato chyba nastává, když se pokoušíte vybrat více likvidity, než je dostupné v rezervách likviditního poolu.


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

Příčina:

  1. Likviditní pool neobsahuje dostatečné množství jednoho nebo obou tokenů k splnění požadované výměny.
  2. Požadované množství tokenů pro výběr (amount0Out nebo amount1Out) překračuje dostupný počet tokenů v poolu.
  3. Nesoulad mezi rezervami ve smlouvě a skutečným stavem poolu. Rezervy uložené ve smlouvě nemusí odpovídat skutečnému stavu zůstatku tokenů v poolu kvůli chybám nebo manipulaci.

Řešení:

  1. Zkontrolujte rezervy poolu a ujistěte se, že jsou dostatečné pro splnění požadované výměny. To lze provést pomocí funkce getReserves.
  2. Ujistěte se, že parametry amount0Out a amount1Out jsou správné a nepřekračují dostupný počet tokenů v poolu.
  3. Ujistěte se, že rezervy ve smlouvě odpovídají skutečnému zůstatku tokenů. K tomu můžete přidat kontrolu a aktualizaci rezerv před provedením výměny.

INSUFFICIENT_LIQUIDITY

4. APPROVE_FAILED

Chyba `APPROVE_FAILED` se vyskytuje během vykonávání funkce `safeApprove`. Tato funkce je navržena k nastavení množství tokenů, které vlastník umožňuje vydavateli používat jeho jménem.


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

Příčina:

  1. Smlouva s tokeny nemusí mít funkci `approve` nebo může být implementována nesprávně.
  2. Může být problém se stavem smlouvy s tokeny, například nedostatečný zůstatek nebo limit.
  3. Funkce `approve` může vrátit chybu z bezpečnostních důvodů implementovaných ve smlouvě s tokeny.

Řešení:

  1. Ujistěte se, že smlouva s tokeny je v souladu s ERC-20 standardem a obsahuje správně implementovanou funkci `approve`.
  2. Zkontrolujte stav smlouvy s tokeny a ujistěte se, že účet má dostatek tokenů na schválení.
  3. Ověřte, že adresa a množství předané funkci `safeApprove` jsou správné.
  4. Dále laděte tím, že zkontrolujete konkrétní chybovou zprávu nebo důvod pro zrušení v smlouvě s tokeny.

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

Chyba `ds-math-sub-underflow` se vyvolá, když operace odečítání způsobí podtečení, tj. když je výsledek odečítání menší než nula.


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

Příčina:
Tato chyba nastává, protože operace odečítání `x - y` vede k zápornému číslu, což není povoleno pro nezáporná celá čísla v Solidity.

Řešení:

  1. Ujistěte se, že hodnota `y` je vždy menší nebo rovna `x` před provedením odečítání.
  2. Implementujte kontroly ve vašem kódu, které budou zpracovávat případy, kdy může být `y` větší než `x`, a přijměte odpovídající opatření, například vrátit transakci nebo upravit logiku.

6. Chyba s oznámením 'ERC20: částka převodu překračuje povolení'

Chyba `ERC20: částka převodu překračuje povolení` se vyskytuje, když se pokusíte převést tokeny jménem jiného uživatele, ale částka, kterou se snažíte převést, překračuje povolení, které vlastník tokenů nastavil pro výdajce.

Příčina:
Tato chyba je vyvolána funkcí `transferFrom` smlouvy ERC-20 tokenu, když je částka k převodu větší než povolený limit nastavený vlastníkem tokenů.

Řešení:

  1. Ujistěte se, že vlastník tokenů nastavil adekvátní povolení pro výdajce pomocí funkce `approve`.
  2. Zkontrolujte aktuální povolení před pokusem o operaci `transferFrom`.
  3. Pokud je to nutné, požádejte vlastníka tokenů, aby zvýšil povolení zavoláním funkce `approve` s vyšší hodnotou.

7. TRANSFER_FAILED

Tato chyba nastává, když převod tokenů z jedné adresy na druhou selže. Funkce `_safeTransfer` zajišťuje, že převodová operace uspěje a že vrácená data, pokud nějaká existují, dekódují na `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'); }`

Příčina:

  1. Funkce `token.call` neprovádí úspěšně (tj. `success` je `false`).
  2. Volání vrací data, která se nedekódují na `true`, což naznačuje selhání ve funkci `transfer` smlouvy s tokenem.

Řešení:

  1. Zajistěte shodu s ERC-20: Ověřte, že smlouva s tokenem dodržuje standard ERC-20, což zahrnuje správnou implementaci funkce `transfer`.
  2. Oprávněné parametry: Ujistěte se, že adresa `to` je platná a `value` je v rámci povolených limitů, s ohledem na zůstatek odesílatele a logiku smlouvy.
  3. Další podmínky: Zkontrolujte, zda smlouva s tokenem vyžaduje další podmínky, jako je předchozí schválení částky výdajů (`approve` a `allowance` funkce).

INSUFFICIENT_LIQUIDITY

8. INSUFFICIENT_OUTPUT_AMOUNT

Tato chyba se vyskytuje v kontextu decentralizované burzy, když výstupní částka swapu tokenů je menší než minimální částka specifikovaná uživatelem. Toto je ochranný mechanismus, aby se zajistilo, že uživatelé nedostanou méně tokenů, než očekávali kvůli skluzu nebo změnám ceny během transakce.


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

Příčina:

  1. Volatilita trhu ovlivňující ceny tokenů mezi okamžikem zahájení transakce a jejím provedením.
  2. Vysoké nastavení skluzu, které umožňuje značné odchylky od očekávaných výstupů.
  3. Nedostatečná likvidita v obchodním poolu, což způsobuje větší dopady na cenu.

Řešení:

  1. Zajistěte shodu s ERC-20: Ověřte, že smlouva s tokenem dodržuje standard ERC-20, což zahrnuje správnou implementaci funkce `transfer`.
  2. Oprávněné parametry: Ujistěte se, že adresa `to` je platná a `value` je v rámci povolených limitů, s ohledem na zůstatek odesílatele a logiku smlouvy.
  3. Další podmínky: Zkontrolujte, zda smlouva s tokenem vyžaduje další podmínky, jako je předchozí schválení částky výdajů (`approve` a `allowance` funkce).

9. INSUFFICIENT_INPUT_AMOUNT

Tato chyba se vyskytuje, když žádná z vstupních částek pro swap tokenů není větší než nula. Zajišťuje se tím, že alespoň jedna z vstupních částek (`amount0In` nebo `amount1In`) je kladná, aby bylo možné pokračovat ve swapu.


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

Příčina:

  1. Nesprávné vstupní parametry pro funkci swapu.
  2. Nedostatečné prostředky na uživatelském účtu.
  3. Chyby v logice výpočtu vstupních částek.

Řešení:

  1. Ověřte vstupní částky: Ujistěte se, že vstupní částky jsou správně nastaveny před vyvoláním funkce swapu. To zahrnuje správnou validaci uživatelského vstupu a nastavení parametrů.
  2. Zkontrolujte zůstatky uživatele: Ověřte, že uživatel má dostatečný zůstatek tokenů určených pro swap. To lze provést voláním funkce `balanceOf` příslušných smluv s tokeny.

10. Chyba

Příčina:

  1. Transakce nemůže být provedena, protože nemá dostatek plynu na dokončení všech operací.
  2. Nesprávná logika nebo podmínky v chytré smlouvě mohou způsobit selhání (například volání funkce require nebo assert, které selže).
  3. Pokus o provedení transakce s tokenem nebo kryptoměnou, když je zůstatek na účtu nedostatečný.
  4. V případě práce s tokeny standardu ERC-20 a ERC-721 může transakce selhat kvůli nedostatečným oprávněním.
  5. Volání chytré smlouvy může být vráceno zpět kvůli nesplnění podmínek uvnitř (např. použití funkce revert).

Řešení:

  1. Zvyšte limit plynu při odesílání transakce.
  2. Ověřte podmínky a logiku v chytré smlouvě.
  3. Ujist ěte se, že účet má dostatek prostředků na dokončení transakce.
  4. Zavolejte funkci approve s dostatečnou hodnotou před voláním transferFrom.
  5. Ověřte podmínky, které způsobují vrácení transakce.
  6. Ověřte svůj zůstatek na poplatky.

Závěr

Porozumění a řešení těchto běžných chyb v chytrých smlouvách ERC-20 vyžaduje solidní znalosti programování v Solidity, standardu ERC-20 a vnitřních fungování decentralizovaných burz. Pečlivým přezkoumáním příčin a implementací navrhovaných řešení mohou vývojáři vytvářet robustnější a spolehlivější chytré smlouvy, čímž zajistí plynulý zážitek pro uživatele v decentralizovaném ekosystému.

All posts

Connect to a wallet

Metamask