Preskoči na sadržaj

Članci

Kontrolni popis spremnosti pametnih ugovora za audit

30 provjera prije audita pametnih ugovora: opseg i dokumentacija, testovi, Foundry fuzz i invarijante, Slither trijaža, kontrola pristupa i implementacija.

Inženjerski tim sigmacode.io8 min čitanja

Na ovoj stranici (9)
  1. 1. Opseg i dokumentacija
  2. 2. Higijena koda i statička analiza
  3. 3. Testovi
  4. 4. Fuzzing i testiranje invarijanti
  5. 5. Kontrola pristupa i nadogradivost
  6. 6. Vanjske integracije
  7. 7. Implementacija i rad u produkciji
  8. 8. Organizacija audita
  9. Kako vam možemo pomoći

Audit pametnih ugovora skup je i strogo vremenski ograničen. Auditori imaju fiksan broj dana, a svaki sat koji potroše na otkrivanje što bi kod trebao raditi, praćenje commita koji se stalno mijenja ili pisanje testova koje niste napisali sat je koji ne provode na logici zbog koje se stvarno mogu izgubiti sredstva. Izvještaj se tada puni nedostajućim NatSpec komentarima, plutajućim pragmama i netestiranim revert putanjama umjesto problemima za čije ste pronalaženje platili.

Dobro pripremljena kodna baza za isti budžet dobiva dublji audit. Ovaj kontrolni popis sažima ono što pripremimo prije predaje koda vanjskim auditorima: 30 konkretnih provjera koje pokrivaju dokumentaciju, higijenu koda, testiranje, kontrolu pristupa, integracije, implementaciju i organizaciju. Ne zamjenjuje audit, nego osigurava da vrijeme audita ode tamo gdje je važno.

1. Opseg i dokumentacija#

Auditori mogu provjeriti ponašanje samo u odnosu na namjeru koju razumiju, pa ta namjera mora biti zapisana.

  • Zamrznite commit hash. Predajte auditorima jedan označeni commit i ne mijenjajte kod koji se pregledava tijekom audita. Ispravci nastaju na zasebnoj grani i pregledavaju se u rundi provjere ispravaka.
  • Objavite popis datoteka u opsegu s nSLOC-om. Navedite svaki ugovor u opsegu s putanjom i brojem normaliziranih linija koda te izričito navedite što nije u opsegu (biblioteke, mockovi, skripte, već auditirane datoteke). Auditori procjenjuju i planiraju na temelju nSLOC-a, pa točan broj sprječava iznenađenja na obje strane.
  • Napišite pregled arhitekture. Jedna do dvije stranice 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 što svaka vanjska funkcija mora raditi i koja svojstva uvijek moraju vrijediti, npr. „zbroj korisničkih salda jednak je totalAssets” ili „samo timelock može mijenjati naknade”. Te izjave postaju temelj i za pregled auditora i za vaše vlastite testove invarijanti.
  • Dokumentirajte poznate probleme i prihvaćene rizike. Navedite ograničenja kojih ste već svjesni i dizajnerske odluke koje prihvaćate, poput kompromisa centralizacije ili nepodržanih vrsta tokena. Tako ne završe u izvještaju, a auditori vide gdje ste već sve promislili.

2. Higijena koda i statička analiza#

Šum u kodu troši vrijeme audita i stvara nalaze male vrijednosti, pa ga uklonite prije nego što ga auditori vide.

  • Fiksirajte verziju compilera i dođite do nula upozorenja. Koristite točnu pragma solidity 0.8.x; umjesto plutajuće ^0.8.0 te uskladite verziju, broj optimizer runova, via_ir i evm_version u foundry.toml s onim što ćete implementirati. Svako upozorenje compilera treba ispraviti ili svjesno obrazložiti.
  • Fiksirajte i popišite ovisnosti. Zaključajte OpenZeppelin Contracts i svaku drugu biblioteku na točno izdanje, npr. označeni v5.x submodule ili točnu verziju u package.json. Navedite sve ovisnosti u dokumentaciji za audit i označite sve kopirane ili izmijenjene datoteke.
  • Uklonite mrtvi kod, TODO-e i debug ispis. Obrišite nekorištene funkcije, zakomentirani kod, console.log importe i zaostale testne pomoćnike iz ugovora u opsegu. Otvoreni TODO-i upućuju na nedovršenu logiku i bit će tako i prijavljeni.
  • Dovršite NatSpec za vanjske i javne funkcije. Svaka vanjska i javna funkcija treba imati @notice, @param, @return i, gdje je relevantno, napomenu o kontroli pristupa i revertima. Koristite custom errors i emitirajte evente za svaku promjenu stanja koja je važna izvan lanca.
  • Pokrenite Slither i trijažirajte svaki nalaz. Pokrenite slither na 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 drukčije obrasce, a podijeljena trijaža auditorima pokazuje koji su automatizirani nalazi već riješeni.

3. Testovi#

Testovi auditorima pokazuju kako se kod treba koristiti i omogućuju im da brzo napišu proof of concept.

  • Pokrijte svaku vanjsku funkciju i objavite izvještaj. Svaka vanjska i javna funkcija treba barem jedan test uobičajenog scenarija. Generirajte izvještaj o pokrivenosti linija i grana s forge coverage i objasnite nepokrivene grane umjesto da ih skrivate.
  • Testirajte revert putanje i rubne slučajeve. Pomoću vm.expectRevert provjerite da neovlašteni pozivi, neispravni parametri, nulti iznosi i granične vrijednosti revertiraju s očekivanim custom errorom. U netestiranim revert putanjama skrivaju se greške validacije i kontrole pristupa.
  • Pokrenite fork testove na stvarnim integracijama. Ako protokol komunicira s vanjskim ugovorima poput DEX-ova, lending tržišta ili oracla, testirajte na mainnet ili L2 forku s fiksiranim brojem bloka. Mockovi dokazuju samo da vaš kod radi s vašim pretpostavkama o drugoj strani.

4. Fuzzing i testiranje invarijanti#

Fuzzing pronalazi kombinacije ulaza na koje nitko nije pomislio, a testovi invarijanti provjeravaju da sustav ostaje konzistentan kroz nizove poziva.

  • Fuzzajte svaku funkciju s numeričkim ulazima. Napišite Foundry fuzz testove za iznose, vremenske oznake, izračune udjela i logiku naknada te ograničite ulaze s bound() umjesto pretjeranog vm.assume. Tipične mete su smjer zaokruživanja i preljev pri ekstremnim vrijednostima.
  • Napišite stateful testove invarijanti s handlerima. Koristite Foundry invariant testiranje s handler ugovorima koji pozivaju sustav u realističnim nizovima iz perspektive više aktera. Nakon svakog niza poziva provjerite solventnost, očuvanje vrijednosti i svojstva kontrole pristupa.
  • Uskladite zapisane invarijante i testni paket. Svaka invarijanta iz specifikacije treba imati svoj test invarijante, a svaki test invarijante treba se moći povezati sa specifikacijom. Pokrećite paket u CI-ju sa smislenim brojem runova i dubinom, a ne samo lokalno sa zadanim postavkama.

5. Kontrola pristupa i nadogradivost#

Privilegirane funkcije i nadogradnje mogu pomaknuti ili zaključati svu imovinu u sustavu, pa model povjerenja mora biti izričit.

  • Popišite svaku privilegiranu ulogu i funkciju. Dokumentirajte svaku ulogu, koje funkcije smije pozivati, tko je drži i koji je najgori scenarij ako joj je ključ kompromitiran. To je odjeljak o pretpostavkama povjerenja koji auditori prvi traže.
  • Stavite administratorske ovlasti iza multisiga i timelocka. Kritičnim parametrima i nadogradnjama treba upravljati multisig poput Safea, uz TimelockController ili jednakovrijednu odgodu za promjene koje utječu na sredstva korisnika. Dokumentirajte prag potpisnika i trajanje odgode.
  • Provjerite storage layout nadogradivih ugovora. Za proxyje koristite nadogradive ugovore iz OpenZeppelin v5 s ERC-7201 namespaced storageom i validirajte nadogradnje OpenZeppelinovim alatima za nadogradnje. Ako je nadogradnja u opsegu, priložite razliku storage layouta između verzija.
  • Zaštitite inicijalizatore i funkcije nadogradnje. Pozovite _disableInitializers() u konstruktoru implementacije, ispravno koristite modifikatore initializer i reinitializer te ograničite _authorizeUpgrade kod UUPS proxyja (ERC-1822). Nezaštićeni implementacijski ugovor nalaz je koji auditori nikada ne bi trebali morati prijaviti.

6. Vanjske integracije#

Svaki vanjski poziv pretpostavka je o tuđem kodu, a svaku pretpostavku treba zapisati i testirati.

  • Obradite zastarjele podatke i ispad oracla. Provjerite updatedAt u odnosu na heartbeat feeda, odbacite cijene jednake nuli ili negativne te na L2 mrežama provjerite sequencer uptime feed. Odlučite i dokumentirajte što protokol radi kada oracle nije dostupan.
  • Uzmite u obzir posebnosti tokena. Navedite koje su vrste tokena podržane te obradite ili izričito isključite fee-on-transfer, rebasing, tokene s brojem decimala različitim od 18 i nestandardne ERC-20 tokene. Za prijenose koristite SafeERC20 i mjerite razliku salda gdje je bitan stvarno primljeni iznos.
  • Mapirajte površine za reentrancy. Popišite svaki vanjski poziv i prijenos tokena, slijedite obrazac checks-effects-interactions i koristite ReentrancyGuard (ili ReentrancyGuardTransient uz EIP-1153) gdje se stanje dijeli. Uzmite u obzir cross-function i read-only reentrancy te 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 inflacijskog napada prvog deponenta i pregledajte svu logiku koja ovisi o redoslijedu transakcija. Dokumentirajte koje rizike redoslijeda prihvaćate.

7. Implementacija i rad u produkciji#

Auditirani kod siguran je samo onoliko koliko je siguran način na koji se implementira i održava.

  • Neka deploy skripte budu ponovljive, a parametri dokumentirani. Implementirajte Foundry skriptama sa zamrznutog commita, držite svaki parametar konstruktora i inicijalizatora u verzioniranoj konfiguraciji te uključite skripte u opseg ili barem u paket za predaju. Ispravan ugovor implementiran s pogrešnim parametrima i dalje je neispravan.
  • Uvježbajte implementaciju na testnetu s verificiranim izvornim kodom. Pokrenite istu deploy skriptu na testnetu i na mainnet forku, verificirajte izvorni kod na block exploreru i provjerite jesu li uloge završile na predviđenim adresama. Dajte auditorima testnet adrese kako bi mogli raditi sa stvarnom implementacijom.
  • Pripremite pauzu, runbook i nadzor. Odlučite tko smije pauzirati što, napišite kratki runbook za incidente i postavite upozorenja za promjene uloga, nadogradnje, velika povlačenja i stanja pauze. Auditori pregledavaju hitne putanje, pa one moraju postojati prije audita.

8. Organizacija audita#

Dobra organizacija održava tempo audita i osigurava da se runda ispravaka doista iskoristi.

  • Imenujte tehničku kontakt osobu i kanal. Odredite jednog developera koji poznaje kodnu bazu i može odgovoriti na pitanja u roku od nekoliko sati te dogovorite zajednički kanal za trajanje audita. Svako neodgovoreno pitanje usporava pregled.
  • Rezervirajte vrijeme za ispravke i rundu njihove provjere. Planirajte kapacitet developera odmah nakon primitka izvještaja i unaprijed dogovorite da auditori provjere ispravke. Neprovjereni ispravci mogu unijeti nove greške nakon što je audit zaključen.
  • Otkrijte prethodne audite i preglede. Podijelite ranije izvještaje o auditu, status njihovih ispravaka i sve interne preglede. Auditori se tada mogu usredotočiti na promjene i provjeriti da se raniji nalazi nisu vratili.

Kako vam možemo pomoći#

Nudimo Audit-Readiness Sprint fiksnog opsega u trajanju od jednog do dva tjedna: model prijetnji, analizu nedostataka testnog paketa, Foundry fuzz i testove invarijanti, Slither trijažu, prioritiziran popis ispravaka i paket za predaju auditorima s opsegom, dokumentacijom i poznatim problemima. Nismo tvrtka za audit i sprint ne zamjenjuje vanjski audit; on priprema vaš kod kako bi auditori svoje vrijeme mogli posvetiti logici. Pojedinosti su na našoj stranici s cijenama i među našim uslugama za Blockchain i Web3.

Ako želite besplatnu procjenu za svoju kodnu bazu, opišite nam svoj projekt. Prije nego što podijelite kod, rado ćemo potpisati obostrani NDA.

Imate projekt na umu?

Recite nam što gradite. Dobit ćete iskrenu procjenu, jasan opseg i ponudu s fiksnom cijenom ili po fazama – obično u roku od nekoliko radnih dana.

Radije biste prvo pisali? Pišite nam