Članci
Kontrolna lista spremnosti pametnih ugovora za audit
30 provera pre audita pametnih ugovora: obim i dokumentacija, testovi, Foundry fuzz i invarijante, Slither trijaža, kontrola pristupa i postavljanje.
Inženjerski tim sigmacode.io8 min čitanja
Na ovoj stranici (9)
Audit pametnih ugovora je skup i strogo vremenski ograničen. Auditori imaju fiksan broj dana, a svaki sat koji potroše na otkrivanje šta bi kod trebalo da radi, praćenje commita koji se stalno menja ili pisanje testova koje niste napisali je sat koji ne provode na logici zbog koje se sredstva zaista mogu izgubiti. Izveštaj se tada puni nedostajućim NatSpec komentarima, plutajućim pragmama i netestiranim revert putanjama umesto problemima za čije ste pronalaženje platili.
Dobro pripremljena kodna baza za isti budžet dobija dublji audit. Ova kontrolna lista sažima ono što pripremamo pre predaje koda spoljnim auditorima: 30 konkretnih provera koje pokrivaju dokumentaciju, higijenu koda, testiranje, kontrolu pristupa, integracije, postavljanje i organizaciju. Ne zamenjuje audit, već obezbeđuje da vreme audita ode tamo gde je važno.
1. Obim i dokumentacija#
Auditori mogu da provere ponašanje samo u odnosu na nameru koju razumeju, pa ta namera mora biti zapisana.
- Zamrznite commit hash. Predajte auditorima jedan označeni commit i ne menjajte kod koji se pregleda tokom audita. Ispravke nastaju na zasebnoj grani i pregledaju se u rundi provere ispravki.
- Objavite spisak datoteka u obimu sa nSLOC-om. Navedite svaki ugovor u obimu sa putanjom i brojem normalizovanih linija koda i izričito navedite šta nije u obimu (biblioteke, mockovi, skripte, već auditovane datoteke). Auditori procenjuju i planiraju na osnovu nSLOC-a, pa tačan broj sprečava iznenađenja na obe strane.
- Napišite pregled arhitekture. Jedna do dve strane koje opisuju ugovore, kako se međusobno pozivaju, koji ugovori drže sredstva i glavne korisničke tokove. Jednostavan dijagram poziva i tokova tokena auditorima štedi sate reverse engineeringa.
- Specificirajte ponašanje i invarijante prozom. Opišite šta svaka spoljna funkcija mora da radi i koja svojstva uvek moraju da važe, npr. „zbir korisničkih salda jednak je
totalAssets” ili „samo timelock može da menja naknade”. Te izjave postaju osnova i za pregled auditora i za vaše sopstvene testove invarijanti. - Dokumentujte poznate probleme i prihvaćene rizike. Navedite ograničenja kojih ste već svesni i dizajnerske odluke koje prihvatate, poput kompromisa centralizacije ili nepodržanih vrsta tokena. Tako ne završe u izveštaju, a auditori vide gde ste već sve promislili.
2. Higijena koda i statička analiza#
Šum u kodu troši vreme audita i stvara nalaze male vrednosti, pa ga uklonite pre nego što ga auditori vide.
- Fiksirajte verziju kompajlera i dođite do nula upozorenja. Koristite tačnu
pragma solidity 0.8.x;umesto plutajuće^0.8.0i uskladite verziju, broj optimizer runova,via_irievm_versionufoundry.tomlsa onim što ćete postaviti. Svako upozorenje kompajlera treba ispraviti ili svesno obrazložiti. - Fiksirajte i popišite zavisnosti. Zaključajte OpenZeppelin Contracts i svaku drugu biblioteku na tačno izdanje, npr. označeni v5.x submodule ili tačnu verziju u
package.json. Navedite sve zavisnosti u dokumentaciji za audit i označite sve kopirane ili izmenjene datoteke. - Uklonite mrtav kod, TODO-e i debug ispis. Obrišite nekorišćene funkcije, zakomentarisani kod,
console.logimporte i zaostale test pomoćnike iz ugovora u obimu. Otvoreni TODO-i ukazuju na nedovršenu logiku i biće tako i prijavljeni. - Dovršite NatSpec za spoljne i javne funkcije. Svaka spoljna i javna funkcija treba da ima
@notice,@param,@returni, gde je relevantno, napomenu o kontroli pristupa i revertima. Koristite custom errors i emitujte evente za svaku promenu stanja koja je važna van lanca. - Pokrenite Slither i trijažirajte svaki nalaz. Pokrenite
slitherna zamrznutom commitu i svaki nalaz označite kao ispravljen, lažno pozitivan ili prihvaćen, uz obrazloženje u jednoj rečenici. Drugi alat poput Aderyna često pronađe drugačije obrasce, a podeljena trijaža auditorima pokazuje koji su automatizovani nalazi već rešeni.
3. Testovi#
Testovi auditorima pokazuju kako kod treba da se koristi i omogućavaju im da brzo napišu proof of concept.
- Pokrijte svaku spoljnu funkciju i objavite izveštaj. Svaka spoljna i javna funkcija treba da ima bar jedan test uobičajenog scenarija. Generišite izveštaj o pokrivenosti linija i grana pomoću
forge coveragei objasnite nepokrivene grane umesto da ih skrivate. - Testirajte revert putanje i granične slučajeve. Pomoću
vm.expectRevertproverite da neovlašćeni pozivi, neispravni parametri, nulti iznosi i granične vrednosti revertuju sa očekivanim custom errorom. U netestiranim revert putanjama kriju se greške validacije i kontrole pristupa. - Pokrenite fork testove na stvarnim integracijama. Ako protokol komunicira sa spoljnim ugovorima poput DEX-ova, lending tržišta ili orakla, testirajte na mainnet ili L2 forku sa fiksiranim brojem bloka. Mockovi dokazuju samo da vaš kod radi sa vašim pretpostavkama o drugoj strani.
4. Fuzzing i testiranje invarijanti#
Fuzzing pronalazi kombinacije ulaza na koje niko nije pomislio, a testovi invarijanti proveravaju da sistem ostaje konzistentan kroz nizove poziva.
- Fuzzujte svaku funkciju sa numeričkim ulazima. Napišite Foundry fuzz testove za iznose, vremenske oznake, izračunavanje udela i logiku naknada i ograničite ulaze pomoću
bound()umesto preteranogvm.assume. Tipične mete su smer zaokruživanja i prekoračenje pri ekstremnim vrednostima. - Napišite stateful testove invarijanti sa handlerima. Koristite Foundry invariant testiranje sa handler ugovorima koji pozivaju sistem u realističnim nizovima iz perspektive više aktera. Posle svakog niza poziva proverite solventnost, očuvanje vrednosti i svojstva kontrole pristupa.
- Uskladite zapisane invarijante i test paket. Svaka invarijanta iz specifikacije treba da ima svoj test invarijante, a svaki test invarijante treba da može da se poveže sa specifikacijom. Pokrećite paket u CI-ju sa smislenim brojem runova i dubinom, a ne samo lokalno sa podrazumevanim podešavanjima.
5. Kontrola pristupa i nadogradivost#
Privilegovane funkcije i nadogradnje mogu da pomere ili zaključaju svu imovinu u sistemu, pa model poverenja mora biti izričit.
- Popišite svaku privilegovanu ulogu i funkciju. Dokumentujte svaku ulogu, koje funkcije sme da poziva, ko je drži i koji je najgori scenario ako joj je ključ kompromitovan. To je odeljak o pretpostavkama poverenja koji auditori prvi traže.
- Stavite administratorska ovlašćenja iza multisiga i timelocka. Kritičnim parametrima i nadogradnjama treba da upravlja multisig poput Safe-a, uz
TimelockControllerili ekvivalentno odlaganje za promene koje utiču na sredstva korisnika. Dokumentujte prag potpisnika i trajanje odlaganja. - Proverite storage layout nadogradivih ugovora. Za proxy ugovore koristite nadogradive ugovore iz OpenZeppelin v5 sa ERC-7201 namespaced storageom i validirajte nadogradnje OpenZeppelin alatima za nadogradnje. Ako je nadogradnja u obimu, priložite razliku storage layouta između verzija.
- Zaštitite inicijalizatore i funkcije nadogradnje. Pozovite
_disableInitializers()u konstruktoru implementacije, ispravno koristite modifikatoreinitializerireinitializeri ograničite_authorizeUpgradekod UUPS proxy ugovora (ERC-1822). Nezaštićen implementacioni ugovor je nalaz koji auditori nikada ne bi trebalo da moraju da prijave.
6. Spoljne integracije#
Svaki spoljni poziv je pretpostavka o tuđem kodu, a svaku pretpostavku treba zapisati i testirati.
- Obradite zastarele podatke i ispad orakla. Proverite
updatedAtu odnosu na heartbeat feeda, odbacite cene jednake nuli ili negativne i na L2 mrežama proverite sequencer uptime feed. Odlučite i dokumentujte šta protokol radi kada orakl nije dostupan. - Uzmite u obzir posebnosti tokena. Navedite koje su vrste tokena podržane i obradite ili izričito isključite fee-on-transfer, rebasing, tokene sa brojem decimala različitim od 18 i nestandardne ERC-20 tokene. Za prenose koristite
SafeERC20i merite razliku salda gde je bitan stvarno primljeni iznos. - Mapirajte površine za reentrancy. Popišite svaki spoljni poziv i prenos tokena, sledite obrazac checks-effects-interactions i koristite
ReentrancyGuard(iliReentrancyGuardTransientuz EIP-1153) gde se stanje deli. Uzmite u obzir cross-function i read-only reentrancy, kao i callbackove ERC-721, ERC-1155 i ERC-777 tokena. - Razmotrite MEV i front-running. Dodajte ograničenja slippagea i rokove swapovima i depozitima, zaštitite ERC-4626 vaultove od inflacionog napada prvog deponenta i pregledajte svu logiku koja zavisi od redosleda transakcija. Dokumentujte koje rizike redosleda prihvatate.
7. Postavljanje i rad u produkciji#
Auditovani kod je bezbedan samo onoliko koliko je bezbedan način na koji se postavlja i održava.
- Neka deploy skripte budu ponovljive, a parametri dokumentovani. Postavljajte ugovore Foundry skriptama sa zamrznutog commita, držite svaki parametar konstruktora i inicijalizatora u verzionisanoj konfiguraciji i uključite skripte u obim ili bar u paket za predaju. Ispravan ugovor postavljen sa pogrešnim parametrima i dalje je neispravan.
- Uvežbajte postavljanje na testnetu sa verifikovanim izvornim kodom. Pokrenite istu deploy skriptu na testnetu i na mainnet forku, verifikujte izvorni kod na block exploreru i proverite da li su uloge završile na predviđenim adresama. Dajte auditorima testnet adrese kako bi mogli da rade sa stvarnim postavljanjem.
- Pripremite pauzu, runbook i nadzor. Odlučite ko sme da pauzira šta, napišite kratak runbook za incidente i podesite upozorenja za promene uloga, nadogradnje, velika povlačenja i stanja pauze. Auditori pregledaju hitne putanje, pa one moraju da postoje pre audita.
8. Organizacija audita#
Dobra organizacija održava tempo audita i obezbeđuje da se runda ispravki zaista iskoristi.
- Odredite tehničku kontakt osobu i kanal. Odredite jednog developera koji poznaje kodnu bazu i može da odgovori na pitanja u roku od nekoliko sati i dogovorite zajednički kanal za trajanje audita. Svako neodgovoreno pitanje usporava pregled.
- Rezervišite vreme za ispravke i rundu njihove provere. Planirajte kapacitet developera odmah po prijemu izveštaja i unapred dogovorite da auditori provere ispravke. Neproverene ispravke mogu da unesu nove greške nakon što je audit zaključen.
- Otkrijte prethodne audite i preglede. Podelite ranije izveštaje o auditu, status njihovih ispravki i sve interne preglede. Auditori tada mogu da se usredsrede na promene i provere da se raniji nalazi nisu vratili.
Kako možemo da pomognemo#
Nudimo Audit-Readiness Sprint fiksnog obima u trajanju od jedne do dve nedelje: model pretnji, analizu nedostataka test paketa, Foundry fuzz i testove invarijanti, Slither trijažu, prioritizovanu listu ispravki i paket za predaju auditorima sa obimom, dokumentacijom i poznatim problemima. Nismo firma za audit i sprint ne zamenjuje spoljni audit; on priprema vaš kod kako bi auditori svoje vreme mogli da posvete logici. Detalji su na našoj stranici sa cenama i među našim uslugama za Blockchain i Web3.
Ako želite besplatnu procenu za svoju kodnu bazu, opišite nam svoj projekat. Pre nego što podelite kod, rado ćemo potpisati obostrani NDA.