Résumé de gestion
Dusa a contacté Sayfer pour effectuer un audit de sécurité sur ses contrats intelligents.
Ce rapport documente les recherches effectuées par Sayfer ciblant les ressources sélectionnées définies dans le cadre de la recherche. En particulier, ce rapport présente l'examen de la posture de sécurité des contrats intelligents de Dusa.
Au cours de la période de recherche de 4 semaines, nous avons découvert 17 vulnérabilités dans le contrat.
Dans l’ensemble, Dusa est un protocole bien construit. Le fait qu’il soit dérivé et traduit de TraderJoe en fait un protocole très solide avec une architecture assez courante, mais considérée comme optimale. Cependant, nous avons quelques recommandations qui, selon nous, pourraient améliorer la qualité et la sécurité du protocole. Ces recommandations sont détaillées dans la section « Revue de l'architecture ».
En conclusion, plusieurs correctifs devraient être mis en œuvre suite au rapport, mais la posture de sécurité du système est compétente.
Après examen par l'équipe Sayfer, nous certifions que tous les problèmes de sécurité mentionnés dans ce rapport ont été résolus ou reconnus par l'équipe Dusa.
Méthodologie des risques
Chez Sayfer, nous nous engageons à fournir à nos clients des audits de contrats intelligents de la plus haute qualité. C'est pourquoi nous avons mis en œuvre un modèle complet d'évaluation des risques pour évaluer la gravité de nos constatations et fournir à nos clients les meilleures recommandations possibles pour les atténuer.
Notre modèle d’évaluation des risques repose sur deux facteurs clés : IMPACT ainsi que PROBABILITÉ. L'impact fait référence au préjudice potentiel qui pourrait résulter d'un problème, tel qu'une perte financière, une atteinte à la réputation ou un système non opérationnel. La probabilité fait référence à la probabilité qu'un problème se produise, en tenant compte de facteurs tels que la complexité du contrat et le nombre d'attaquants potentiels.
En combinant ces deux facteurs, nous pouvons créer une compréhension globale du risque posé par un problème particulier et fournir à nos clients une évaluation claire et exploitable de la gravité du problème. Cette approche nous permet de prioriser nos recommandations et de garantir que nos clients reçoivent les meilleurs conseils possibles sur la façon de protéger leurs contrats intelligents.
Le risque est défini comme suit :
Vulnérabilités par risque
Haute – Menace directe sur les processus métier clés.
Moyenne – Menace indirecte sur les processus métier clés ou menace partielle sur les processus métier.
Faible – Aucune menace directe n'existe. La vulnérabilité peut être exploitée à l'aide d'autres vulnérabilités.
D'information – Cette constatation n'indique pas de vulnérabilité, mais énonce un commentaire qui signale des défauts de conception et une mise en œuvre incorrecte qui pourraient causer un problème à long terme.
Approche
Présentation du protocole
Présentation du protocole
Dusa est un protocole de finance décentralisée (DeFi) révolutionnaire, introduisant une expérience de teneur de marché automatisé (AMM) entièrement décentralisée et avancée. Construit sur la blockchain Massa, Dusa met l'accent sur des principes clés tels que la décentralisation complète, l'accessibilité pour tous les profils d'utilisateurs, l'interopérabilité avec les futures applications décentralisées (DApps) et un engagement fort en faveur de la sécurité et de la résistance à la censure. Sa feuille de route décrit une approche progressive, comprenant la recherche et le développement, les tests, les quêtes incitatives et le déploiement d'un échange décentralisé (DEX). Les caractéristiques uniques de Dusa incluent une liquidité concentrée, des frais variables, une liquidité autonome et des ordres de négociation complexes, tous conçus pour améliorer l'expérience utilisateur et maximiser le rendement. Avec une équipe dédiée, des investisseurs stratégiques et des conseillers, Dusa vise à être pionnier dans l'adoption de contrats intelligents autonomes et à étendre ses solutions décentralisées à d'autres écosystèmes.
Examen de l'architecture
Reconnaissant que Dusa est un dérivé d'une solution bien établie, TraderJoe, et s'aligne sur un modèle architectural reconnu, nous notons des recommandations supplémentaires limitées pour l'architecture actuelle. Cependant, notre évaluation de l’architecture du protocole Dusa a conduit à une vision globale, combinant des informations précieuses avec des recommandations réfléchies d’amélioration :
- Du point de vue des meilleures pratiques, nous recommandons d'envisager la mise en œuvre d'un portefeuille multisig pour gérer les rôles privilégiés à l'avenir. Bien que nous reconnaissions la publication récente du code Massa multisig (https://github.com/massalabs/massa-standards/tree/feature/multisig-sc/smart-contracts/assembly/contracts/multisig), nous conseillons la prudence et considérons l’utilisation d’une clé privée standard également comme une option viable pour le moment.
- Une autre recommandation judicieuse suggère d’adopter un modèle de liquidité unifié, en envisageant un Vault/PoolManager global au lieu de contrats individuels par pool. Ce changement stratégique, inspiré des récentes avancées des AMM comme Uniswap V4 et Balancer, promet des avantages significatifs. Il s’agit notamment de swaps multi-sauts rentables et d’une capacité de prêt flash améliorée, attribuées à un accès rationalisé à l’ensemble du pool de liquidités.
Évaluation de la sécurité
Tests spécifiques à Dusa
Comme Dusa se trouve dans une situation unique en tant que reflet de TraderJoe dans un langage de programmation différent, nous avons effectué plusieurs tests supplémentaires en plus de nos tests habituels pour nous assurer qu'il n'y a aucune pièce manquante. Voici une liste de tests réalisés spécifiquement pour le protocole Dusa :
Contrôles de sécurité
- Vérifications de débordement/sous-débordement, notamment en raison du changement de base de code d'un langage avec des vérifications par défaut à un langage où des vérifications explicites sont requises.
- Utilisation de bibliothèques sécurisées (checked_*).
- Cohérence entre les contrats concernant les flux de fonds et les appels.
- Visibilité des fonctions pour garantir que les fonctions appropriées sont exportées.
- Mise en place du contrôle d'accès et protection des fonctions sensibles.
- Swap protection pour sécuriser les interactions avec la liquidité contre le dérapage.
Authentification et autorisation
- Audit de l'ensemble du processus d'authentification, des droits des propriétaires et du schéma d'autorisation des points d'entrée publics individuels.
- Identification des vulnérabilités potentielles conduisant à des autorisations malveillantes pour les attaquants.
Mathématiques et gestion des variables
- Problèmes liés aux calculs, notamment avec plusieurs types de variables, la conversion et la gestion des nombres à virgule flottante.
- Erreurs décimales liées à l'aspect unique de MASSA ayant 9 décimales.
- Gestion des capacités de débordement/sous-débordement.
Prêt Flash et gestion des liquidités
- Examen des erreurs typiques liées aux prêts flash, notamment les erreurs de calcul et le blocage de fonds.
- Problèmes liés à la création d'usines et de paires, tels que la création de pools dangereux et la gestion des liquidités.
- Vérification des calculs de suppression de liquidité, en tenant compte des frais obtenus lors de l'apport de liquidité.
Fonctionnalité et mise en œuvre
- Mise en œuvre de swaps par rapport aux autres DEX, en mettant l'accent sur la gestion des frais et les différences dans les types de jetons.
- Possibilité d'attaques DoS lors de l'utilisation de types dangereux tels que des vecteurs ou des tableaux.
- Vérification des problèmes de centralisation, tels que l'influence potentielle sur les prix, les transferts de jetons utilisateur et les changements de configuration.
Gestion des données contextuelles
- Vérifiez la transmission des données contextuelles correctes aux fonctions pour éviter les vulnérabilités.
Tests génériques
Les cas de test suivants ont été la ligne directrice lors de l'audit du système. Cette liste de contrôle est une version modifiée de la SCSVS v1.2, avec une grammaire améliorée, de la clarté, de la concision et des critères supplémentaires. Lorsqu'il y a une lacune dans la numérotation, un critère initial a été supprimé. Les critères marqués d'un astérisque ont été ajoutés par nos soins.
Architecture, conception et modélisation des menaces
Architecture, conception et modélisation des menaces | Nom du test |
G1.2 | Chaque modification de conception introduite est précédée d'une modélisation des menaces. |
G1.3 | La documentation définit clairement et précisément toutes les frontières de confiance dans le contrat (relations de confiance avec les autres contrats et flux de données importants). |
G1.4 | Le SCSVS, les exigences ou la politique de sécurité sont disponibles pour tous les développeurs et testeurs. |
G1.5 | Les événements pour les opérations (changement d'état/cruciales pour l'entreprise) sont définis. |
G1.6 | Le projet inclut un mécanisme qui peut stopper temporairement les fonctionnalités sensibles en cas d'attaque. Ce mécanisme ne doit pas bloquer l'accès des utilisateurs à leurs actifs (par exemple, les jetons). |
G1.7 | La quantité de crypto-monnaies non utilisées conservées sur le contrat est contrôlée et au niveau minimum acceptable afin de ne pas devenir une cible potentielle d'attaque. |
G1.8 | Si la fonction de secours peut être appelée par n'importe qui, elle est incluse dans le modèle de menace. |
G1.9 | La logique métier est cohérente. Des changements importants dans la logique doivent être appliqués dans tous les contrats. |
G1.10 | Des outils d'analyse de code automatique sont utilisés pour détecter les vulnérabilités. |
G1.11 | La dernière version majeure de Solidity est utilisée. |
G1.12 | Lors de l'utilisation d'une implémentation externe d'un contrat, la version la plus récente est utilisée. |
G1.13 | Lorsque les fonctions sont remplacées pour étendre les fonctionnalités, le mot-clé super est utilisé pour conserver les fonctionnalités précédentes. |
G1.14 | L'ordre d'héritage est soigneusement spécifié. |
G1.15 | Il existe un composant qui surveille l'activité du contrat à l'aide d'événements. |
G1.16 | Le modèle de menace inclut les transactions de baleines. |
G1.17 | La fuite d'une clé privée ne compromet pas la sécurité de l'ensemble du projet. |
Les politiques et les procédures
Les politiques et les procédures | Nom du test |
G2.2 | La sécurité du système fait l'objet d'une surveillance constante (par exemple, le niveau de financement attendu). |
G2.3 | Il existe une politique pour suivre les nouvelles vulnérabilités de sécurité et mettre à jour les bibliothèques vers la dernière version sécurisée. |
G2.4 | Le service de sécurité peut être contacté publiquement et que la procédure de traitement des bogues signalés (par exemple, une prime de bogue approfondie) est bien définie. |
G2.5 | Le processus d'ajout de nouveaux composants au système est bien défini. |
G2.6 | Le processus de modifications majeures du système implique la modélisation des menaces par une société externe. |
G2.7 | Le processus d'ajout et de mise à jour des composants du système comprend un audit de sécurité par une société externe. |
G2.8 | En cas de piratage, une procédure d'atténuation claire et bien connue est en place. |
G2.9 | La procédure en cas de piratage définit clairement quelles personnes doivent exécuter les actions requises. |
G2.10 | La procédure consiste à alerter d'autres projets sur le piratage via des canaux de confiance. |
G2.11 | Une procédure d'atténuation des fuites de clé privée est définie. |
Évolutivité
Évolutivité | Nom du test |
G3.2 | Avant la mise à jour, une émulation est faite dans un fork du réseau principal et tout fonctionne comme prévu sur la copie locale. |
G3.3 | Le processus de mise à niveau est exécuté par un contrat multisig où plus d'une personne doit approuver l'opération. |
G3.4 | Les timelocks sont utilisés pour les opérations importantes afin que les utilisateurs aient le temps d'observer les changements à venir (veuillez noter que la suppression des vulnérabilités potentielles dans ce cas peut être plus difficile). |
G3.5 | initialiser() ne peut être appelé qu'une seule fois. |
G3.6 | initialiser() ne peut être appelé que par un rôle autorisé via des modificateurs appropriés (par exemple initialiseur, seul propriétaire). |
G3.7 | Le processus de mise à jour est effectué en une seule transaction afin que personne ne puisse l'exécuter en amont. |
G3.8 | Les contrats évolutifs ont réservé un espace sur les créneaux horaires pour éviter l'écrasement. |
G3.9 | Le nombre d'emplacements réservés (en tant qu'écart) a été réduit de manière appropriée si de nouvelles variables ont été ajoutées. |
G3.10 | Il n'y a aucun changement dans l'ordre dans lequel les variables d'état du contrat sont déclarées, ni leurs types. |
G3.11 | Les nouvelles valeurs renvoyées par les fonctions sont les mêmes que dans les versions précédentes du contrat (par exemple propriétaire(), balanceOf(adresse)). |
G3.12 | L'implémentation est initialisée. |
G3.13 | L'implémentation ne peut pas être détruite. |
Logique métier
Logique métier | Nom du test |
G4.2 | La mise en œuvre de la logique du contrat et des paramètres du protocole correspond à la documentation. |
G4.3 | La logique métier procède dans un ordre d'étape séquentiel et il n'est pas possible de sauter des étapes ou de le faire dans un ordre différent de celui conçu. |
G4.4 | Le contrat a correctement appliqué les limites commerciales. |
G4.5 | La logique métier ne repose pas sur les valeurs récupérées à partir de contrats non approuvés (en particulier lorsqu'il y a plusieurs appels au même contrat dans un seul flux). |
G4.6 | La logique métier ne repose pas sur le solde du contrat (par exemple, solde == 0). |
G4.7 | Les opérations sensibles ne dépendent pas des données de bloc (par exemple, bloc de hachage, horodatage). |
G4.8 | Le contrat utilise des mécanismes qui atténuent les attaques de commande de transaction (front-running) (par exemple, les schémas de pré-engagement). |
G4.9 | Le contrat n'envoie pas de fonds automatiquement, mais permet aux utilisateurs de retirer des fonds dans des transactions distinctes à la place. |
Contrôle d'accès
Contrôle d'accès | Nom du test |
G5.2 | Le principe du moindre privilège est respecté. Les autres contrats ne devraient pouvoir accéder qu'aux fonctions et données pour lesquelles ils disposent d'une autorisation spécifique. |
G5.3 | Les nouveaux contrats ayant accès au contrat audité respectent le principe des droits minimaux par défaut. Les contrats doivent avoir un minimum ou aucune autorisation jusqu'à ce que l'accès aux nouvelles fonctionnalités soit explicitement accordé. |
G5.4 | Le créateur du contrat respecte le principe du moindre privilège et ses droits suivent strictement ceux décrits dans la documentation. |
G5.5 | Le contrat applique les règles de contrôle d'accès spécifiées dans un contrat de confiance, en particulier si le contrôle d'accès côté client dApp est présent et peut être contourné. |
G5.6 | Les appels à des contrats externes ne sont autorisés qu'en cas de nécessité. |
G5.7 | Le code modificateur est clair et simple. La logique ne doit pas contenir d'appels externes à des contrats non approuvés. |
G5.8 | Tous les attributs d'utilisateur et de données utilisés par les contrôles d'accès sont conservés dans des contrats de confiance et ne peuvent pas être manipulés par d'autres contrats, sauf autorisation spécifique. |
G5.9 | Les contrôles d'accès échouent en toute sécurité, y compris lorsqu'un retour se produit. |
G5.10 | Si l'entrée (paramètres de la fonction) est validée, l'approche de validation positive (liste blanche) est utilisée dans la mesure du possible. |
Communication
Communication | Nom du test |
G6.2 | Les bibliothèques qui ne font pas partie de l'application (mais dont le contrat intelligent dépend pour fonctionner) sont identifiées. |
G6.3 | L'appel délégué n'est pas utilisé avec les contrats non approuvés. |
G6.4 | Les contrats de tiers n'occultent pas les fonctions spéciales (par exemple, revenir). |
G6.5 | Le contrat ne vérifie pas si l'adresse est un contrat utilisant l'opcode extcodesize. |
G6.6 | Les attaques de réentrance sont atténuées en bloquant les appels récursifs provenant d'autres contrats et en suivant le modèle Check-Effects-Interactions. N'utilisez pas la fonction d'envoi sauf si c'est indispensable. |
G6.7 | Le résultat d'appels de fonction de bas niveau (par exemple envoyer, déléguer appeler, appeler) d'autres contrats est cochée. |
G6.8 | Le contrat repose sur les données fournies par le bon expéditeur et non sur la valeur tx.origin. |
Arithmétique
Arithmétique | Nom du test |
G7.2 | Les valeurs et les opérations mathématiques résistent aux débordements d'entiers. Utilisez la bibliothèque SafeMath pour les opérations arithmétiques avant Solidity 0.8.*. |
G7.3 | Les extraits de code non cochés de Solidity ≥ 0.8.* n'introduisent pas de sous/débordements entiers. |
G7.4 | Les valeurs extrêmes (par exemple, les valeurs maximales et minimales du type de variable) sont prises en compte et ne modifient pas le flux logique du contrat |
G7.5 | L'inégalité non stricte est utilisée pour l'égalité d'équilibre. |
G7.6 | Les ordres de grandeur corrects sont utilisés dans les calculs. |
G7.7 | Dans les calculs, la multiplication est effectuée avant la division pour plus de précision. |
G7.8 | Le contrat ne suppose pas une précision en virgule fixe et utilise un multiplicateur ou stocke à la fois le numérateur et le dénominateur. |
Déni de service
Déni de service | Nom du test |
G8.2 | Le contrat n'itère pas sur des boucles non liées. |
G8.3 | La fonctionnalité d'autodestruction n'est utilisée que si nécessaire. S'il est inclus dans le contrat, il doit être clairement décrit dans la documentation. |
G8.4 | La logique métier n'est pas bloquée si un acteur (par exemple contrat, compte, oracle) est absent. |
G8.5 | La logique métier ne décourage pas les utilisateurs d'utiliser des contrats (par exemple, le coût de la transaction est supérieur au profit). |
G8.6 | Les expressions de fonctions assert ou require ont une variante passante. |
G8.7 | Si la fonction de secours ne peut être appelée par personne, elle ne bloque pas les fonctionnalités du contrat. |
G8.8 | Il n'y a pas d'opérations coûteuses en boucle. |
G8.9 | Il n'y a pas d'appels à des contrats non approuvés dans une boucle. |
G8.10 | S'il existe une possibilité de suspendre l'exécution du contrat, il est également possible de le reprendre. |
G8.11 | Si des listes blanches et des listes noires sont utilisées, elles n'interfèrent pas avec le fonctionnement normal du système. |
G8.12 | Il n'y a pas de DoS causé par les débordements et les débordements. |
Données de la chaîne de blocs
Données de la chaîne de blocs | Nom du test |
G9.2 | Toutes les données enregistrées dans les contrats ne sont pas considérées comme sécurisées ou privées (même les variables privées). |
G9.3 | Aucune donnée confidentielle n'est stockée dans la blockchain (mots de passe, données personnelles, token etc.). |
G9.4 | Les contrats n'utilisent pas de littéraux de chaîne comme clés pour les mappages. Les constantes globales sont utilisées à la place pour empêcher l'attaque homoglyphe. |
G9.5 | Le contrat ne génère pas trivialement des nombres pseudo-aléatoires basés sur les informations de la blockchain (par exemple, l'ensemencement avec le numéro de bloc). |
Utilisation du gaz et limites
Utilisation du gaz et limites | Nom du test |
G10.1 | L'utilisation du gaz est anticipée, définie et a des limites claires qui ne peuvent pas être dépassées. La structure du code et les entrées malveillantes ne doivent pas provoquer d'épuisement des gaz. |
G10.2 | L'exécution et la fonctionnalité des fonctions ne dépendent pas des frais de gaz codés en dur (ils sont susceptibles de varier). |
Clarté et lisibilité
Clarté et lisibilité | Nom du test |
G11.2 | La logique est claire et modularisée en plusieurs contrats et fonctions simples. |
G11.3 | Chaque contrat comporte un court commentaire de 1 à 2 phrases qui explique son objectif et sa fonctionnalité. |
G11.4 | Des implémentations prêtes à l'emploi sont utilisées, cela est clairement indiqué dans les commentaires. Si ces implémentations ont été modifiées, les modifications sont notées tout au long du contrat. |
G11.5 | L'ordre d'héritage est pris en compte dans les contrats qui utilisent plusieurs fonctions d'héritage et de duplication. |
G11.6 | Dans la mesure du possible, les contrats utilisent du code testé existant (par exemple, des contrats de jeton ou des mécanismes tels que propriétaire) au lieu d'implémenter les leurs. |
G11.7 | Des modèles de dénomination cohérents sont suivis tout au long du projet. |
G11.8 | Les variables ont des noms distinctifs. |
G11.9 | Toutes les variables de stockage sont initialisées. |
G11.10 | Les fonctions avec le type de retour spécifié renvoient une valeur de ce type. |
G11.11 | Toutes les fonctions et variables sont utilisées. |
G11.12 | exigent est utilisé au lieu de revenir in if Déclarations. |
G11.13 | La affirmer La fonction est utilisée pour tester les erreurs internes et le exigent La fonction est utilisée pour garantir une condition valide dans les entrées des utilisateurs et des contrats externes. |
G11.14 | Le code d'assemblage n'est utilisé que si nécessaire. |
Couverture de test
Couverture de test | Nom du test |
G12.2 | Les récits d'abus détaillés dans le modèle de menace sont couverts par des tests unitaires |
G12.3 | Les fonctions sensibles dans les contrats vérifiés sont couvertes par des tests en phase de développement. |
G12.4 | La mise en œuvre des contrats vérifiés a été vérifiée pour les vulnérabilités de sécurité à l'aide d'analyses statiques et dynamiques. |
G12.5 | La spécification du contrat a été formellement vérifiée |
G12.6 | La spécification et les résultats de la vérification formelle sont inclus dans la documentation. |
Finance décentralisée
Finance décentralisée | Nom du test |
G13.1 | Le contrat du prêteur ne suppose pas que son solde (utilisé pour confirmer le remboursement du prêt) soit modifié uniquement avec ses propres fonctions. |
G13.2 | Les fonctions qui modifient le solde des prêteurs et/ou prêtent de la crypto-monnaie sont non réentrantes si le contrat intelligent permet d'emprunter la crypto-monnaie de la plateforme principale (par exemple Ethereum). Il bloque les attaques qui mettent à jour le solde de l'emprunteur lors de l'exécution du prêt flash. |
G13.3 | Les fonctions de prêt Flash ne peuvent appeler que des fonctions prédéfinies sur le contrat de réception. Si cela est possible, définissez un sous-ensemble de contrats de confiance à appeler. Habituellement, le contrat d'envoi (d'emprunt) est celui à rappeler. |
G13.4 | Si cela inclut des opérations potentiellement dangereuses (par exemple, renvoyer plus d'ETH/tokens qu'emprunté), la fonction du destinataire qui gère les ETH ou les tokens empruntés ne peut être appelée que par le pool et dans le cadre d'un processus initié par le propriétaire du contrat destinataire ou une autre source de confiance (par exemple multisig). |
G13.5 | Les calculs de la part du pool de liquidités sont effectués avec la plus grande précision possible (par exemple, si la contribution est calculée pour ETH, elle doit être effectuée avec une précision de 18 chiffres - pour Wei, pas Ether). Le dividende doit être multiplié par 10 à la puissance du nombre de chiffres décimaux (par exemple dividende * 10^18 / diviseur). |
G13.6 | Les récompenses ne peuvent pas être calculées et distribuées dans le même appel de fonction qui dépose des jetons (il doit également être défini comme non réentrant). Cela protège des fluctuations momentanées des actions. |
G13.7 | Les contrats de gouvernance sont protégés contre les attaques de prêts flash. Une technique d'atténuation possible consiste à exiger que le processus de dépôt de jetons de gouvernance et de proposition d'un changement soit exécuté dans différentes transactions incluses dans différents blocs. |
G13.8 | Lors de l'utilisation d'oracles en chaîne, les contrats peuvent suspendre les opérations en fonction du résultat des oracles (en cas d'oracle compromis). |
G13.9 | Les contrats externes (même ceux de confiance) qui sont autorisés à modifier les attributs d'un contrat de projet (par exemple, le prix du jeton) ont les limitations suivantes mises en œuvre : des seuils pour le changement (par exemple, pas plus/moins de 5 %) et une limite de mises à jour (par exemple une mise à jour par jour). |
G13.10 | Les attributs de contrat pouvant être mis à jour par les contrats externes (même ceux de confiance) sont surveillés (par exemple à l'aide d'événements) et une procédure de réponse aux incidents est mise en place (par exemple lors d'une attaque en cours). |
G13.11 | Les opérations mathématiques complexes qui consistent à la fois en opérations de multiplication et de division effectuent d'abord des multiplications, puis des divisions. |
G13.12 | Lors du calcul des prix d'échange (par exemple ETH à jeton ou vice versa), le numérateur et le dénominateur sont multipliés par les réserves (voir le getInputPrice fonction de l' UniswapExchange Contrat). |
Commandez l'audit de Sayfer
Constatations des audits
[H] Risque de course avant lors de la création d'une nouvelle paire
ID | DIRE-01 |
Statut | Fixé |
Analyse | Haute |
La Brochure Impact | Dans certains cas, les utilisateurs peuvent perdre les fonds qu'ils ont déposés afin de financer la création de paires. Soit un leader malveillant peut créer une paire aux dépens d'un autre utilisateur, soit plusieurs utilisateurs peuvent tenter de créer une paire en même temps, avec succès ou échec au hasard. |
Localisation |
|
Description
Afin de créer une nouvelle paire, l'utilisateur doit appeler Routeur ::createLBPair(StaticArray ). Sous le capot, cette fonction appelle Usine : createLBPair (StaticArray ), qui à son tour appelle Massa transferCoins(Adresse, numéro).
- Usine.ts:264 ; créerLBPair(StaticArray )
transferCoins(_pair._origin, 200 * ONE_COIN);
Selon le Documentation, cette fonction transfère simplement les pièces de l'adresse actuelle vers une adresse donnée. Cela signifie que ces fonds doivent être préalablement envoyés à Usine. D'autre part, les utilisateurs ont la possibilité d'appeler créer une paire depuis le routeur, qui est le point d’entrée par défaut pour d’autres opérations. Cependant, s'ils sont déposés dans le cadre d'une transaction distincte, il est possible que quelqu'un, intentionnellement ou non, appelle également créerLBPair(StaticArray ).
Lorsqu'un bloc de transactions est finalisé, elles seront disposées dans un ordre inconnu. Ensuite, la première transaction incluse verra ces fonds transférés de Factory vers une nouvelle paire, tandis que le deuxième utilisateur (cette dernière transaction) verra sa transaction annulée en raison du manque de fonds disponibles.
Atténuation
Le financement de la création de paires doit effectivement avoir lieu dans la même transaction pour éviter les problèmes de réorganisation des transactions.
Par exemple, l'un des moyens d'y parvenir pourrait être un mécanisme vérifiant le solde de l'usine et le solde du pool à la fin d'une fonction et renvoyant le surplus, similaire à celui-ci. https://github.com/massalabs/coin-vester/blob/master/smart-contract/assembly/contracts/main.ts#L34
Le mécanisme sera en place dans le créerLBPair fonction de Usine), dans le constructeur, menthe, brûler, collecter les frais, augmenterOracleLength, transfert sécuriséDe & safeBatchTransferFrom (de paire). Ce sont les fonctions capables de dépenser Massa pour le stockage car elles peuvent créer de nouvelles entrées dans le stockage (la modification du stockage ne coûte rien). Les fonctions interagissant avec ces fonctions doivent également disposer de ce mécanisme.
On peut les séparer en deux sortes différentes :
- Fonctions interagissant avec celles-ci et qui n'interagissent pas avec WMAS (créerLBPair du routeur et de l'usine + ajouterLiquidité, supprimerLiquidité) transférera tous les Pièces transférées, enregistrez le solde du SC dans une constante, et après l'appel du SC, retransférez à l'appelant la différence entre le nouveau solde et le solde enregistré.
- Fonctions interagissant avec celles-ci et qui interagissent avec WMAS (ajouterLiquiditéMAS, supprimerLiquiditéMAS) aura besoin d'un paramètre supplémentaire pour connaître le nombre de pièces à emballer, vous enverrez la différence entre Pièces transférées et ce numéro dans l'appel. Le reste du mécanisme de ces fonctions sera le même que celui juste avant.
[H] Les fonds déposés pour la création de paires peuvent être perdus
ID | DIRE-02 |
Statut | Fixé |
Analyse | Haute |
Impact sur les entreprises | Les utilisateurs qui déposent des fonds sur le routeur pour créer une paire peuvent perdre leur argent sans voir de résultat. Nous avons évalué ce problème comme étant élevé (plutôt que critique) car il existe un flux de travail alternatif : appeler usine::createLBPair(StaticArray ) directement avec les fonds. |
Localisation |
|
Description
Ce problème résulte de la façon dont la création de paires est conçue. Un utilisateur peut appeler Routeur ::createLBPair(StaticArray ) et comme une création de paire nécessite un dépôt, il peut joindre des fonds à l'appel de fonction, ce qui semble être une solution intuitive.
Cependant, si l'utilisateur le fait, les fonds n'atteindront jamais la paire et seront perdus dans le contrat (bien qu'ils puissent être récupérés par le propriétaire). En effet, ils seront bloqués dans le contrat du routeur, tandis que la création de la paire a lieu dans le contrat d'usine, où transferCoins(), qui déduit les fonds de l'adresse actuelle (de l'usine), est utilisé à la place.
- Usine.ts:264 ; créerLBPair(StaticArray )
transferCoins(_pair._origin, 200 * ONE_COIN);
Puisqu'il est implémenté dans l'usine, les fonds envoyés au routeur n'atteindront pas l'usine, qui n'aura pas non plus les fonds nécessaires pour créer une paire et revenir en arrière.
Atténuation
Une option consiste à mettre en œuvre la solution suggérée dans DIRE-01.
Inversement, Usine.ts peut être appelé directement pour créer des paires et demander aux utilisateurs d'envoyer soit le montant exact requis avec l'appel de fonction, OU au moins le montant requis avec le remboursement de tout excédent de fonds envoyé.
[M] Plusieurs paires du même type peuvent diluer la liquidité
ID | DIRE-03 |
Statut | Fixé |
Analyse | Moyenne |
Impact sur les entreprises | Si une application AMM permet de créer plusieurs pools avec les mêmes paramètres, la liquidité peut être diluée dans ces pools, au lieu d'être concentrée dans un seul. Cela pourrait avoir un impact négatif sur les utilisateurs et entraîner des transactions moins favorables pour les utilisateurs du protocole.
De plus, la paire précédente ne sera plus utilisée pour le routage. Cela peut entraîner des liquidités ou une manipulation des prix. |
Localisation |
|
Description
Lors de la création d’une nouvelle paire, il n’est pas vérifié si exactement la même paire existe déjà. Cela peut disperser les liquidités des utilisateurs sur plusieurs pools équivalents. Les pools à faible liquidité sont plus sujets aux manipulations de prix et offrent des transactions moins favorables ; ils doivent donc être évités.
Atténuation
Vérifiez si une paire de certains paramètres existe déjà lors de la création de la paire, si c'est le cas, annulez.
[L] La vérification exacte du solde après un prêt flash peut être utilisée de manière abusive
ID | DIRE-04 |
Statut | Fixé |
Analyse | Faible |
Impact sur les entreprises | Un destinataire de prêt flash peut effectuer des appels externes lors du rappel. Étant donné que le système exige que le solde après le prêt flash soit exactement le solde avant plus les frais, ces contrats externes pourraient transférer un très petit montant à la paire pendant l'exécution pour garantir que le prêt flash échouera (ce qui peut être rentable pour eux). dans certaines situations). |
Localisation |
|
Description
Après un prêt flash, le système exige que le solde soit exactement le solde avant le prêt flash plus les frais.
- flashLoan(StaticArray )
assert(
_balanceAfter == SafeMath256.add(_balanceBefore, _fees.total),
LBPair__FlashLoanInvalidBalance(),
);
En règle générale, il est nécessaire que le solde soit supérieur, car exiger une correspondance exacte est restrictif.
Atténuation
Vérifiez uniquement si le solde est supérieur au solde avant le prêt flash majoré des frais. C'est également la logique que TraderJoe utilise dans sa fonction de prêt flash.
[L] Ignorer une paire LB n'émet pas d'événement
ID | DIRE-05 |
Statut | Fixé |
Analyse | Faible |
La Brochure Impact | Les indexeurs hors chaîne peuvent recevoir des informations incorrectes, conduisant à des calculs erronés. |
Localisation |
|
Description
La fonction setLBPairIgnored(StaticArray ) peut être utilisé pour contrôler si une paire doit être ignorée pour le routage ou non. Tout changement de flag via cette fonction émet l'événement SET_LBPAIR_IGNORED. Cependant, il est également possible de changer le drapeau via setLBPairInformation(StaticArray ), qui n'émet pas d'événement.
Atténuation
[L] Recouvrement des frais incohérent
ID | DIRE-06 |
Statut | Reconnu |
Analyse | Faible |
La Brochure Impact | N'importe quel utilisateur peut déclencher la collecte des frais pour d'autres utilisateurs, alors que la collecte des frais de protocole ne peut être déclenchée que par le propriétaire. |
Localisation |
|
Description
N'importe qui peut appeler collecter des frais (StaticArray ) pour toute adresse de répartir les frais à cette adresse. Cela peut être indésirable pour certains utilisateurs qui souhaitent contrôler le moment où les frais leur sont distribués.
Ceci est en outre incompatible avec collectProtocolFees(StaticArray ), qui ne peut être appelé que par le destinataire.
- collectProtocolFees(StaticArray )
assert(
Context.caller().equals(_feeRecipient),
LBPair__OnlyFeeRecipient(_feeRecipient, Context.caller()),
);
Atténuation
[L] Utilisation incohérente de SafeMath
ID | DIRE-07 |
Statut | Fixé |
Analyse | Faible |
La Brochure Impact | Les dépassements de capacité ou les dépassements inférieurs dans le code peuvent entraîner des retours inattendus et/ou des erreurs de calcul. |
Localisation | - |
Description
Même si SafeMath est utilisé à de nombreux endroits, certaines fonctions qui utilisent des opérations arithmétiques restent non protégées, ce qui peut par conséquent conduire à des débordements ou des sous-débordements.
Atténuation
[L] Énumération des actifs inefficace
ID | DIRE-08 |
Statut | Fixé |
Analyse | Faible |
La Brochure Impact | Certaines fonctions d'usine consommeront plus de gaz que nécessaire. Dans le pire des cas, si le propriétaire enregistre un très grand nombre d’actifs, cela pourrait conduire à un DoS. Mais c'est peu probable. |
Localisation |
|
Description
voici deux problèmes avec cette fonction :
- La boucle ne se rompt pas après avoir trouvé un actif et parcourt inutilement le reste du tableau. Ainsi, chaque cas is le pire des cas.
- Un mappage serait ici plus efficace, car il nécessite une recherche temporelle constante.
- isQuoteAsset (Adresse)
for (let i = 0; i < quoteAssets.length; i++) {
if (quoteAssets[i].equals(_token)) {
isQuoteAsset = true;
}
}
Atténuation
Il y a deux solutions ici :
- Conservez l'algorithme de recherche linéaire actuel et ajoutez simplement une pause dans le if bloquer après réglage isQuoteAsset à vrai.
- Une meilleure solution serait de passer à un mappage. Lorsqu'un nouveau jeton est ajouté au système, quoteActifs[token] doit être défini sur true. Désormais, il est accessible en cas de besoin – plus besoin de le rechercher. Peut-être que toute la fonction peut simplement être remaniée.
[L] Les frais maximum du prêt Flash ne sont pas définis après le déploiement
ID | DIRE-09 |
Statut | Fixé |
Analyse | Faible |
La Brochure Impact | Il est possible d'avoir des frais de prêt flash supérieurs à MAX_FEE. |
Localisation |
|
Description
Chaque fois que les frais du prêt flash sont définis à l'aide de setFlashLoanFee(), on valide qu'elle est inférieure à la valeur MAX_FEE. Toutefois, cette vérification n’est pas effectuée lors de l’initialisation du contrat et il est possible d’y fixer des frais de prêt flash arbitrairement élevés.
Atténuation
[L] Protection contre les glissements incomplète – Contrôle des délais manquants
ID | DIRE-10 |
Statut | Fixé |
Analyse | Faible |
La Brochure Impact | Il existe une probabilité accrue que les utilisateurs obtiennent des transactions moins favorables lorsqu'ils utilisent l'AMM. |
Localisation | Routeur.ts
|
Description
Le slippage est le résultat d'une volatilité des solutions de type AMM, et signifie simplement que le prix lors de la demande d'un changement de transaction/swap/liquidité est différent de celui lors de l'exécution de la transaction. Pour protéger les utilisateurs d'énormes dérapages, qui peuvent être naturels ou résulter d'attaques intentionnelles comme le Sandwiching, il existe deux types génériques de protections : le montant minimal, qui est présent, et le contrôle des délais, qui manque.
Ces contrôles doivent être mis en œuvre pour tout swap, ajout ou retrait de liquidité, car tous sont sujets à des dérapages.
Un contrôle de délai ne permet tout simplement pas d'inclure la transaction après un certain moment, qui peut par exemple être intentionnellement inclus plus tard par un constructeur de blocs malveillant pour tenter quand même d'exécuter la transaction à des conditions de prix moins favorables. Cependant, étant donné qu’un montant minimal de jetons est vérifié, l’impact de ce problème est limité.
Atténuation
Mettre en œuvre le _assurer (date limite) de la même manière, il est déjà présent dans toutes les autres fonctions traitant de la liquidité.
[L] Transfert de propriété en une étape
ID | DIRE-11 |
Statut | Fixé |
Analyse | Faible |
La Brochure Impact | Fournir une adresse incorrecte pourrait entraîner une perte irrévocable de la propriété du contrat. |
Localisation |
|
Description
In Usine.ts, le changement de propriétaire est réalisé par l'ancien propriétaire en appelant le transfert de propriété ([u8]) avec le nouveau propriétaire. La fonction modifie alors le PROPRIÉTAIRE état variable.
- transfert de propriété ([u8])
export function transferOwnership(bs: StaticArray<u8>): void {
_onlyOwner();
const _newOwner = new Address(new Args(bs).nextString().unwrap());
_setFeeRecipient(_newOwner);
Storage.set(OWNER, _newOwner.toString());
}
Atténuation
Nous recommandons de mettre en œuvre un processus en deux étapes pour le transfert de propriété. Ceci est conforme aux bonnes pratiques largement reconnues et pourrait empêcher les transferts accidentels. Pour illustrer, nous utiliserons l'implémentation d'OpenZepplin.
Un transfert de propriété en deux étapes nécessite d’abord que le propriétaire actuel initie le transfert.
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
Mais pour finaliser le processus, le nouveau propriétaire doit approuver le transfert.
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
Cela garantit que le nouveau propriétaire est la cible visée.
[I] Émission d'événement insuffisante
ID | DIRE-12 |
Statut | Fixé |
Analyse | D'information |
La Brochure Impact | Diminution de la traçabilité et de la visibilité des changements historiques d’état clé affectant le protocole. |
Localisation | Usine.ts
|
Description
Certains des changements d'état clés du protocole n'émettent pas d'événement associé.
Remarque: transferOwnership (bs: StaticArray ) émet un événement, mais uniquement pour _setFeeRecipient.
Atténuation
[I] Les getters et setters sont mélangés avec des fonctions externes
ID | DIRE-13 |
Statut | Fixé |
Analyse | D'information |
La Brochure Impact | Le mixage, les getters, les setters, les points d'entrée et les fonctions internes rendent le code moins lisible. |
Localisation |
|
Description
Certains contrats ont des sections distinctes contenant des fonctions qui changent l'état (setters), le lisent (getters) ou font partie de l'arborescence des appels de fonction (interne).
Mais dans certains contrats, cet ordre est perturbé – les fonctions sont mélangées. Parfois, les fonctions exportées (points d’entrée) sont également confondues avec les fonctions internes.
Atténuation
[I] Manque de tests unitaires
ID | DIRE-14 |
Statut | Reconnu |
Analyse | D'information |
La Brochure Impact | Les scénarios de test et les tests unitaires aident les développeurs à détecter les bogues et les vulnérabilités qui autrement passeraient inaperçus lors d'une simple analyse statique. Les tests dynamiques sont inestimables pour garantir la qualité du produit fini. |
Localisation | - |
Description
Hormis une dizaine de tests pour un certain nombre de fonctionnalités de la bibliothèque, le code ne comportait pas de tests unitaires, fonctionnels ou d'intégration. Tous les défauts ne peuvent pas être détectés par une simple analyse statique, laissant le produit dans une position précaire.
Atténuation
Il est considéré comme une bonne pratique de garantir que la couverture du code pour les tests est aussi élevée que possible et que les scénarios de test incluent à la fois des chemins heureux et malheureux.
[I] Code inutile
ID | DIRE-15 |
Statut | Fixé |
Analyse | D'information |
La Brochure Impact | Ce problème n'a aucun impact direct sur le code ou sur le protocole et a donc été classé à titre informatif. |
Localisation | Routeur.ts : 770-772 ; _getAmountsIn(u64[], Adresse[], IERC20[], u256) |
Description
La fonction _getAmountsIn() prend les étapes bin comme argument et effectue la vérification suivante :
- _getAmountsIn(u64[], Adresse[], IERC20[], u256)
if (_binStep == 0) {
// means TraderJoe V1 swap
} else {
...
}
Cependant, cela n’est pas nécessaire. Le système ne prend pas en charge les swaps de style V1 et le reste de la fonction ne prend pas en compte les étapes bin, car il reçoit les paires (correspondant aux étapes bin) comme argument supplémentaire.
Atténuation
[I] Importations inutilisées
ID | DIRE-16 |
Statut | Fixé |
Analyse | D'information |
La Brochure Impact | Ce problème n'a aucun impact direct sur le code ou sur le protocole et a donc été classé à titre informatif. |
Localisation |
|
Description
Les importations spécifiées semblent ne jamais être utilisées dans leurs contrats respectifs. Ils pourraient être supprimés.
Atténuation
[I] Utilisation des « nombres magiques »
ID | DIRE-17 |
Statut | Reconnu |
Analyse | D'information |
La Brochure Impact | Cela peut augmenter la difficulté d'analyser le code pour les lecteurs inconnus. |
Localisation |
|
Description
À plusieurs endroits, le contrat utilise des valeurs numériques qui ne sont pas bien documentées, décrites ou commentées.
Atténuation
Ajoutez des commentaires expliquant le choix des constantes.