Analise smart-contract
07.08.2024

Κατανόηση των κοινών σφαλμάτων έξυπνων συμβολαίων ERC-20 στο Solidity

Τα έξυπνα συμβόλαια στο οικοσύστημα του Ethereum περιέχουν συχνά περίπλοκες λογικές για να εξασφαλίσουν την ασφάλεια και τη λειτουργικότητα των αποκεντρωμένων εφαρμογών. Ωστόσο, μπορεί να προκύψουν σφάλματα λόγω διαφόρων λόγων, οδηγώντας σε αποτυχημένες συναλλαγές και πιθανές ευπάθειες. Αυτό το άρθρο θα εξετάσει κάποια κοινά σφάλματα που συναντώνται στις συναλλαγές με token ERC-20, τις αιτίες τους και τις λύσεις.

1. Pancake: K

Το σφάλμα εμφανίζεται αν παραβιαστεί το αμετάβλητο 'το προϊόν των αποθεμάτων πρέπει να παραμένει σταθερό'. Αυτή η συνθήκη εγγυάται ότι, μετά την εκτέλεση της ανταλλαγής, το νέο προϊόν των αποθεμάτων (συμπεριλαμβανομένων των προμηθειών) δεν θα είναι μικρότερο από το παλιό προϊόν. Μια παραβίαση αυτής της συνθήκης μπορεί να συμβεί αν:

  1. Τα token που εισάγονται στην πισίνα (amount0In ή amount1In) δεν ταιριάζουν με τις αναμενόμενες τιμές σύμφωνα με τον τύπο του αμετάβλητου. Υπήρξε σφάλμα στον υπολογισμό των υπολοίπων μετά την ανταλλαγή.
  2. Κάποιος προσπάθησε να χειραγωγήσει την πισίνα, προκαλώντας την αλλαγή των υπολοίπων των token, παρακάμπτοντας τη διαδικασία ανταλλαγής.
  3. Αν δεν πληρείται αυτή η συνθήκη, εμφανίζεται το σφάλμα ‘Pancake: K’, υποδεικνύοντας παραβίαση μαθηματικού αμετάβλητου.

Μια παραβίαση του αμετάβλητου σημαίνει ότι μία από τις θεμελιώδεις συνθήκες που εξασφαλίζουν τη σωστή λειτουργία του συστήματος δεν πληρούται πλέον. Στο πλαίσιο των αποκεντρωμένων ανταλλαγών όπως το PancakeSwap, το αμετάβλητο συνήθως σχετίζεται με μια μαθηματική εξίσωση που πρέπει να παραμένει αληθής για να διατηρηθεί η ισορροπία μεταξύ των αποθεμάτων των token στην πισίνα ρευστότητας.


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

Λύση:
Ελέγξτε ότι η πισίνα διαθέτει αρκετή ρευστότητα για να πραγματοποιήσει την ανταλλαγή και ότι οι τιμές δεν υπερβαίνουν τα αποθέματα (_reserve0, _reserve1). Παρακολουθείτε συνεχώς τα αποθέματα της πισίνας και λάβετε μέτρα για την ανανέωσή τους εάν χρειάζεται.

2. TransferHelper: TRANSFER_FROM_FAILED

Αυτό το σφάλμα σημαίνει αποτυχημένη μεταφορά token χρησιμοποιώντας τη μέθοδο safeTransferFrom, η οποία είναι ένα κοινό μοτίβο για τη ασφαλή μεταφορά 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');
  }

Αιτία:

  1. Η διεύθυνση από την οποία γίνεται η μεταφορά δεν έχει χορηγήσει ή δεν έχει χορηγήσει αρκετές άδειες για τη διεύθυνση msg.sender να μεταφέρει tokens (allowance, approve).
  2. Η διεύθυνση από την οποία γίνεται η μεταφορά δεν διαθέτει αρκετά tokens για να πραγματοποιήσει τη μεταφορά. Αυτό μπορεί επίσης να οφείλεται στο γεγονός ότι οι διαχειριστές του token έχουν τη δυνατότητα να τροποποιήσουν το υπόλοιπο του token και κατά τη στιγμή της ανάληψης ο χρήστης που έκανε την επένδυση μπορεί να μην έχει αρκετό υπόλοιπο για να πραγματοποιήσει την ανάληψη.
  3. Ο συμβόλαιο του token ενδέχεται να μην υλοποιεί σωστά τη λειτουργία transferFrom ή να την υλοποιεί εσφαλμένα.
  4. Ο συμβόλαιο του token μπορεί να περιέχει επιπλέον ελέγχους ή περιορισμούς στη λειτουργία transferFrom, οι οποίοι μπορεί να προκαλέσουν την ακύρωση της συναλλαγής.
  5. Εάν δεν υπάρχει αρκετό gas για την εκτέλεση της συναλλαγής, η συναλλαγή μπορεί να αποτύχει.

Λύση:

  1. Βεβαιωθείτε ότι η διεύθυνση από την οποία γίνεται η μεταφορά έχει χορηγήσει αρκετή άδεια για τη διεύθυνση msg.sender. Αυτό μπορεί να γίνει καλώντας τη λειτουργία allowance του συμβολαίου token.
  2. Βεβαιωθείτε ότι η διεύθυνση από την οποία γίνεται η μεταφορά διαθέτει αρκετά tokens για να πραγματοποιήσει τη μεταφορά.
  3. Επαληθεύστε ότι η διεύθυνση του συμβολαίου token είναι σωστή και ότι το συμβόλαιο συμμορφώνεται με τον πρότυπο ERC-20.
  4. Ελέγξτε την υλοποίηση της λειτουργίας transferFrom στο συμβόλαιο token. Βεβαιωθείτε ότι έχει υλοποιηθεί σωστά και δεν έχει επιπλέον περιορισμούς που θα μπορούσαν να προκαλέσουν αποτυχία.
  5. Δοκιμάστε να αυξήσετε το όριο gas κατά την κλήση της συναλλαγής για να βεβαιωθείτε ότι το πρόβλημα δεν είναι έλλειψη gas.

3. INSUFFICIENT_LIQUIDITY

Αυτό το σφάλμα εμφανίζεται όταν προσπαθείτε να αποσύρετε περισσότερη ρευστότητα από ό,τι είναι διαθέσιμη στα αποθέματα μιας πισίνας ρευστότητας.


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

Αιτία:

  1. Η πισίνα ρευστότητας δεν περιέχει αρκετό ποσό από ένα ή και τα δύο tokens για να εκπληρώσει την αιτούμενη ανταλλαγή.
  2. Το αιτούμενο ποσό tokens για ανάληψη (amount0Out ή amount1Out) υπερβαίνει τον διαθέσιμο αριθμό tokens στην πισίνα.
  3. Διαφορά μεταξύ των αποθεμάτων στο συμβόλαιο και της πραγματικής κατάστασης της πισίνας. Τα αποθέματα που αποθηκεύονται στο συμβόλαιο ενδέχεται να μην αντιστοιχούν στην πραγματική κατάσταση των tokens στην πισίνα λόγω σφαλμάτων ή χειραγώγησης.

Λύση:

  1. Ελέγξτε τα αποθέματα της πισίνας και βεβαιωθείτε ότι είναι επαρκή για να εκπληρώσουν την αιτούμενη ανταλλαγή. Αυτό μπορεί να γίνει χρησιμοποιώντας τη λειτουργία getReserves.
  2. Βεβαιωθείτε ότι οι παράμετροι amount0Out και amount1Out είναι σωστές και δεν υπερβαίνουν τον διαθέσιμο αριθμό tokens στην πισίνα.
  3. Βε βαιωθείτε ότι τα αποθέματα στο συμβόλαιο αντιστοιχούν στο πραγματικό υπόλοιπο token. Για να το κάνετε αυτό, μπορείτε να προσθέσετε ελέγχους και ανανεώσεις αποθεμάτων πριν πραγματοποιήσετε την ανταλλαγή.

INSUFFICIENT_LIQUIDITY

4. APPROVE_FAILED

Το σφάλμα `APPROVE_FAILED` εμφανίζεται κατά την εκτέλεση της λειτουργίας `safeApprove`. Αυτή η λειτουργία έχει σχεδιαστεί για να ορίζει το ποσό των tokens που επιτρέπει ένας ιδιοκτήτης σε έναν δαπανητή να χρησιμοποιήσει εκ μέρους του.


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

Αιτία:

  1. Το συμβόλαιο του token μπορεί να μην έχει τη λειτουργία `approve` ή μπορεί να είναι λανθασμένα υλοποιημένο.
  2. Μπορεί να υπάρχει πρόβλημα με την κατάσταση του συμβολαίου του token, όπως ανεπάρκεια υπολοίπου ή άδειας.
  3. Η λειτουργία `approve` μπορεί να αποτύχει για λόγους ασφαλείας που έχουν εφαρμοστεί στο συμβόλαιο του token.

Λύση:

  1. Εξασφαλίστε ότι το συμβόλαιο του token συμμορφώνεται με τον πρότυπο ERC-20 και περιλαμβάνει μια σωστά υλοποιημένη λειτουργία `approve`.
  2. Ελέγξτε την κατάσταση του συμβολαίου του token και βεβαιωθείτε ότι ο λογαριασμός διαθέτει αρκετά tokens για έγκριση.
  3. Επαληθεύστε ότι η διεύθυνση και το ποσό που μεταφέρονται στη λειτουργία `safeApprove` είναι σωστά.
  4. Κάντε επιπλέον αποσφαλμάτωση ελέγχοντας το συγκεκριμένο μήνυμα σφάλματος ή την αιτία της αποτυχίας στο συμβόλαιο του token.

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

Το σφάλμα `ds-math-sub-underflow` εμφανίζεται όταν μια λειτουργία αφαίρεσης υπερχειλίσει, δηλαδή όταν το αποτέλεσμα της αφαίρεσης είναι μικρότερο από το μηδέν.


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

Αιτία:
Αυτό το σφάλμα συμβαίνει επειδή η λειτουργία αφαίρεσης `x - y` παράγει έναν αρνητικό αριθμό, ο οποίος δεν επιτρέπεται για μη υπογεγραμμένους ακέραιους αριθμούς στη Solidity.

Λύση:

  1. Εξασφαλίστε ότι η τιμή του `y` είναι πάντα μικρότερη ή ίση με το `x` πριν από την εκτέλεση της αφαίρεσης.
  2. Εφαρμόστε ελέγχους στον κώδικα σας για να διαχειριστείτε περιπτώσεις όπου το `y` μπορεί να είναι μεγαλύτερο από το `x` και λάβετε κατάλληλες ενέργειες, όπως την ανατροπή της συναλλαγής ή την προσαρμογή της λογικής.

6. Σφάλμα με 'ERC20: το ποσό μεταφοράς υπερβαίνει την επιτρεπόμενη ποσότητα'

Το σφάλμα `ERC20: το ποσό μεταφοράς υπερβαίνει την επιτρεπόμενη ποσότητα` εμφανίζεται όταν επιχειρείτε να μεταφέρετε tokens εκ μέρους ενός άλλου χρήστη, αλλά το ποσό που μεταφέρεται υπερβαίνει την επιτρεπόμενη ποσότητα που έχει ορίσει ο ιδιοκτήτης του token για τον δαπανητή.

Αιτία:
Το σφάλμα αυτό προκύπτει από τη λειτουργία `transferFrom` του συμβολαίου ERC-20 όταν το ποσό που πρόκειται να μεταφερθεί είναι μεγαλύτερο από το επιτρεπόμενο όριο που έχει ορίσει ο ιδιοκτήτης του token.

Λύση:

  1. Εξασφαλίστε ότι ο ιδιοκτήτης του token έχει ορίσει επαρκή ποσότητα επιτρεπόμενης χρήσης για τον δαπανητή χρησιμοποιώντας τη λειτουργία `approve`.
  2. Ελέγξτε την τρέχουσα επιτρεπόμενη ποσότητα πριν επιχειρήσετε τη λειτουργία `transferFrom`.
  3. Εάν είναι απαραίτητο, ζητήστε από τον ιδιοκτήτη του token να αυξήσει την επιτρεπόμενη ποσότητα καλώντας τη λειτουργία `approve` με υψηλότερη τιμή.

7. TRANSFER_FAILED

Το σφάλμα αυτό συμβαίνει όταν η μεταφορά tokens από μια διεύθυνση σε άλλη αποτυγχάνει. Η λειτουργία `_safeTransfer` εξασφαλίζει ότι η λειτουργία μεταφοράς είναι επιτυχής και ότι τα επιστραφέντα δεδομένα, αν υπάρχουν, αποκωδικοποιούνται σε `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'); }`

Αιτία:

  1. Η συνάρτηση `token.call` δεν εκτελείται με επιτυχία (δηλαδή, το `success` είναι `false`).
  2. Η κλήση επιστρέφει δεδομένα που δεν αποκωδικοποιούνται σε `true`, υποδεικνύοντας αποτυχία στη λειτουργία `transfer` του συμβολαίου token.

Λύση:

  1. Εξασφαλίστε Συμμόρφωση με το ERC-20: Επαληθεύστε ότι το συμβόλαιο του token συμμορφώνεται με το πρότυπο ERC-20, το οποίο περιλαμβάνει τη σωστή υλοποίηση της λειτουργίας `transfer`.
  2. Σωστές Παράμετροι: Εξασφαλίστε ότι η διεύθυνση `to` είναι έγκυρη και ότι η `value` είναι εντός επιτρεπτών ορίων, λαμβάνοντας υπόψη το υπόλοιπο του αποστολέα και τη λογική του συμβολαίου.
  3. Πρόσθετες Συνθήκες: Ελέγξτε αν το συμβόλαιο token απαιτεί πρόσθετες συνθήκες, όπως η προέγκριση του ποσού δαπάνης (`approve` και `allowance` λειτουργίες).

INSUFFICIENT_LIQUIDITY

8. INSUFFICIENT_OUTPUT_AMOUNT

Το σφάλμα αυτό συμβαίνει σε ένα αποκεντρωμένο πλαίσιο ανταλλαγής όταν το ποσό εξόδου μιας ανταλλαγής token είναι μικρότερο από την ελάχιστη ποσότητα που έχει καθορίσει ο χρήστης. Αυτό είναι μια προστασία για να διασφαλιστεί ότι οι χρήστες δεν θα λάβουν λιγότερα tokens από όσα αναμέναν λόγω παρεκκλίσεων ή αλλαγών τιμών κατά τη διάρκεια της συναλλαγής.


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

Αιτία:

  1. Η μεταβλητότητα της αγοράς επηρεάζει τις τιμές των token μεταξύ της στιγμής που ξεκινά η συναλλαγή και όταν αυτή εκτελείται.
  2. Υψηλές ρυθμίσεις παρεκκλίσεων, οι οποίες επιτρέπουν σημαντικές αποκλίσεις από τα αναμενόμενα αποτελέσματα.
  3. Ανεπαρκής ρευστότητα στην πισίνα συναλλαγών, προκαλώντας μεγαλύτερες επιπτώσεις στις τιμές.

Λύση:

  1. Εξασφαλίστε Συμμόρφωση με το ERC-20: Επαληθεύστε ότι το συμβόλαιο του token συμμορφώνεται με το πρότυπο ERC-20, το οποίο περιλαμβάνει τη σωστή υλοποίηση της λειτουργίας `transfer`.
  2. Σωστές Παράμετροι: Εξασφαλίστε ότι η διεύθυνση `to` είναι έγκυρη και ότι η `value` είναι εντός επιτρεπτών ορίων, λαμβάνοντας υπόψη το υπόλοιπο του αποστολέα και τη λογική του συμβολαίου.
  3. Πρόσθετες Συνθήκες: Ελέγξτε αν το συμβόλαιο token απαιτεί πρόσθετες συνθήκες, όπως η προέγκριση του ποσού δαπάνης (`approve` και `allowance` λειτουργίες).

9. INSUFFICIENT_INPUT_AMOUNT

Το σφάλμα αυτό συμβαίνει όταν κανένα από τα ποσά εισόδου για μια ανταλλαγή token δεν είναι μεγαλύτερο από το μηδέν. Διασφαλίζει ότι τουλάχιστον ένα από τα ποσά εισόδου (`amount0In` ή `amount1In`) είναι θετικό για να προχωρήσει η ανταλλαγή.


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

Αιτία:

  1. Λανθασμένες παράμετροι εισόδου για τη λειτουργία ανταλλαγής.
  2. Ανεπαρκή κεφάλαια στον λογαριασμό του χρήστη.
  3. Λάθη στη λογική που υπολογίζει τα ποσά εισόδου.

Λύση:

  1. Επικύρωση Ποσών Εισόδου: Εξασφαλίστε ότι τα ποσά εισόδου έχουν ρυθμιστεί σωστά πριν από την κλήση της λειτουργίας ανταλλαγής. Αυτό περιλαμβάνει τη σωστή επικύρωση εισόδου από τον χρήστη και τη ρύθμιση παραμέτρων.
  2. Ελέγξτε τα Υπολείμματα Χρήστη: Επαληθεύστε ότι ο χρήστης έχει επαρκές υπόλοιπο των tokens που προορίζονται για την ανταλλαγή. Αυτό μπορεί να γίνει καλώντας τη λειτουργία `balanceOf` των αντίστοιχων συμβολαίων token.

10. Αποτυχία

Αιτία:

  1. Μια συναλλαγή δεν μπορεί να εκτελεστεί επειδή δεν υπάρχει επαρκές gas για να ολοκληρωθούν όλες οι λειτουργίες.
  2. Λανθ ασμένη λογική ή συνθήκες εντός ενός έξυπνου συμβολαίου μπορεί να προκαλέσουν αποτυχία εκτέλεσης (για παράδειγμα, μια κλήση σε require ή assert που αποτυγχάνει).
  3. Προσπάθεια εκτέλεσης μιας συναλλαγής token ή κρυπτονομίσματος όταν το υπόλοιπο του λογαριασμού είναι ανεπαρκές.
  4. Στην περίπτωση εργασίας με tokens προτύπων ERC-20 και ERC-721, η συναλλαγή μπορεί να αποτύχει λόγω ανεπαρκών δικαιωμάτων.
  5. Μια κλήση σε ένα έξυπνο συμβόλαιο μπορεί να αναιρεθεί λόγω αποτυχίας εκπλήρωσης των συνθηκών εντός του (π.χ. χρησιμοποιώντας τη λειτουργία revert).

Λύση:

  1. Αυξήστε το όριο gas κατά την αποστολή της συναλλαγής.
  2. Ελέγξτε τις συνθήκες και τη λογική εντός του έξυπνου συμβολαίου.
  3. Επιβεβαιώστε ότι ο λογαριασμός έχει επαρκή κεφάλαια για την ολοκλήρωση της συναλλαγής.
  4. Καλέστε τη λειτουργία approve με επαρκές ποσό πριν από την κλήση της transferFrom.
  5. Ελέγξτε τις συνθήκες που προκαλούν την αναιρέση της συναλλαγής.
  6. Ελέγξτε το υπόλοιπό σας για προμήθειες.

Συμπέρασμα

Η κατανόηση και η επίλυση αυτών των κοινών σφαλμάτων σε έξυπνα συμβόλαια ERC-20 απαιτεί καλή γνώση του προγραμματισμού Solidity, του προτύπου ERC-20 και της εσωτερικής λειτουργίας των αποκεντρωμένων ανταλλαγών. Εξετάζοντας προσεκτικά τις αιτίες και εφαρμόζοντας τις προτεινόμενες λύσεις, οι προγραμματιστές μπορούν να δημιουργήσουν πιο ισχυρά και αξιόπιστα έξυπνα συμβόλαια, εξασφαλίζοντας μια ομαλή εμπειρία για τους χρήστες στο αποκεντρωμένο οικοσύστημα.

All posts

Connect to a wallet

Metamask