Megbízhatósági legjobb gyakorlatok az intelligens szerződéses biztonság érdekében

blog 1NewsDevelopersEnterpriseBlockchain ExplainedEvents and ConferencesPressHírlevelek

Contents

Iratkozzon fel hírlevelünkre.

Email cím

Tiszteletben tartjuk a magánéletét

HomeBlogBlockchain fejlesztés

Megbízhatósági legjobb gyakorlatok az intelligens szerződéses biztonság érdekében

A figyeléstől kezdve az időbélyegző szempontokig, íme néhány profi tipp az Ethereum intelligens szerződéseinek megerősítéséhez. Készítette ConsenSys 2020. augusztus 21. Feladva 2020. augusztus 21-én

szilárdság legjobb gyakorlatok hős

A ConsenSys Diligence, blokklánc biztonsági szakértőkből álló csapatunk.

Ha a szívére vette az intelligens szerződéses biztonsági gondolkodásmódot, és kezébe veszi az EVM sajátosságait, itt az ideje, hogy fontolóra vegyen néhány, a Solidity programozási nyelvre jellemző biztonsági mintát. Ebben a körben a Solidity biztonságos fejlesztési ajánlásaira összpontosítunk, amelyek hasznosak lehetnek más nyelvű intelligens szerződések kidolgozásához is. 

Oké, ugorjunk be.

Használja megfelelően az assert (), a szükséges (), a visszaállítást ()

A kényelmi funkciók állítják és megkövetelik felhasználható a feltételek ellenőrzésére és egy kivétel kivetésére, ha a feltétel nem teljesül.

állítják funkció csak a belső hibák tesztelésére és az invariánsok ellenőrzésére használható.

megkövetelik függvényt kell használni az érvényes feltételek, például a bemenetek vagy a szerződésállapot-változók teljesülésének biztosításához, vagy a külső szerződésekre irányuló hívásokból származó visszatérési értékek érvényesítéséhez. 

Ennek a paradigmának a követése lehetővé teszi a formális elemző eszközök segítségével annak ellenőrzését, hogy az érvénytelen opcode soha nem érhető el: vagyis a kódban egyetlen invariáns sem sérül meg, és hogy a kódot hivatalosan ellenőrzik.

pragma szilárdság ^ 0,5,0; szerződéses megosztó {function sendHalf (fizetendő cím addr) nyilvános fizetendő hozamok (uint egyenleg) {előírja (msg.value% 2 == 0, "Egyenletes érték szükséges."); // A Require () opcionális üzenetlánccal rendelkezhet uint balanceBeforeTransfer = address (this) .balance; (bool siker,) = addr.call.value (msg.value / 2) (""); megkövetelik (siker); // Mivel visszavontuk, ha az átutalás sikertelen volt, nem szabad, hogy // a pénz fele megmaradjon. állítás (cím (ez) .egyensúly == balanceBeforeTransfer – msg.value / 2); // belső hibaellenőrzéshez használt visszatérési cím (ez) .balance; }} Kód nyelve: JavaScript (javascript)


Lát SWC-110 & SWC-123

A módosítókat csak ellenőrzésekhez használja

A módosítóban lévő kódot általában a függvénytörzs előtt hajtják végre, így bármilyen állapotváltozás vagy külső hívás megsérti a Ellenőrzések-hatások-kölcsönhatások minta. Sőt, ezeket az utasításokat a fejlesztő sem észreveheti, mivel a módosító kódja távol állhat a függvény deklarációjától. Például egy külső hívás a módosítóban újból belépési támadáshoz vezethet:

szerződés Nyilvántartás {cím tulajdonosa; function isVoter (address _addr) külső visszatér (bool) {// Code}} szerződés Választás {Registry register; a módosító isEligible (cím _addr) {igényel (register.isVoter (_addr)); _; } függvény szavazás () isEligible (msg.sender) public {// Code}} Kód nyelve: JavaScript (javascript)

Ebben az esetben a nyilvántartási szerződés újraterápiás támadást tehet az ElV.vote () meghívásával az isVoter () oldalon..

Jegyzet: Használat módosítók a többszörös feltételellenőrzések cseréjére több funkcióban, például az isOwner () esetén, különben használja a function vagy a return funkciót. Ez okosabb szerződéskódját olvashatóbbá és könnyebben ellenőrizhetővé teszi.

Vigyázzon egész kerekítéssel

Minden egész osztás lefelé kerekszik a legközelebbi egész számra. Ha nagyobb pontosságra van szüksége, fontolja meg a szorzó használatát, vagy tárolja mind a számlálót, mind a nevezőt.

(A jövőben a Szoliditásnak lesz egy fix pont típusú, ami ezt megkönnyíti.)

// rossz uint x = 5/2; // Az eredmény 2, minden egész osztókör lefelé kerekít a legközelebbi egész számra Kód nyelve: JavaScript (javascript)

A szorzó használata megakadályozza a lefelé kerekítést, ezt a szorzót figyelembe kell venni, ha a jövőben x-szel dolgozik:

// jó uint szorzó = 10; uint x = (5 * szorzó) / 2; Kód nyelve: JavaScript (javascript)

A számláló és a nevező tárolása azt jelenti, hogy kiszámíthatja a számláló / nevező eredményét a láncon kívül:

// jó uint számláló = 5; uint nevező = 2; Kód nyelve: JavaScript (javascript)

Legyen tisztában a közötti kompromisszumokkal elvont szerződések és interfészek

Mind az interfészek, mind az absztrakt szerződések testreszabható és újrafelhasználható megközelítést biztosítanak az intelligens szerződésekhez. Az interfészek, amelyeket a Solidity 0.4.11-ben vezettek be, hasonlóak az elvont szerződésekhez, de nem képesek egyetlen funkciót sem végrehajtani. Az interfészeknek vannak olyan korlátai is, mint például az, hogy nem férhetnek hozzá a tárhelyhez, vagy nem örökölhetnek más interfészektől, ami általában az absztrakt szerződéseket teszi praktikusabbá. Bár az interfészek minden bizonnyal hasznosak a megvalósítás előtti szerződések megtervezéséhez. Ezenkívül fontos szem előtt tartani, hogy ha egy szerződés elvont szerződésből öröklődik, akkor minden nem megvalósított funkciót felülírva kell végrehajtania, különben elvont is lesz.

Tartalék funkciók

Tartsa egyszerűvé a tartalék funkciókat

Tartalék funkciók hívják, amikor a szerződésnek argumentum nélküli üzenetet küldenek (vagy ha egyetlen funkció sem felel meg), és csak 2300 gázhoz férhet hozzá, ha a .send () vagy .transfer () hívás kezdeményezi. Ha azt szeretné, hogy az étert egy .send () vagy .transfer () alkalmazásból tudja fogadni, akkor a tartalék funkcióban az esemény naplózása a legtöbb. Használjon megfelelő funkciót, ha több gáz kiszámítására van szükség.

// rossz funkció () fizetendő {egyenlegek [msg.sender] + = msg.value; } // jó funkciójú betét () fizetendő külső {egyenlegek [msg.sender] + = msg.value; } függvény () fizetendő {igényel (msg.data.length == 0); emite LogDepositReceived (msg.sender); } Kód nyelve: JavaScript (javascript)

Ellenőrizze az adatok hosszát a tartalék funkciókban

Mivel a tartalék funkciók nem csak sima éter-átvitelre szólít fel (adatok nélkül), hanem akkor is, ha más funkció nem egyezik meg, akkor ellenőrizze, hogy az adatok üresek-e, ha a tartalék funkciót csak a kapott éter naplózásához kívánják használni. Ellenkező esetben a hívók nem veszik észre, ha a szerződését helytelenül használják, és nem létező funkciókat hívnak meg.

// rossz funkció () fizetendő {emit LogDepositReceived (msg.sender); } // jó funkció () fizetendő {igényel (msg.data.length == 0); emite LogDepositReceived (msg.sender); } Kód nyelve: JavaScript (javascript)

Kifejezetten jelölje meg a fizetendő függvényeket és az állapotváltozókat

A Solidity 0.4.0-tól kezdve minden étert kapó függvénynek fizetendő módosítót kell használnia, különben, ha a tranzakció msg.value > 0 visszaáll (kivéve, ha kényszerítik).

Jegyzet: Valami, ami nem biztos, hogy nyilvánvaló: A fizetendő módosító csak a külső szerződésekből érkező hívásokra vonatkozik. Ha ugyanabban a szerződésben hívok egy nem fizetendő függvényt a fizetendő függvényben, akkor a nem fizetendő függvény nem fog meghiúsulni, bár az msg.value még mindig be van állítva.

Kifejezetten jelölje meg a láthatóságot a függvényekben és az állapotváltozókban

Kifejezetten jelölje meg a függvények és az állapotváltozók láthatóságát. A funkciók megadhatók külső, nyilvános, belső vagy privátként. Kérjük, értse meg a köztük lévő különbségeket, például a nyilvános helyett elegendő lehet a külső. Állapotváltozók esetén a külső nem lehetséges. A láthatóság kifejezett felcímkézése megkönnyíti a helytelen feltételezések felismerését azzal kapcsolatban, hogy ki hívhatja meg a függvényt, vagy férhet hozzá a változóhoz.

  • A külső funkciók a szerződéses felület részét képezik. Az f külső függvény nem hívható belülről (azaz az f () nem működik, de ez az f () működik). A külső funkciók néha hatékonyabbak, ha nagy adattömböket kapnak.
  • A nyilvános funkciók a szerződéses felület részét képezik, és meghívhatók belsőleg vagy üzenetek útján. Nyilvános állapotú változók esetén egy automatikus getter funkció jön létre (lásd alább).
  • A belső függvények és az állapotváltozók csak belsőleg érhetők el, ennek használata nélkül.
  • A privát függvények és az állapotváltozók csak azoknál a szerződéseknél láthatók, amelyekben meghatározták őket, és nem származtatott szerződéseknél. jegyzet: Minden, ami egy szerződésen belül van, a blokkláncon kívüli összes megfigyelő számára látható, még a privát változók is.

// rossz uint x; // az alapértelmezés az állapotváltozók számára belső, de kifejezetten meg kell adni a buy () függvényt {// az alapértelmezett a public // nyilvános kód} // good uint private y; function buy () external {// csak külsőleg hívható, vagy a this.buy ()} function utility () public {// külsőleg és belsőleg is használható: a kód megváltoztatásához mindkét esetre gondolni kell. } function internalAction () internal {// belső kód} Kód nyelve: PHP (php)

Lát SWC-100 és SWC-108

A pragmák zárolása a fordító adott verziójához

A szerződéseket ugyanazzal a fordítóverzióval és jelzőkkel kell telepíteni, amelyekkel a legtöbbet tesztelték. A pragma lezárása segít abban, hogy a szerződések véletlenül ne kerüljenek telepítésre, például a legújabb fordító segítségével, amelynek nagyobb lehet a felfedezetlen hibák kockázata. A szerződéseket mások is alkalmazhatják, és a pragma jelzi az eredeti szerzők által tervezett fordítói verziót.

// rossz pragma szilárdság ^ 0,4.4; // jó pragma szilárdság 0.4.4; Kód nyelve: JavaScript (javascript)

Megjegyzés: egy lebegő pragma verzió (azaz. ^ 0.4.25) 0,4,26-os éjszakai fordítással működik. 2018.9.25, azonban az éjszakai buildeket soha nem szabad felhasználni a gyártási kód összeállításához.

Figyelem: A pragma utasítások lebeghetnek akkor, ha a szerződést más fejlesztők fogyasztják, például könyvtár vagy EthPM csomagban kötött szerződések esetén. Ellenkező esetben a fejlesztőnek manuálisan frissítenie kell a pragmát a helyi fordítás érdekében.

Lát SWC-103

Használja az eseményeket a szerződéses tevékenység figyelemmel kísérésére

Hasznos lehet, ha módja van a szerződés tevékenységének nyomon követésére a telepítés után. Ennek megvalósításának egyik módja a szerződés összes tranzakciójának megvizsgálása, azonban ez nem lehet elégséges, mivel a szerződések közötti üzenethívásokat nem rögzítik a blokkláncban. Ezenkívül csak a bemeneti paramétereket mutatja, az állapot tényleges változtatásait nem. Az eseményeket fel lehet használni a felhasználói felület funkcióinak elindítására is.

szerződés Jótékonysági {térképezés (cím => uint) mérlegek; függvény donate () fizetendő nyilvános {egyenlegek [msg.sender] + = msg.value; }} szerződéses játék {function buyCoins () fizetendő nyilvános {// 5% a jótékonysági jótékonysági.donate.value (msg.value / 20) (); }} Kód nyelve: JavaScript (javascript)

Itt a játék szerződés belső hívást kezdeményez a Charity.donate () címre. Ez a tranzakció nem jelenik meg a Charity külső tranzakciók listájában, de csak a belső tranzakcióknál látható.

Az esemény kényelmes módja annak, hogy naplózza a szerződésben történteket. A kibocsátott események a blokkláncban maradnak a többi szerződéses adattal együtt, és rendelkezésre állnak a jövőbeni ellenőrzéshez. Itt van egy továbbfejlesztés a fenti példához: az események felhasználásával bemutatjuk a Szeretetszolgálat adományainak történetét.

szerződéses jótékonysági {// eseményesemény meghatározása LogDonate (uint _összeg); leképezés (cím => uint) mérlegek; függvény donate () fizetendő nyilvános {egyenlegek [msg.sender] + = msg.value; // emit event emit LogDonate (msg.value); }} szerződéses játék {function buyCoins () fizetendő nyilvános {// 5% a jótékonysági jótékonysági.donate.value (msg.value / 20) (); }} Kód nyelve: JavaScript (javascript)

Itt minden olyan tranzakció, amely közvetlenül vagy sem a jótékonysági szerződésen megy keresztül, megjelenik a szerződés eseménylistájában, az adományozott pénzösszeg mellett.

Megjegyzés: Inkább az újabb Solidity konstrukciókat részesítse előnyben. Előnyben részesítjük az olyan konstrukciókat / álneveket, mint az önmegsemmisítés (az öngyilkossággal szemben) és a keccak256 (a sha3 felett). Az ehhez hasonló minták (msg.sender.send (1 éter)) egyszerűsíthetők a transfer () használatával is, mint az msg.sender.transfer (1 éter) esetében. Nézd meg Szilárdság változás napló további hasonló változásokhoz.

Ne feledje, hogy a „Beépítettek” árnyékolhatók

Jelenleg lehetséges árnyék beépített globálisok a szilárdságban. Ez lehetővé teszi, hogy a szerződések felülbírálják a beépített funkciók, például az msg és a revert () funkcionalitását. Bár ez szánják, félrevezetheti a szerződés felhasználóit a szerződés valódi magatartása tekintetében.

szerződés PretendingToRevert {function revert () belső konstans {}} contract ExampleContract PretendingToRevert {function somethingBad () public {revert (); }}

A szerződéses felhasználóknak (és auditoroknak) tisztában kell lenniük minden alkalmazás teljes intelligens szerződésének forráskódjával.

Kerülje a tx.origin használatát

Soha ne használja a tx.origin szolgáltatást engedélyezésre, egy másik szerződésnek lehet egy módszere, amely felhívja a szerződését (ahol például a felhasználónak van némi forrása), és a szerződése engedélyezi a tranzakciót, mivel a címe a tx.origin címen található..

szerződés MyContract {címtulajdonos; függvény MyContract () public {owner = msg.sender; } function sendTo (cím vevő, uint összeg) public {igényel (tx.origin == tulajdonos); (bool siker,) = vevő.hívás.érték (összeg) {""); megkövetelik (siker); }} szerződés AttackingContract {MyContract myContract; cím támadó; függvény AttackingContract (cím myContractAddress) public {myContract = MyContract (myContractAddress); támadó = üzenet küldő; } function () public {myContract.sendTo (támadó, msg.sender.balance); }} Kód nyelve: JavaScript (javascript)

Az engedélyezéshez az msg.sender szolgáltatást kell használnia (ha egy másik szerződés felhívja az Ön szerződését, akkor az msg.sender lesz a szerződés címe, és nem annak a felhasználónak a címe, aki felhívta a szerződést).

Bővebben itt olvashat róla: Szilárdsági dokumentumok

Figyelem: Az engedélyezéssel kapcsolatos probléma mellett fennáll annak az esélye, hogy a jövőben a tx.origin eltávolításra kerül az Ethereum protokollból, így a tx.origin nevű kód nem lesz kompatibilis a jövőbeli kiadásokkal Vitalik: „NE feltételezzük, hogy a tx.origin továbbra is használható vagy értelmes marad.”

Érdemes megemlíteni azt is, hogy a tx.origin használatával korlátozza a szerződések közötti átjárhatóságot, mert a tx.origint használó szerződést egy másik szerződés nem tudja felhasználni, mivel szerződés nem lehet a tx.origin.

Lát SWC-115

Időbélyeg függőség

Három fő szempont van, amikor az időbélyeget használjuk a kritikus funkció végrehajtásához a szerződésben, különösen akkor, ha a műveletek pénzátutalással járnak.

Időbélyeg manipuláció

Ne feledje, hogy a blokk időbélyegét egy bányász manipulálhatja. Ezt fontold meg szerződés:

uint256 állandó magán só = blokk.időszimbólum; function random (uint Max) állandó privát visszatérés (uint256 eredmény) {// a véletlenszerűséghez a legjobb magot kapja uint256 x = só * 100 / Max; uint256 y = só * blokk.szám / (só% 5); uint256 mag = blokk.szám / 3 + (só% 300) + Last_Payout + y; uint256 h = uint256 (block.blockhash (mag)); return uint256 ((h / x))% Max + 1; // véletlenszerű szám 1 és Max között} Kód nyelve: PHP (php)

Amikor a szerződés az időbélyeget használja a véletlenszerű szám kiírására, a bányász a blokk érvényesítésétől számított 15 másodpercen belül ténylegesen fel tud tenni egy időbélyeget, amely lehetővé teszi a bányász számára, hogy előre kiszámítsa a lottó esélyeihez kedvezőbb lehetőséget. Az időbélyegek nem véletlenszerűek, és ebben az összefüggésben nem használhatók.

A 15 másodperces szabály

Sárga könyv (Az Ethereum referencia specifikációja) nem határoz meg korlátozást arra vonatkozóan, hogy mennyi blokk sodródhat az időben, de meg is határozza hogy minden időbélyegnek nagyobbnak kell lennie a szülőjének időbélyegénél. Népszerű Ethereum protokoll implementációk Geth és Paritás mindkettő elutasítja a blokkokat időbélyeggel, amely a jövőben több mint 15 másodperc. Ezért jó ökölszabály az időbélyeg használatának értékelésekor: ha az időfüggő esemény skálája 15 másodperccel változhat és fenntarthatja az integritást, akkor biztonságos a block.timestamp használata.

Kerülje a block.number időbélyegként való használatát

Meg lehet becsülni az időeltolódást a block.number tulajdonság és átlagos blokkidő, azonban ez nem jövőbeli bizonyíték, mivel a blokkidők változhatnak (mint pl villaátalakítások és a nehézségi bomba). Napokon át tartó eladás esetén a 15 másodperces szabály lehetővé teszi, hogy megbízhatóbb időbecslést érjünk el.

Lát SWC-116

Többszörös öröklési óvatosság

Ha a többszörös öröklődést a Solidity-ben hasznosítja, fontos megérteni, hogy a fordító hogyan állítja össze az öröklődési grafikont.

szerződés Végleges {uint public a; függvény Végső (uint f) public {a = f; }} B szerződés végleges {közpénz; B funkció (uint f) Végső (f) public {} függvény setFee () public {díj = 3; }} C szerződés végleges {közpénz; C függvény (uint f) Végső (f) public {} függvény setFee () public {díj = 5; }} A szerződés B, C {funkció A () public B (3) C (5) {setFee (); }} Kód nyelve: PHP (php)

A szerződés telepítésekor a fordító linearizálja az öröklést jobbról balra (miután a kulcsszó a szülők a legalapvetőbbtől a legeredményesebbekig vannak felsorolva). Itt van az A szerződés linearizálása:

Végső <- B <- C <- A

A linearizálás következménye 5-ös díjérték lesz, mivel a C a legeredményesebb szerződés. Ez nyilvánvalónak tűnhet, de képzeljen el olyan forgatókönyveket, amelyekben C képes árnyékolni a létfontosságú függvényeket, átrendezni a logikai záradékokat, és a fejlesztőt kihasználható szerződések megírására késztetni. A statikus elemzés jelenleg nem vet fel problémát az árnyékolt funkciókkal, ezért manuálisan ellenőrizni kell.

A hozzájárulás elősegítése érdekében a Solidity’s Github a projekt az örökléssel kapcsolatos minden kérdéssel.

Lát SWC-125

A típusbiztonság érdekében használja az interfész típusát a cím helyett

Ha egy függvény argumentumként a szerződés címét veszi, akkor jobb, ha a felületet vagy a szerződés típusát adja át a nyers cím helyett. Ha a függvényt máshol hívják meg a forráskódon belül, a fordító további típusú biztonsági garanciákat nyújt.

Itt két alternatívát látunk:

szerződés Validator {function validate (uint) külső visszatérések (bool); } szerződés TypeSafeAuction {// jó függvény validateBet (Validator _validator, uint _value) belső visszatér (bool) {bool valid = _validator.validate (_value); érvényes visszaküldés; }} contract TypeUnsafeAuction {// rossz funkció validateBet (cím _addr, uint _value) belső visszatér (bool) {Validator validator = Validator (_addr); bool valid = validator.validate (_value); érvényes visszaküldés; }} Kód nyelve: JavaScript (javascript)

A fenti TypeSafeAuction szerződés használatának előnyei a következő példából láthatók. Ha a validateBet () meghívásra kerül egy cím argumentummal, vagy a Validatortól eltérő szerződéstípussal, a fordító ezt a hibát dobja el:

szerződéses NonValidator {} szerződéses aukció TypeSafeAuction {NonValidator nonValidator; function bet (uint _value) {bool valid = validateBet (nonValidator, _value); // TypeError: Érvénytelen típus az argumentumhoz a függvényhívásban. // Érvénytelen implicit átalakítás a NonValidator szerződésből // szerződésbe Validator kért. }} Kód nyelve: JavaScript (javascript)

Kerülje az extcodesize használatát a külső tulajdonú fiókok ellenőrzésére

A következő módosítót (vagy hasonló ellenőrzést) gyakran alkalmazzák annak ellenőrzésére, hogy egy külső tulajdonú számláról (EOA) vagy szerződéses számláról indítottak-e hívást:

// rossz módosító isNotContract (_a cím) {uint size; assembly {méret: = extcodesize (_a)} igény (méret == 0); _; } Kód nyelve: JavaScript (javascript)

Az ötlet egyértelmű: ha egy cím kódot tartalmaz, akkor az nem EOA, hanem szerződéses számla. azonban, a szerződés nem rendelkezik forráskóddal az építkezés során. Ez azt jelenti, hogy amíg a konstruktor fut, hívásokat kezdeményezhet más szerződésekre, de a címének exkódolása nulla értéket ad vissza. Az alábbiakban bemutatunk egy minimális példát, amely bemutatja, hogyan lehet ezt az ellenőrzést kijátszani:

szerződés csakFOREOA {uint public flag; // rossz módosító isNotContract (_a cím) {uint len; assembly {len: = extcodesize (_a)} igényel (len == 0); _; } function setFlag (uint i) public isNotContract (msg.sender) {flag = i; }} szerződés FakeEOA {konstruktor (_a cím) public {OnlyForEOA c = OnlyForEOA (_a); c.setFlag (1); }} Kód nyelve: JavaScript (javascript)

Mivel a szerződéscímek előre kiszámíthatók, ez az ellenőrzés akkor is kudarcot vallhat, ha egy olyan címet ellenőriz, amely az n blokkban üres, de egy n-nél nagyobb blokknál van telepítve egy szerződés..

Figyelem: Ez a kérdés árnyalt. Ha az a célja, hogy megakadályozza, hogy más szerződések felhívhassák a szerződését, valószínűleg az extcodesize ellenőrzés elegendő. Alternatív megközelítés a (tx.origin == msg.sender) értékének ellenőrzése, bár ez is hátrányai vannak.

Vannak más helyzetek, amikor az extcodesize ellenőrzés az Ön célját szolgálja. Ezek mindegyikének leírása itt kívül esik. Értse meg az EVM mögöttes viselkedését, és használja megítélését.

Biztonságos a Blockchain kódod?

Foglaljon egy napos helyszíni ellenőrzést biztonsági szakértőinknél. Book Yours Today DiligenceSecuritySmart ContractsSolidityNewsletterHírlevélre feliratkozás a legfrissebb Ethereum-hírekről, vállalati megoldásokról, fejlesztői erőforrásokról és egyebekről. E-mail címExkluzív tartalomHogyan készítsünk sikeres blokklánc terméketWebinárium

Hogyan készítsünk sikeres blokklánc terméket

Hogyan állítsunk be és futtassunk Ethereum csomópontotWebinárium

Hogyan állítsunk be és futtassunk Ethereum csomópontot

Hogyan készítsünk saját Ethereum API-tWebinárium

Hogyan készítsünk saját Ethereum API-t

Hogyan hozzunk létre közösségi tokentWebinárium

Hogyan hozzunk létre közösségi tokent

Biztonsági eszközök használata az intelligens szerződés-fejlesztésbenWebinárium

Biztonsági eszközök használata az intelligens szerződés-fejlesztésben

A pénzügyi eszközök digitális eszközei és a DeFi jövőjeWebinárium

A pénzügyek jövője: digitális eszközök és DeFi

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me
Like this post? Please share to your friends:
Adblock
detector
map