16. December, 2021
Introduktion
1inch team bad os om at gennemgå og revidere deres Limit Order Protocol v2 smarte kontrakter. Vi kiggede på koden og offentliggør nu vores resultater.
Anvendelsesområde
Vi reviderede forpligtelse 4d94eea25e4dac6271bfd703096a5c4a4d899b4a
af 1inch/limit-order-protocol
depot. I omfang var følgende kontrakter:
- OrderMixin.sol
- OrderRFQMixin.sol
- PredicateHelper.sol
- RevertReasonParser.sol
- Permitable.sol
- ChainlinkCalculator.sol
- ArgumentsDecoder.sol
- AmountCalculator.sol
- NonceManager.sol
- LimitOrderProtocol.sol
- ImmutableOwner.sol
- InteractiveNotificationReceiver.sol
- AggregatorInterface.sol
- IDaiLikePermit.sol
Alle andre projektfiler og mapper (herunder tests), sammen med eksterne afhængigheder og projekter, spilteori og incitamentsdesign, blev også udelukket fra denne revisions omfang. Ekstern kode og kontraktafhængighed blev antaget at fungere som dokumenteret, og back-end-tjenester leveret af 1inch blev antaget at handle i protokollens bedste interesse.
Generel sundhed
Generelt fandt vi, at projektets kodebase var læsbar og velorganiseret, selvom den kunne drage fordel af mere omfattende dokumentation, især omkring blokkene med assembly-kode, protokollens kantcases, aktiver/prædikater/eksterne-ressourcer, der vil blive brugt, ansvar/begrænsninger for den leverede back-end-tjeneste og interaktioner mellem aktører. Projektet går meget op i at gøre handlinger gaseffektive, nogle gange endda med risiko for at gøre koden sværere at ræsonnere om; vi rejser spørgsmål relateret til det nedenfor. Under hele revisionen var 1-tommer-teamet yderst tilgængeligt, lydhørt og meget nemt at arbejde med.
System overblik
Limit Order Protocol muliggør orden makers
at underskrive ordrer uden for kæden for token-swaps. Protokollen letter derefter udfyldelsen af tidligere underskrevne ordrer efter ordre takers
. Ordrer er meget udvidelige og kan statisk kalde eksterne kontrakter på flere punkter gennem hele ordreudfyldningsprocessen. Denne udvidelsesmulighed gennemsyrer protokollen med nytte, men den tilføjer både kompleksitet og en større angrebsflade for selve ordrerne.
Det er vigtigt at bemærke, at der ikke er nogen on-chain opbevaring af ordreoplysninger. Opfyldningsstatus eller annulleringsstatus for ordrer spores kun via ordrehash. Dette nødvendiggør, at ordrer deles peer-to-peer eller via en centraliseret part. I dette tilfælde har 1inch-teamet til hensigt at fungere som den centraliserede part, samle signerede ordrer og bruge disse ordrer som en kilde til likviditet til deres andre protokoller. Ordrer vil blive offentliggjort via deres egen API, så brugerne er i stand til at interagere med dem.
Denne centralisering giver 1 tommer-teamet ekstrem kontrol over, hvilke ordrer der offentliggøres og i sidste ende eksekveres. Dette giver dem også mulighed for at censurere ordrer, hvilket kan være nyttigt i tilfælde af ondsindede eller vildledende ordrer, men som også kan blive misbrugt og give dem mulighed for at frontløbe enhver anden bruger i tilfælde af en gunstig ordre ved ikke at vise den gennem API'en.
Privilegerede roller
Selvom de kontrakter, rollen bruges i, var uden for omfanget, blev der identificeret en privilegeret rolle. An immutableOwner
er sat til skaberen af en fuldmagtskontrakt på opførelsestidspunktet og bruges til at begrænse adgangen til fuldmagtens external
funktioner.
Eksterne afhængigheder og tillidsantagelser
Designet af denne protokol nødvendiggør komponenter uden for kæden og på kæden, og denne hybridmodel kan bruges til at afbøde nogle angrebsvektorer, vi identificerer i vores rapport, men omkostningerne ved denne evne er øget afhængighed af 1-tommer-teamet og infrastrukturen.
Derudover giver Limit Order Protocol funktioner, der er beregnet til at hente priser fra Chainlink-orakler. Vi antog, at disse orakler var ærlige, tilgængelige og korrekt fungerende.
På grund af en ordres fleksibilitet er der desuden flere kontaktpunkter med eksterne kontrakter, som ikke er valideret. Dette betyder, at en ondsindet bruger kan misbruge sådanne opkald og efterligne prædikater, aktiver eller orakler med ondsindede kontrakter for at udføre handlinger under ordreudfyldning. Selvom projektet er beskyttet i nogle områder mod genindtræden, kan sådanne vektorer forårsage lammelsesangreb eller uopdagede spam-ordrer. 1-tommer-teamet er klar over, at visse problemer kan opstå, når de bruger ukendte kontrakter til protokollen, og har tilkendegivet, at de har til hensigt, at kun større "blue chip"-aktiver vil blive fuldt understøttet af projektet. Det skal dog bemærkes, at selv med de mest populære aktiver er der iboende adfærd fra hvert aktiv, der kan forårsage problemer på protokoller, der ikke adresserer dem korrekt, såsom at have et gebyr under overførsler med USDT eller returnere en fejlkode i stedet for en succes boolean med cTokens.
Fund
Her præsenterer vi vores resultater.
Kritisk sværhedsgrad
Ingen.
Høj sværhedsgrad
[H01] Inkonsistente data videregivet til _makeCall
I OrderMixin
kontrakt, den _makeCall
funktion bruges til at overføre aktiver fra tageren til skaberen og så fra skaberen til aftageren. I sidstnævnte overførsel, den _makeCall
funktion er forkert bestået ordrens makerAsset
som sidste parameter, hvornår det skal være ordrens makerAssetData
.
Som et resultat kan enhver proxy-funktionalitet, der er afhængig af makerAssetData
argumentet vil bryde.
For at være i overensstemmelse med det tidligere opkald til _makeCall
og for fuldt ud at understøtte proxy-funktionalitet, overveje at opdatere order.makerAsset
parameter til order.makerAssetData
.
Update: Rettet ind træk anmodning # 57.
[H02] Delvist udfyldte private ordrer kan udfyldes af alle
Protokollen tillader oprettelse af private og offentlige ordrer. På private ordrer er det kun allowedSender
adresse, angivet af producenten under ordrens oprettelse, er i stand til at udfylde ordren.
Dog i OrderMixin
kontrakt, validering for allowedSender
adresse er forkert scoped, hvilket betyder, at den kun evalueres inde i logikken, der håndterer den første udfyldning af en ordre. Hvis en privat ordre er delvist udfyldt, så checken for allowedSender
Adressen er ikke længere tilgængelig, og ordren kan udfyldes af alle.
For at afklare hensigten omkring, hvorvidt en bruger skal være i stand til at udfylde delvist udfyldte private ordrer eller ej, overveje enten at dokumentere årsagen til den aktuelle adfærd eller validere allowedSender
adresse uden for omfanget af den første udfyldning for at sikre, at den vil blive valideret hver gang en udfyldning forsøges.
Update: Rettet ind træk anmodning # 58.
[H03] Ondsindet producent kunne drage fordel af delvise udfyldninger til at stjæle tagerens aktiver
Ordrer fra OrderMixin
kontrakt har mulighed for at blive delvist udfyldt. For at understøtte delvise fyldninger kræver protokollen en måde at beregne begge sider af swaps. Begge getMakerAmount
, getTakerAmount
felter defineres af ordregiveren til netop dette formål.
Ved udfyldelse af en ordre skal modtagere oplyse enten makingAmount
eller takingAmount
værdier samt en thresholdAmount
værdi. Der er to forskellige kodestier, der kan tages, baseret på om makingAmount
eller takingAmount
blev leveret.
Den første er, når makingAmount
parameter er defineret. Det kunne afkorte og makingAmount
værdi og også beregne takingAmount
værdi for det. I denne situation er thresholdAmount
sikrer, at takingAmount
værdi taget er ikke uventet stor.
Den anden er, når takingAmount
parameter er defineret. I så fald vil det beregne makingAmount
værdi, med mulighed for afkorte den , genberegning af takingAmount
værdi, hvis det sker. I denne situation er thresholdAmount
værdi sikrer, at makingAmount
værdi returneret er ikke uventet lille.
Der findes to udnyttelsesmetoder, som hver er unikke for en af de tidligere nævnte kodestier. Disse udnyttelsesmetoder kræver ondsindet getMakerAmount
, getTakerAmount
funktioner. En simpel implementering af disse funktioner ville have en identisk adfærd som AmountCalculator
's getMakerAmount
, getTakerAmount
funktioner, men med en hårdkodet switch, der vil tvinge dem til at returnere en hackerkontrolleret værdi, når det er nødvendigt.
Det første, mindre alvorlige udnyttelsesmønster involverer den første kodesti, hvor makingAmount
værdi er angivet i en udfyldningsrækkefølge. En ondsindet maker ville vente på en udfyldningsordre, der specificerer makingAmount
at dukke op i mempoolen for at frontløbe den. De ville dræne hele værdien undtagen 1 fra producentens side og derefter forcere _callGetTakerAmount
at returnere det beløb, der er angivet i brugerens thresholdAmount
værdi (eller deres godtgørelse, hvis den er mindre). Når brugerens transaktion endelig går igennem, vil de bytte deres fulde thresholdAmount
værd af takerAsset
for en enkelt enhed af makerAsset
. Denne udnyttelse er begrænset af mængden givet af thresholdAmount
værdi eller mængden af takerAsset
brugeren tilladt på LimitOrderProtocol
kontrakt.
Det andet, mere alvorlige udnyttelsesmønster involverer den anden kodesti, hvor takingAmount
værdi er angivet. Den ondsindede maker ville på samme måde vente på en udfyldningsordre, der specificerede en takingAmount
værdi for at blive vist i mempoolen. De ville frontløbe transaktionen og tvinge makingAmount
værdi returneret af _callGetMakerAmount
funktion at være højere end begge remainingMakerAmount
og thresholdAmount
. De ville også indstille takingAmount
returneret værdi pr _callGetTakerAmount
at være mængden af takerAsset
aktiv tilladt på LimitOrderProtocol
af aftageren. Når modtagerens transaktion går igennem, vil den afkorte makingAmount
værdi og derefter genberegne takingAmount
værdi. Denne genberegning er dog ikke garanteret lavere, og i dette tilfælde vil den dræne modtageren for alle takerAsset
som de tillod på kontrakten. I denne kodesti er thresholdAmount
Værdien er at sikre, at makingAmount
er ikke for lav, så tager alle takers takerAsset
aktiv er ukontrolleret. De tabte midler er begrænset af beløbet på takerAsset
aktiv brugeren tilladt på LimitOrderProtocol
kontrakt.
Disse udnyttelser er ikke mulige uden delvise ordrer og mere specifikt delvise ordrer med ondsindet getMakerAmount
, getTakerAmount
implementeringer.
Hovedspørgsmålet i thresholdAmount
værditjekket er, at det kun dækker den ene side af byttet, men den anden side kan manipuleres via frontrunning. Der er ingen garantier for, at den værdi, som modtageren oprindeligt foreslog, forbliver uændret. Overvej at fjerne makingAmount
trunkering fra både kodestier og tilbagevenden, hvis ordren ikke kan understøtte en så stor udfyldning som anmodet. Ved at gøre dette vil thresholdAmount
kan bruges til tilstrækkeligt at begrænse den anden side af byttet og undgå uventet adfærd, selv i ondsindede ordrer.
Update: Rettet ind træk anmodning # 83.
Medium sværhedsgrad
[M01] Statiske argumenter videregivet efter dynamiske argumenter
I OrderMixin
kontrakt, den getTakerAmount
, getMakerAmount
bytes felter bruges som argumenter for _callGetTakerAmount
, _callGetMakerAmount
funktioner. Disse opkald giver en måde at beregne den ene side af byttet baseret på den anden side, og de giver brugerne mulighed for delvist at udfylde ordrer.
getTakerAmount
/getMakerAmount
felter er dynamiske variabler og er pakket foran takerAmount
, makerAmount
værdier i _callGetTakerAmount
, _callGetMakerAmount
funktioner. Det er muligt for en ondsindet producent at levere flere data end forventet i getTakerAmount
,getMakerAmount
felter til at skubbe takerAmount
, makerAmount
bytes forbi, hvor de antages at være, når de afkodes i den næste funktion. Dette gør det muligt for producenten at flytte den indgivne taker eller maker-mængde med hele bytes til højre og endda erstatte dem fuldstændigt, hvis der leveres yderligere 32 bytes data.
Brugere skal allerede manuelt gennemgå getTakerAmount
, getMakerAmount
felter i rækkefølgen, men denne teknik er ret svær at få øje på. Også værd at bemærke, dette angreb gælder endda for internt betroede getMakerAmount
, getTakerAmount
funktioner. For de fleste angreb vil en rimelig tærskelværdi forhindre tab af midler.
For at forhindre dette skal du overveje at indkode de statiske argumenter før de dynamiske argumenter for at undgå at give de dynamiske argumenter en metode til at styre de statiske argumenter.
Update: Ikke fikset. 1 tommer holdet udtalte:
Vi vil være ekstra forsigtige med getters-validering. Vi vil forsøge at implementere fornuftsvalidering af getters i vores sdk, der vil hjælpe med at filtrere potentielt ondsindede ordrer.
[M02] ERC721-ordrer kan manipuleres
Det er muligt at bytte mere end blot ERC20'er via OrderMixin
ved at implementere en kontrakt, der deler den samme funktionsvælger som IERC20's transferFrom
, og leverer denne kontrakt som makerAsset
eller takerAsset
i en ordre.
Fuldmagterne uden for anvendelsesområdet, nemlig ERC721Proxy
, ERC721ProxySafe
og ERC1155Proxy
kontrakter følger dette mønster for at yde støtte til ERC721
, ERC1155
tokens. Da proxyerne skal kaldes med samme mønster som en IERC20 transferFrom
opkald, skal signaturen starte med address from
, address to
, uint256 amount
. Alt andet, som fuldmagterne kræver, kan sendes ind efter, og defineres i rækkefølgen som makerAssetData
, takerAssetData
.
ERC1155s kan naturligvis overføre flere af de samme id-tokens på én gang, hvilket betyder ERC1155Proxy
kontrakt gør brug af amount
Mark. På den anden side, ERC721
s ikke har en åbenlys brug for amount
Mark. Da de repræsenterer ikke-fungible tokens, vil et specifikt tokenId kun have et i eksistens, hvilket gør amount
felt ubrugelig. På grund af dette, implementeringen for begge ERC721Proxy
, ERC721ProxySafe
kontrakter anvender de nødvendige amount
felt som tokenId
i stedet.
Denne overbelastning af amount
parameter skaber mulighed for delvis påfyldning ERC721
ordrer for at købe særskilt anførte tokens til nedsatte priser. For eksempel kan der være et tilfælde, hvor en enkelt bruger har flere ERC721
s af samme kontrakt tilladt at blive overført af ERC721Proxy
kontrakt og anfører dem i separate grænserækkefølger.
Hvis grænseordrerne også giver getMakerAmount
, getTakerAmount
felter, vil det være muligt at delvist udfylde disse ERC721
Ordre:% s. Siden ordrens amount
felt svarer faktisk til tokenId
, kan en ondsindet bruger placere en delvis udfyldning på ERC721
med det højere tokenId, hvilket resulterer i en makingAmount
/takingAmount
af en ERC721
der kunne svare til en lavere tokenId
. Resultatet er ERC721
med den nederste tokenId
ville blive overført til prisen for (higher tokenId price) * (lower tokenId's id) / (higher tokenId's id)
.
Denne udnyttelse har et par krav:
- Multiple
ERC721
s fra den samme kontrakt skal tillades på entenERC721
fuldmagt af en enkelt ejer. - Åben ordre til en af de
ERC721
er det ikke det lavestetokenId
af de tilladte. - Delvis påfyldning tilladt på ordren.
For helt at fjerne muligheden for delvis ERC721
udfylder, overveje at adskille amount
, tokenId
argumenter. Uanset om argumenterne er adskilte eller ej, så overvej også at dokumentere dette for at advare brugerne om denne adfærd og for at undgå dette mønster i fremtiden.
Update: Rettet ind træk anmodning # 59.
[M03] Udokumenterede decimalantagelser
LimitOrderProtocol
kontrakt arver ChainlinkCalculator
kontrakt gennem OrderMixin
kontrakt. Denne kontrakt afslører to funktioner for at muliggøre brugen af Chainlink-orakler under prædikater check og opslag af producentbeløb/aftager beløb.
Kontrakten gør dog udokumenterede antagelser om antallet af decimaler, som Chainlink-oraklerne skal rapportere i, samt antallet af decimaler, som funktionsparametrene skal indeholde. I visse scenarier kan dette føre til uventet adfærd, herunder forkert prisfastsættelse af aktiver og utilsigtet tab af midler.
Mere specifikt, gennem hele kontrakten er den implicitte antagelse, at Chainlink-oraklerne vil rapportere med 18 decimalers præcision. Dog ikke alle Chainlink orakler rapport med dette antal decimaler. Faktisk, hvis oraklet rapporterer et token-par, der er i form af en valuta (for eksempel USD), vil det kun have 8 decimalers præcision. Da der ikke er begrænsninger vedr som orakler kan bruges, skal der ikke gøres implicitte antagelser om antallet af decimaler, de vil rapportere med.
I relation hertil er der en implicit antagelse om, at amount
parameter for ChainlinkCalculator
funktioner vil bruge 18 decimaler sammen med den vildledende eksplicitte erklæring om, at singlePrice
funktion Calculates price of token relative to ETH scaled by 1e18
. I virkeligheden, selv med et orakel, der gør rapport med 18 decimaler, returværdien af singlePrice
funktion vil blive skaleret med antallet af decimaler i amount
parameter, som ikke nødvendigvis er 18 decimaler.
På samme måde er doublePrice
funktion antager, at to Chainlink-orakler vil rapportere med det samme antal decimaler, hvilket får resultatet af funktionen til at afvige fra forventningerne.
Overvej eksplicit at dokumentere antagelser vedrørende antallet af decimaler, som parametre og returværdier skal være i forhold til. Overvej desuden enten at begrænse beregninger, der afhænger af orakler, der bryder disse antagelser, eller at de relevante beregninger tager det faktiske antal decimaler i betragtning.
Update: Rettet ind træk anmodning # 75.
Lav sværhedsgrad
[L01] Konstanter er ikke eksplicit angivet
Der er nogle få forekomster af bogstavelige værdier, der bruges med uforklarlig betydning i kodebasen. For eksempel:
- I
OrderMixin
kontrakt, den_remaining
kortlægning er semantisk overbelastet (som forklaret i udgaven Semantisk overbelastning af kortlægning) for at spore mængden af resterende aktiv for en delvist udfyldt ordre samt hvis en ordre er blevet fuldstændig udfyldt. Specifikt,0
betyder, at der ikke er foretaget udfyldninger forbundet med en ordre,1
betyder, at en ordre ikke længere kan udfyldes, og noget større end1
betyder, at der er et resterende beløb tilknyttet ordren, som potentielt kan udfyldes. - I
ChainlinkCalculator
kontrakt, den bogstavelige værdi1e18
bruges isinglePrice
funktion.
For at forbedre kodens læsbarhed og lette refactoring kan du overveje at definere en konstant for hvert magisk tal og give det et klart og selvforklarende navn. For komplekse værdier kan du overveje at tilføje en indlejret kommentar, der forklarer, hvordan de blev beregnet, eller hvorfor de blev valgt.
Update: Rettet ind træk anmodning # 75 , træk anmodning # 76.
[L02] Ondsindede parter kan forhindre udførelsen af tilladte ordrer
OrderMixin
kontrakt giver brugere mulighed for at indsende tilladte ordrer så de kan udføres i én transaktion i stedet for at skulle have en separat transaktion for godkendelser. Også ordremodtagere kan indsende deres egen tilladelse under udfyldelsen af ordren til samme formål.
Men fordi producentens tilladelse er indeholdt i ordrer, ville både producentens og modtagerens tilladelser være tilgængelige, mens ordreudfyldningstransaktionen er i mempoolen. Dette ville gøre det muligt for enhver ondsindet bruger at tage disse tilladelser og udføre dem på de respektive aktivkontrakter, mens udfyldningstransaktionen køres i forvejen. Fordi disse tilladelser har en nonce
for at forhindre et dobbeltforbrugsangreb, ville ordrens udfyldningstransaktion mislykkes som et resultat af forsøg på at bruge den samme tilladelse, som lige blev brugt under frontrun.
Selvom der ikke er nogen sikkerhedsrisiko, og producenten kunne oprette en ny ordre og forhåndsgodkende transaktionen, kan dette angreb bestemt påvirke anvendeligheden af tilladte ordrer. Faktisk kunne en motiveret angriber blokere alle tilladte ordrer med dette angreb. Overvej at validere, om tilladelsen allerede var indsendt, eller om godtgørelsen er nok, under ordreudfyldningen. Overvej også at fortælle brugerne om dette mulige angreb under ordresammensætning.
Update: Ikke fikset. 1 tommer holdet udtaler:
Vi havde godkendelsestjek før, men besluttede at forenkle tilladelsesflowet for blot at vende tilbage til mislykkede godkendelser. Vi vil overveje måder at underrette producenter om problemet.
[L03] Duplikeret kode
Der er forekomster af duplikeret kode i kodebasen. Duplikering af kode kan føre til problemer senere i udviklingens livscyklus og efterlader projektet mere udsat for introduktion af fejl. Sådanne fejl kan utilsigtet introduceres, når funktionalitetsændringer ikke replikeres på tværs af alle forekomster af kode, der burde være identiske. Eksempler på duplikeret kode omfatter:
I stedet for at duplikere kode kan du overveje kun at have én kontrakt eller et bibliotek, der indeholder den duplikerede kode og bruge den, når den duplikerede funktionalitet er påkrævet.
Update: Delvist fastgjort træk anmodning # 60.
[L04] Forkert eller vildledende testpakke
Der er tilfælde i testpakken, hvor testene afviger fra deres forventede adfærd. For eksempel:
-
ChainlinkCalculator
kontrakten er arvet afOrderMixin
kontrakt. Men under testeneAmountCalculator.arbitraryStaticCall
funktionen bruges til at kaldeChainlinkCalculator
kontrakt som en ekstern, selvstændig kontrakt. Selvom resultatet er det forventede, bør testen afspejle adfærden med systemets nuværende design og forventede brugssag ved at kaldeChainlinkCalculator
fungerer direkte uden at bruge det vilkårlige statiske opkald. - Selvom fuldmagtskontrakterne var uden for rækkevidde, bemærkede vi, at da vi testede protokollen med ERC721-aktiver,
ERC721Proxy
kontrakt bruges ikke til at bytte aktiverne i sin testsuite.
Da selve testpakken er uden for denne revisions omfang, bedes du overveje at gennemgå testpakken grundigt for at sikre, at alle test kører med succes i henhold til protokollens specifikationer.
Update: Rettet ind træk anmodning # 57, træk anmodning # 59og træk anmodning # 61.
[L05] Fejl og udeladelser i begivenheder
I hele kodebasen udsendes hændelser generelt, når der foretages følsomme ændringer i kontrakterne. Mange begivenheder mangler dog indekserede parametre og/eller mangler vigtige parametre. For eksempel:
Der er også følsomme handlinger, der mangler begivenheder, såsom:
Overvej mere fuldstændigt at indeksere eksisterende begivenheder og tilføje nye parametre, hvor de mangler. Overvej også at udsende alle hændelser på en sådan fuldstændig måde, at de kan bruges til at genopbygge kontraktens tilstand af tjenester uden for kæden.
Update: Ikke fikset. 1 tommer-holdet tilføjede dog en orderRemaining
parameter til OrderCanceled
begivenhed i træk anmodning # 62.
1 tommer holdet udtaler:
Vi fandt ud af, at der kun kræves en begrænset delmængde af data for at tilfredsstille frontend-behov. I tilfælde af omfattende analyser er alle de foreslåede felter tilgængelige via sporing. Til
OrderRFQMixin
vi forventer, at market makers bygger deres egen sofistikerede måde at spore, hvilke ordrer der er blevet annulleret.
[L06] Lagerændringer under hændelsemission
I NonceManager
kontrakt, når NonceIncreased
hændelse udsendes, afsenderens nonce øges også.
Udførelse af flere operationer samtidigt kan gøre kodebasen sværere at ræsonnere omkring, mere tilbøjelig til fejl og kan føre til, at operationer bliver overset eller misforstået.
For at forbedre kodens overordnede intentionalitet, læsbarhed og klarhed skal du overveje at øge nonce-værdien, før du udsender hændelsen.
Update: Rettet ind træk anmodning # 63.
[L07] Inkonsekvente afkodningsmetoder kan forårsage uoverensstemmelser i resultatet
For at understøtte al dens udvidelsesmuligheder og fleksibilitet skal Limit Order Protocol rutinemæssigt håndtere dynamiske bytesdata og vilkårlige returværdier fra eksterne kontrakter. Som følge heraf indeholder protokollen en ArgumentsDecoder
bibliotek for mere effektivt at konvertere dynamiske bytes-værdier til grundlæggende datatyper. Dette bibliotek bruges dog ikke udelukkende, og i nogle tilfælde abi.decode
bruges i stedet. Derudover bruger nogle kontrakter abi coder v1
mens andre bruger abi coder v2
. Førstnævnte optræder mere på samme måde som ArgumentsDecoder
bibliotek, hvorimod sidstnævnte udfører yderligere kontrol ved afkodning.
Den inkonsekvente brug af disse forskellige afkodningsmetoder kan resultere i subtile uoverensstemmelser mellem kodebasens intention og faktiske adfærd.
For eksempel er den simulateCalls
funktionen bruger kun ArgumentsDecoder.decodeBool
fungere. Hvis simulateCalls
funktionen bruges til at kontrollere kald, der ville blive foretaget i prædikatdelen af en ordre, så kan dens resultater afvige fra, hvad der faktisk opstår, når prædikatbetingelserne evalueres, fordi der anvendes forskellige afkodningsmetoder.
Så for eksempel hvis et prædikat laver et eksternt staticcall
til en funktion, der returnerer en uint256
værdi større end én i stedet for den forventede bool
, så vender det opkald tilbage, fordi returværdien er afkodet med abi coder v2
's abi.decode
som ikke vil acceptere sådanne værdier som bool
. Men hvis nøjagtig samme opkald foretages med simulateCalls
, så det vil blot blive markeret som true
, Fordi decodeBool
behandler enhver værdi større end nul som true
.
At gøre simulateCalls
funktion afspejler fuldt ud adfærden af faktiske prædikatkald, overvej at ændre den til brug abi.decode
.
Update: Rettet ind træk anmodning # 82.
[L08] Manglende inputvalidering
fillOrderToWithPermit
, fillOrderTo
funktioner i OrderMixin
kontrakt, samt fillOrderRFQToWithPermit
, fillOrderRFQTo
funktioner i OrderRFQMixin
kontrakt, valider ikke target
adresse parameter.
Dette gør det muligt for en bruger utilsigtet at indtaste nuladressen og som følge heraf låse de aktiver, de er beregnet til at modtage, efter at have udfyldt en ordre.
For at sikre, at brugere ikke ved et uheld låser deres penge op, skal du overveje at validere, at target
adresse er ikke lig med nuladressen i de nævnte funktioner.
Update: Rettet ind træk anmodning # 78.
[L09] Lav enhedstestdækning
Enhedstestdækningen for hele projektet er omkring 75 %, hvor nogle af kontrakterne har særlig lav dækning.
I betragtning af vigtigheden af enhedstests for at validere kode og forhindre regression ved refaktorering og udvikling af nye funktioner, opfordrer vi til at øge enhedstestdækningen markant til mindst 95 %, og inkludere edge cases, der dækker selv usandsynlige situationer.
Update: Ikke fikset.
[L10] Vildledende eller ufuldstændig inline-dokumentation
Igennem kodebasen blev nogle få tilfælde af vildledende og/eller ufuldstændig inline-dokumentation identificeret og bør rettes.
Følgende er tilfælde af vildledende indlejret dokumentation:
- I
ChainlinkCalculator
kontrakt, densinglePrice
funktion NatSpec@notice
tag siger, at detCalculates price of token relative to ETH scaled by 1e18
, men faktisk er resultatet det værdi ofamount
tokens skaleret efter1e18
, hvor oraklet muligvis ikke rapporterer i form af ETH (for et par, der ikke inkluderer ETH, for eksempel). - I
OrderRFQMixin
kontrakt, deninvalidatorForOrderRFQ
funktion NatSpec@return
tag er vildledende, fordi tilbuddet muligvis ikke er blevet udfyldt for at den respektive invalidator-bit er blevet indstillet. Ordren kan også være blevet annulleret. - På linjer 147, 165og 188 of
OrderMixin.sol
, NatSpec@param
tags er ugrammatiske. - On line 20 of
ERC1155Proxy.sol
,@notice
tag angiver, at den beregnede hash er resultatet af hash affunc_733NCGU
funktion, hvor den skal værefunc_301JL5R
funktion i stedet.
Følgende er tilfælde af ufuldstændig inline-dokumentation:
- Funktioner i
AmountCalculator
kontrakten beskriver ikke nogen af parametrene. - I
ChainlinkCalculator
kontrakt, densinglePrice
,doublePrice
funktioner beskriver ikke alle parametrene. - I
ImmutableOwner
kontrakt, den offentlige variabel og modifikator har ingen NatSpec. - I
InteractiveNotificationReceiver
kontrakt, dennotifyFillOrder
funktion beskriver ikke nogen af parametrene. - I
LimitOrderProtocol
kontrakt, denDOMAIN_SEPARATOR
funktion har ingen NatSpec. - Begivenheder og kortlægninger i
NonceManager
har ingen NatSpec. - I
OrderRFQMixin
kontrakt,cancelOrderRFQ*
funktioner beskriver ikke returværdierne. - I
OrderMixin
kontrakt, flere funktioner mangler komplet NatSpec. - On line 168 of
OrderMixin.sol
og på nettet 71 ofOrderRFQMixin.sol
, mangler den@dev
tag. - Funktioner i
PredicateHelper
kontrakten beskriver ikke alle parametrene.
Tydelig inline-dokumentation er grundlæggende for at skitsere kodens intentioner. Uoverensstemmelser mellem den inline-dokumentation og implementeringen kan føre til alvorlige misforståelser om, hvordan systemet forventes at opføre sig. Overvej at rette disse fejl for at undgå forvirring for både udviklere, brugere og revisorer.
Update: Delvist fast. Vildledende dokumentation behandlet i træk anmodning # 75 , træk anmodning # 77.
1 tommer holdet udtaler:
Vi har rettet vildledende dokumenter. Færdiggørelse af dokumenterne vil ske senere.
[L11] DoS-ordrer muligt ved brug af kroge
OrderMixin
kontrakt implementerer funktionalitet til at udfylde generiske off-chain swapordrer, som kan have betingelser for deres succes. Under ordreudfyldning kan ordren kontrollere de foruddefinerede "prædikat"-betingelser før du fortsætter med udførelsen.
Men fordi disse prædikatbetingelser kunne målrette mod logikken i enhver vilkårlig kontrakt, kunne en ondsindet producent narre modtagere til at tro, at en ordre opfører sig korrekt, og at den er gyldig, når den tjekker den uden for kæden, men så mislykkes, når de forsøger at udfylde den samme ordre. på kæden. Denne ændring i prædikatadfærden kunne enten foretages ved at frontløbe en variabel tilstand, som prædikaterne afhænger af, ved at undersøge den sendte gas eller endda hvilke adresser der er involveret i opkaldet, eller ved en anden logik.
Desuden, hvis producenten definerede en interaktion under byttet, interactionTarget
kontrakt kunne vende tilbage eller tilbagekalde godtgørelsen for at forhindre en vellykket ordreudfyldning, hvilket i det væsentlige fører til det samme resultat som ondsindede prædikater.
Selvom aktiver ikke vil være i fare, vil brugere eller bots, der finder en favorabel ordre, have den øgede byrde at forsøge at identificere den slags spam-ordrer, der kan virke legitime på overfladen. I tilfælde af, at de ikke kan identificere den slags ordrer, vil de pådrage sig spildte gasomkostninger. For at reducere mængden af spam-ordrer bør du overveje at begrænse de tilgængelige mål for disse hooks. Overvej også at advare brugere om denne mulighed, før de forsøger at udfylde ordrer.
Update: Ikke fikset. 1 tommer holdet udtaler:
Vi håndterer det på vores backend, og vi vil overveje måder at underrette mulige modtagere om problemet.
[L12] Afrunding kan være ugunstig for taker
I OrderMixin
, OrderRFQMixin
kontrakter, når en ordre udfyldes, og modtageren kun giver en makingAmount
or takingAmount
beløb, forsøger protokollen at beregne modpartsbeløbet for byttet.
Der er to problemer med disse beregninger, den første er, at der ikke er nogen dokumentation eller logik, der begrænser antallet af decimaler, som mængdeparametrene skal bruge, hvilket vi behandlede i Udokumenterede decimalantagelser problem.
Det andet spørgsmål er, at protokollen i løbet af disse beregninger runder til producentens favør. Afrundingsproblemet kan blive meget forværret, når de implicitte decimalantagelser brydes, men selv når alt er i de forventede vilkår, vil afrunding forekomme med små, ulige beløb.
Overvej at give brugeren mulighed for at angive et minimumsbeløb makerAsset
aktiv, som de er villige til at modtage sammen med et maksimalt beløb på takerAsset
aktiv, de er villige til at bytte, så accepten af enhver afrunding er mere eksplicit.
Update: Ikke fikset. 1 tommer holdet udtaler:
Tærskelbeløbet bør være nok til takers beskyttelse.
[L13] Modstridende ordrehåndtering ved manglende parametre
I OrderMixin
kontrakt, den fillOrderTo
funktionen foretager interne opkald til _callGetMakerAmount
, _callGetTakerAmount
fungerer, hver gang en udfyldning forsøges, og enten makingAmount
eller takingAmount
parametre er henholdsvis nul, eller hvis makingAmount
værdien er større end remainingMakerAmount
værdi.
_callGetMakerAmount
, _callGetTakerAmount
opkald vil føre til tilbageførsler, hvis ordren ikke blev oprettet med getMakerAmount
or getTakerAmount
parametre, og en delvis udfyldning udføres.
An inline kommentar ved siden af _callGetMakerAmount
og en inline kommentar ved siden af _callGetTakerAmount
hævde, at "kun hele udfyldninger er tilladt", hvis ordren ikke blev oprettet med getMakerAmount
or getTakerAmount
parametre.
Der er dog kodestier, som dette ikke gælder for, fordi disse stier ikke tjekker length
s af begge getMakerAmount
, getTakerAmount
parametre.
specifikt når en taker
angiver en takerAmount
værdi for en ordre, som kun har en getMakerAmount
, medmindre det kalder til getMakerAmount
returnerer et beløb større end remainingMakerAmount
, kan en delvis udfyldning udføres i modstrid med den inline-dokumentation.
Dette efterlader intentionaliteten af disse kodestier uklar. Hvis dette er den forventede adfærd, kan du overveje at ændre den inline-dokumentation, så den er mere eksplicit. Hvis dette er utilsigtet adfærd, så overvej altid at tjekke længden af begge getMakerAmount
og getTakerAmount
parametre samtidigt, så implementeringen forstærker adfærden beskrevet af inline-dokumentationen.
Update: Rettet ind træk anmodning # 79.
[L14] Brug af forældede Chainlink-opkald
ChainlinkCalculator
kontrakten er beregnet til at blive brugt til at forespørge på Chainlink-orakler. Det gør det ved at foretage opkald til deres latestTimestamp
, latestAnswer
metoder, som begge er blevet forældet. Faktisk er metoderne ikke længere til stede i API af Chainlink-aggregatorer fra version tre.
For at undgå potentiel fremtidig inkompatibilitet med Chainlink-orakler skal du overveje at bruge latestRoundData
metode i stedet for.
Update: Rettet ind træk anmodning # 67.
Bemærkninger og yderligere oplysninger
[N01] Importerer ikke grænseflader
AggregatorInterface
grænsefladen ser ud til at være en delmængde af kode kopieret fra ChainLink
's offentlige kodelager. Den fulde grænseflade er inkluderet i ChainLink
's kontrakt npm-pakke.
Når det er muligt, kan du overveje at bruge grænseflader installeret via deres officielle npm-pakker i stedet for at omdefinere og/eller omskrive et andet projekts grænseflader for at mindske potentialet for grænsefladeuoverensstemmelser og resulterende problemer.
Update: Rettet ind træk anmodning # 66.
[N02] Forældede projektafhængigheder
Under installationen af projektets afhængigheder, advarer NPM om, at en af de installerede pakker, Highlight
, "vil ikke længere blive understøttet eller modtage sikkerhedsopdateringer i fremtiden".
Selvom det er usandsynligt, at denne pakke kan forårsage en sikkerhedsrisiko, kan du overveje at opgradere den afhængighed, der bruger denne pakke, til en vedligeholdt version.
Update: Rettet ind træk anmodning # 64.
[N03] Eksterne opkald til visningsmetoder er ikke statiske opkald
I det meste af kodebasen foretager protokollen eksplicit eksterne opkald via OpenZeppelin's functionStaticCall
metode til at begrænse muligheden for statsændringer, når de enten ikke forventes eller ikke er ønskelige. Men i ChainlinkCalculator
kontrakt, på trods af intentionen om kun at foretage eksterne opkald til view
metoder på Chainlink orakler, de eksterne opkald i singlePrice
, doublePrice
funktioner er ikke lavet via eksplicit staticcall
s.
Selvom vi ikke identificerede nogen umiddelbare sikkerhedsproblemer, der stammer fra dette, bør du overveje at bruge eksplicit for at reducere angrebsoverfladen, forbedre konsistensen og præcisere hensigten staticcall
s, for alle eksterne opkald til view
funktioner i ChainlinkCalculator
kontrakt.
Update: Ikke fikset. 1 tommer holdet udtaler:
Vi mener, at syntakskomplikation ophæver forbedringer i konsistensen.
[N04] Fejler ikke tidligt med ugyldige ordrer
I OrderMixin
kontrakt, den fillOrderTo
funktion håndterer den særlige tilstand, når en ordre ikke tidligere er afgivet (remainingMakerAmount == 0
), men den håndterer ikke eksplicit betingelsen, når ordren ikke længere er gyldig (remainingMakerAmount == 1
).
I sidstnævnte scenarie vil funktionen til sidst vende tilbage, men kun efter afbrænding af ikke-trivielle mængder gas. For at tydeliggøre hensigten, øge læsbarheden og reducere gasforbruget, overveje eksplicit at håndtere scenariet med ugyldig ordre mod begyndelsen af funktionen.
Update: Rettet ind træk anmodning # 68.
[N05] Hjælperkontrakter er ikke markeret som abstrakte
I Soliditet er nøgleordet abstract
bruges til kontrakter, der enten ikke er funktionelle kontrakter i sig selv, eller ikke er beregnet til at blive brugt som sådan. I stedet, abstract
kontrakter nedarves af andre kontrakter i systemet for at skabe selvstændige funktionskontrakter.
Igennem kodebasen er der eksempler på hjælperkontrakter, der ikke er markeret som abstrakte, på trods af at de ikke er beregnet til at blive implementeret alene. For eksempel AmountCalculator
, ChainlinkCalculator
, ImmutableOwner
, NonceManager
og PredicateHelper
kontrakter er alle sammensat af et basissæt af funktioner, som er beregnet til at blive brugt af nedarvede kontrakter.
Overvej at markere hjælperkontrakter som abstract
at tydeligt angive, at de udelukkende er designet til at tilføje funktionalitet til kontrakter, der arver dem.
Update: Ikke fikset. 1 tommer holdet udtaler:
Disse hjælpere kan indsættes separat. De arves kun for gasbesparelser.
[N06] Inkonsekvent funktionsbestilling
Gennem hele kodebasen følger funktionsrækkefølgen generelt anbefalet rækkefølge i Solidity Style Guide, som er: constructor
, fallback
, external
, public
, internal
, private
.
Men i den OrderMixin
kontrakt, den public
checkPredicate
funktion afviger fra stilguiden og halverer external
funktioner.
For at forbedre projektets overordnede læsbarhed kan du overveje at standardisere funktionsrækkefølgen i hele kodebasen, som anbefalet af Solidity Style Guide.
Update: Rettet ind træk anmodning # 69.
[N07] Inkonsekvent ordreudfyldningsflow
OrderMixin
, RFQOrderMixin
kontrakter håndterer begge udfyldelse af underskrevne ordrer, men det generelle ordreflow mellem de to kontrakter er inkonsekvent.
OrderMixin
's fillOrderTo
funktion følger dette generelle flow (pseudo-kode):
if ((takingAmount == 0) == (makingAmount == 0))
else if (takingAmount == 0)
else (handle makingAmount == 0) THEN swapTokens
ud fra følgende betragtninger RFQOrderMixin
er analogt fillOrderRFQTo
funktion følger dette flow (pseudo-kode):
if (takingAmount == 0 && makingAmount == 0)
else if (takingAmount == 0)
else if (makingAmount == 0)
else revert THEN swapTokens
Der er ingen indsigt fra dokumentationen om, hvorfor den første betingelse i hver af disse to funktioner adskiller sig, eller hvorfor takingAmount
, makingAmount
kan ikke begge være nul i sidstnævnte funktion. Også det tilfælde, hvor både en makingAmount
og en takingAmount
er forudsat, er meget lettere at ræsonnere om i fillOrderRFQTo
funktion, da det håndteres tydeligt i finalen else
blok.
For at tydeliggøre hensigten og øge kodens overordnede læsbarhed kan du overveje enten at standardisere det generelle ordreflow på tværs af disse to kontrakter eller eksplicit at dokumentere, hvorfor forskellene eksisterer.
Update: Ikke fikset. 1 tommer holdet udtaler:
Dette skyldes brugerdefinerede prissætningsfunktioner i begrænsede ordrer. Siden
getMakerAmount
potentielt kan afvige væsentligt fragetTakerAmount
, vi troede, at det er bedre ikke at lave standardindstilling for brugeren, da det sandsynligvis vil forvirre dem i tilfælde, hvor disse gettere vil være anderledes.
[N08] Fejlmeddelelser er inkonsekvent formateret eller vildledende
Gennem hele kodebasen er require
, revert
fejlmeddelelser, som er beregnet til at underrette brugere om de særlige forhold, der forårsager en transaktion mislykkedes, viste sig at være inkonsekvent formateret.
For eksempel hver enkelt af fejlmeddelelserne på linjer 85 af OrderMixin.sol
, 16 af ERC721ProxySafe.sol
og 26 af Permitable.sol
bruge en anden stil.
Derudover er nogle fejlmeddelelser vildledende:
Fejlmeddelelser er beregnet til at underrette brugere om svigtende forhold, så de bør give tilstrækkelig information til, at der kan foretages passende rettelser for at interagere med systemet. Uinformative fejlmeddelelser skader i høj grad den overordnede brugeroplevelse og sænker dermed systemets kvalitet. Desuden kan inkonsekvent formaterede fejlmeddelelser skabe unødvendig forvirring. Overvej derfor at gennemgå hele kodebasen for at sikre, at hver require
, revert
sætningen har en fejlmeddelelse, der er konsekvent formateret, nøjagtig, informativ og brugervenlig.
Update: Delvist fastgjort træk anmodning # 81.
[N09] Inkonsekvent brug af navngivne returvariabler
Der er en inkonsekvent brug af navngivne returvariabler i OrderMixin
kontrakt. Nogle funktioner returnere navngivne variable, andre returnere eksplicitte værdier, og andre erklære en navngivet returvariabel, men tilsidesætte den med en eksplicit returopgørelse.
Overvej at anvende en ensartet tilgang til returneringsværdier i hele kodebasen ved at fjerne alle navngivne returvariabler, eksplicit erklære dem som lokale variabler og tilføje de nødvendige retursætninger, hvor det er relevant. Dette ville forbedre både eksplicititeten og læsbarheden af koden, og det kan også hjælpe med at reducere regressioner under fremtidige koderefaktorer.
Update: Rettet ind træk anmodning # 73.
[N10] Ordrens hash-beregning er ikke åben for API'en
external
funktioner remaining
, remainingRaw
, remainingsRaw
alle forventer en ordrehash for vellykket drift.
Dog hjælperfunktionen _hash
, som returnerer hashen af en ordre, har private
sigtbarhed. Det betyder, at brugere bliver nødt til at pakke dele af ordrerne og domænestrengene manuelt for at få hash af en ordre.
For at undgå risikoen for fejl ved beregning af ordrehash og for at give brugerne en metode til at generere en ordres respektive hash, bør du overveje at udvide synligheden af _hash
funktion til public
og refaktorerer navnet til hash
for at være i overensstemmelse med resten af koden.
Update: Rettet ind træk anmodning # 74.
[N11] Semantisk overbelastning af kortlægning
_remaining
kortlægning i OrderMixin
kontrakten er semantisk overbelastet for at spore status for ordrer og den resterende mængde af aktiver, der er tilgængelige for disse ordrer.
De tre stater, den kan tage på, er:
0
: Ordrehashen er ikke set endnu.1
: Ordren er enten blevet annulleret eller helt udfyldt.- Enhver
uint
større end1
: Det resterendemakerAmount
tilgængelig til at blive udfyldt på ordren plus1
.
Denne semantiske overbelastning kræver indpakning og udpakning af denne værdi under lookup
, cancellation
, initialization
og storage
.
Semantisk overbelastning og den nødvendige logik til at aktivere den kan være tilbøjelig til at fejle og kan gøre kodebasen sværere at forstå og ræsonnere omkring, det kan også åbne døren for regressioner i fremtidige opdateringer af koden.
For at forbedre kodens læsbarhed kan du overveje at spore ordrers færdiggørelsestilstand i en separat kortlægning.
Update: Ikke fikset. 1 tommer-teamet citerede, at en løsning ville øge gasomkostningerne for fillOrder
funktion.
[N12] Ordrer med tilladelse tillader opkald til vilkårlige kontrakter
OrderMixin
kontrakt arver Permitable
kontrakt for at tillade udfyldning af ordrer på én enkelt transaktion med aktiver, der accepterer sådanne permit
opfordrer til at ændre kvoter.
Imidlertid opkald til Permitable
kontrakt valider ikke, om målet er et tilladt aktiv, eller om det overhovedet er et aktiv, som kunne tillade en ondsindet bruger at videregive adressen på en vilkårlig kontrakt, som kunne udføre et andet opkald, før ordreudfyldningen er fuldført.
Selvom kontrakten er beskyttet mod genindtrængen, reduktion af angrebsfladen og forebyggelse af indkaldelse af eksterne kontrakter under udførelsen anbefales altid. Overvej enten at begrænse det aktiv, der er involveret i tilladelsen, til de aktiver, der er involveret i ordren, eller til en hvidliste over aktiver for protokollen.
Update: Ikke fikset. 1 tommer holdet udtaler:
OrderMixin
har faktisk ikke info om faktiske tokens sommakerAsset
,takerAsset
nogle gange er proxyer eller andre mellemliggende kontrakter, og information om faktiske tokens er gemt i nogle vilkårlige bytes. Så der er ingen brugbar måde at begrænse hvilket aktiv påpermit
kaldes på.
[N13] solhint
er aldrig genaktiveret
Igennem kodebasen er der et par solhint-disable
erklæringer, især dem på nettet 23 og på nettet 41 of RevertReasonParser.sol
, der ikke afsluttes med solhint-enable
.
Til fordel for eksplicithed og for at være så restriktiv som muligt ved deaktivering solhint
, overvej at bruge solhint-disable-line
or solhint-disable-next-line
i stedet ligner linje 16 af samme fil.
Update: Rettet ind træk anmodning # 72.
[N14] Tastefejl
Kodebasen indeholder følgende tastefejl:
Derudover projektets README
(uden for denne revisions omfang) indeholder følgende tastefejl:
Overvej at rette disse tastefejl for at forbedre kodelæsbarheden.
Update: Rettet ind træk anmodning # 71 , træk anmodning # 77.
[N15] Brug af uint
i stedet for uint256
For at favorisere eksplicithed, alle tilfælde af uint
skal erklæres som uint256
. Især dem i for
sløjfer på linjer 98 , 119 of OrderMixin.sol
og linjer 16 , 30 of PredicateHelper.sol
.
Update: Rettet ind træk anmodning # 70.
konklusioner
Der blev fundet 3 alvorlige problemer. Nogle ændringer blev foreslået for at følge bedste praksis og reducere den potentielle angrebsoverflade.
- &
- 7
- Om
- adgang
- Ifølge
- Konto
- tværs
- Lov
- aktioner
- Yderligere
- adresse
- Fordel
- Alle
- tillade
- allerede
- Skønt
- beløb
- analyse
- api
- tilgang
- argumenter
- omkring
- aktiv
- Aktiver
- revision
- Back-end
- Begyndelse
- være
- BEDSTE
- bedste praksis
- Bit
- bots
- bygge
- ringe
- hvilken
- tilfælde
- Årsag
- chainlink
- lave om
- kontrol
- Kontrol
- kode
- komplekse
- betingelse
- forvirring
- opbygge
- indeholder
- kontrakt
- kontrakter
- Rettelser
- Omkostninger
- kunne
- Par
- skaberen
- Valuta
- Nuværende
- data
- deal
- Denial of Service
- implementering
- Design
- udviklere
- Udvikling
- DID
- afvige
- forskellige
- domæne
- fordoble
- dynamisk
- Tidligt
- Edge
- tilskynde
- især
- ETH
- begivenhed
- begivenheder
- at alt
- eksempel
- udveksling
- forventet
- erfaring
- Exploit
- Funktionalitet
- Fields
- Endelig
- Fornavn
- Fix
- Fleksibilitet
- flow
- følger
- fundet
- fuld
- funktion
- fonde
- fremtiden
- spil
- GAS
- Generelt
- Give
- stor
- vejlede
- Håndtering
- hash
- hashing
- have
- hjælpe
- Høj
- stærkt
- Hvordan
- HTTPS
- Hybrid
- identificere
- KIMOs Succeshistorier
- gennemføre
- vigtigt
- importere
- medtaget
- Herunder
- Forøg
- øget
- info
- oplysninger
- Infrastruktur
- indsigt
- hensigt
- interesse
- grænseflade
- involverede
- spørgsmål
- IT
- stor
- større
- føre
- førende
- Bibliotek
- Limited
- Line (linje)
- Likviditet
- Børsnoterede
- Lister
- lokale
- kiggede
- kig op
- større
- maker
- Making
- Marked
- Mempool
- spejl
- model
- mest
- Mest Populære
- nemlig
- Nye funktioner
- ikke-ombyttelige
- ikke-svampbare symboler
- officiel
- åbent
- Produktion
- Option
- oracle
- ordrer
- ordrer
- Andet
- ejer
- Mønster
- Populær
- præsentere
- forebyggelse
- pris
- prissætning
- private
- behandle
- projekt
- projekter
- beskyttelse
- protokol
- give
- giver
- proxy
- offentlige
- offentliggøre
- køb
- kvalitet
- rejse
- Reality
- reducere
- afhængighed
- indberette
- Rapporter
- Repository
- Krav
- REST
- Resultater
- afkast
- gennemgå
- Risiko
- runder
- Kør
- SDK
- sikkerhed
- Tjenester
- sæt
- delt
- Aktier
- skifte
- lignende
- Simpelt
- lille
- Smart
- Smarte kontrakter
- So
- soliditet
- spam
- specifikt
- udgifterne
- Spot
- starte
- Tilstand
- Statement
- Stater
- Status
- opbevaring
- stil
- indsendt
- succes
- vellykket
- Succesfuld
- support
- Understøttet
- overflade
- Kontakt
- systemet
- mål
- prøve
- Test
- tests
- Gennem
- hele
- tid
- sammen
- token
- Tokens
- spor
- Sporing
- transaktion
- Stol
- enestående
- opdateringer
- us
- usability
- USD
- USDT
- brugere
- nytte
- værdi
- Specifikation
- synlighed
- vente
- Hvad
- whitelist
- inden for
- uden
- Arbejde
- værd
- nul