ICO példa az Ergo tetején

This page is machine-translated.
Alex Chepurnoy

2019. április 10.

Ez a cikk egy teljes funkcionalitású ICO-t (Kezdeti Érmék Kínálata) ír le, amelyet ErgoScript-ben valósítottak meg. A példa számos fontos és új funkciót lefed az Ergo Platformon, és megmutatja, hogyan támogathatja a komplex szerződéseket minimális kódmennyiséggel.

1. rész. Előzetesek

Fontos tervezési döntés egy kriptovaluta protokollban, hogy meghatározzuk, mit költ el egy tranzakció. Két lehetőség van itt. Az első egy UTXO-alapú modell, mint a Bitcoinban, ahol egy tranzakció egyszeri eszközöket (amelyeket 'érméknek' vagy UTXO-knak neveznek a Bitcoinban) költ el, és újakat hoz létre. A másik egy számla-alapú modell, mint a Nxt, Ethereum vagy Waves esetében, ahol egy tranzakció egy meglévő, hosszú életű számláról egy másik, esetleg új, hosszú életű számlára átutal egy bizonyos mennyiségű eszközt, lehetséges mellékhatásokkal, mint például a szerződés végrehajtása a Waves vagy Ethereum esetében. E tekintetben az Ergo hasonló a Bitcoinhoz, mert UTXO-alapú megközelítést alkalmaz, ahol egyszeri tárolók, amelyeket dobozoknak neveznek, kerülnek felhasználásra. Érdekes módon, egy Ergo tranzakciónak lehetnek olyan adatbevételei is, amelyek nem kerülnek felhasználásra, hanem inkább információt szolgáltatnak a jelenlegi, fel nem használt dobozok halmazából.

Nem triviális ICO-t létrehozni egy UTXO-alapú modellen, mert a számla-alapú modellekhez képest itt nincs kifejezett tartós tárolás. Azonban az Ergo egy költési tranzakciót hoz be a szkript végrehajtási kontextusába. Ezzel a kis változtatással lehetővé válik a tranzakciós kimenetek és bemenetek közötti függőségek kifejezése. Viszont a függőségek beállításával akár tetszőlegesen komplex Turing-teljes programokat is végrehajthatunk a blokkláncon (lásd a "Önreprodukáló Érmék, mint Univerzális Turing-gép" cikket). Ebben a cikkben egy konkrét forgatókönyvet definiálunk egy több szakaszból álló szerződéshez ICO használatával, ahol három szakaszunk van (finanszírozás, token kibocsátás, visszavonás).

Most képzeljünk el egy ICO-t, amelyben több ezer résztvevő van. Az Ethereumtól eltérően az Ergo nem biztosít lehetőséget nagy adathalmazonk tárolására és azok átvitelére a szerződés végrehajtása során. Ehelyett csak körülbelül 40 bájt fejléces adatstruktúra tárolására van lehetőség, amely kulcs -> érték szótárként van ábrázolva, hasonlóan a Merkle fához. A szótár egyes elemeinek eléréséhez vagy módosításához egy költési tranzációnak, amely aktiválja a védő szkript végrehajtását, bizonyítékokat kell szolgáltatnia a kereséshez vagy a módosításhoz. Ez lehetőséget ad arra, hogy egy szerződés hitelesítse a potenciálisan hatalmas adathalmazonkat anélkül, hogy sok memóriát igényelne a szerződés állapotának tárolásához. Azonban a tárolási hely a (aktív szerződések) állapotában nagyobb tranzakciókat jelentene, de ez a probléma könnyebb a skálázhatóság szempontjából, és a skálázhatóság kiemelt prioritás az Ergo számára.

2. rész. Az ICO Szerződés

Számos lehetséges forgatókönyv létezhet egy Kezdeti Érmék Kínálatával (ICO) kapcsolatban. Ebben a cikkben egy olyan ICO-t vizsgálunk, amely legalább egy bizonyos összegű forrást (Erg-ben) szeretne gyűjteni a projekt elindításához. Miután a finanszírozási küszöböt átlépték és a finanszírozási időszak véget ér, a projekt elindul, és az ICO tokeneket a projekt bocsátja ki a begyűjtött összes forrás alapján. A visszavonási fázisban, amely örökké tart, a befektetők az ICO tokeneket a finanszírozási időszak alatt befektetett összegük alapján vonják vissza. A szerződés lépéseit röviden az alábbiakban ismertetjük, a részletek később találhatók:

  • Először is, finanszírozási időszak zajlik. Ez egy projekt dobozával kezdődik, amely egy üres szótárat hitelesít. A szótár a (befektető, egyenleg) párok tárolására szolgál, ahol a befektető egy szkript, amely védi a visszavont tokeneket tartalmazó dobozt. Az egyenleg esetében feltételezzük, hogy 1 token egyenlő 1 Ergo-val az ICO alatt. A finanszírozási időszak alatt csak Ergeket lehet elhelyezni a projekt dobozában. Egy finanszírozási tranzakció költi a projekt dobozát, és létrehoz egy új projekt dobozt frissített információkkal. Ehhez a projekt doboz költési tranzakciójának más bemenetei is vannak, amelyek a befektetői visszavonási szkripteket tartalmazzák. A befektetői szkripteket és bemeneti értékeket hozzá kell adni az új doboz fájához. Számos láncolt finanszírozási tranzakció létezhet.
  • Másodszor, a finanszírozási időszak véget ér, ezután a befektetők adatait tartalmazó fa csak olvashatóvá válik. Egy hitelesített fa különböző módosítási műveleteket engedhet meg egyedileg: beszúrásokat, törléseket, frissítéseket, vagy minden műveletet megtilthat (így a fa olvasható módban lehet). Ezenkívül ez a tranzakció létrehozza az ICO projekt tokenjeit, amelyeket a következő szakaszban fognak visszavonni. A projekt ezen a szakaszon Ergeket vonhat vissza.
  • Harmadszor, a befektetők visszavonják ICO tokenjeiket. Ehhez egy költési tranzakció kimeneteket hoz létre védő feltételekkel és a fából származó token értékekkel. A visszavont párokat szintén törlik a fából. Számos láncolt költési tranzakció létezhet.

E három szakasznak logikai sorrendben kell összekapcsolódnia. A célok eléréséhez dobozok sorozatát használják.

3. rész. Az ICO Szerződés Részletei

Most itt az ideje, hogy részleteket és ErgoScript kódot adjunk meg az ICO szerződés szakaszairól.

A Finanszírozási Szakasz

A finanszírozási szakaszban, amely az első, feltételezzük, hogy kezdetben egy projekt létrehoz egy dobozt, amely egy üres szótárra kötelezi magát (az R5 regiszterben tárolva) egy alább leírt védő szkripttel. Ez a szakasz legalább a 2000-es magasságig tart. Konkrétabban, az első tranzakciónak, amelynek magassága 2000 vagy annál nagyobb, meg kell változtatnia a kimeneti doboz szkriptjét, ahogyan a következő szakaszban leírtuk (a kisebb magasságú tranzakcióknak ugyanazzal a szkripttel kell kimeneti dobozt létrehozniuk).

A projekt doboza ellenőrzi, hogy mindig az első bemenet és kimenet egy tranzakcióban. A többi bemenet a befektetők bemeneteinek számít. A befektető bemenete tartalmazza egy szkript hash-ét az R4 regiszterben. Ez a hash képviseli a visszavonási szkriptet, amelyet később a visszavonási fázisban fognak használni. A hash-eket, valamint az összes befektetési bemenet pénzügyi értékeit hozzá kell adni a szótárhoz. A költési tranzakció bizonyítékot szolgáltat arra, hogy a befektetői adatok valóban hozzá lettek adva a szótárhoz, és a bizonyítékot a szerződésben ellenőrzik.

A finanszírozási al-szerződésben nem ellenőrzik, hogy a szótár csak beszúrásokat engedélyez, és nem frissítéseket vagy eltávolításokat (azonban nem nehéz egy kifejezett ellenőrzést hozzáadni).

A költési tranzakciónak díjat kell fizetnie, különben valószínűtlen, hogy egy blokkba kerül. Így a finanszírozási szerződés ellenőrzi, hogy a költési tranzakciónak két kimenete van (az egyik saját magának, a másik a díj kifizetésére), a díjnak nem szabad meghaladnia egy bizonyos határt (például egy nanoErg a példánkban), és a védő javaslatnak olyannak kell lennie, hogy csak egy bányász költhesse el a kimenetet (a példánkban csak egy "feeProp" változót használunk a fordítási környezetből, részletek megadása nélkül). Ez a "feeProp" egy szabványhoz tartozik, bár a protokoll által nem kötelező.

Az alábbi kód érvényesíti a fent leírt feltételeket. Kérjük, vegye figyelembe, hogy a
"nextStageScriptHash" környezeti változó a kibocsátási szakasz sorozatban tárolt szkript hash-ét tartalmazza.

    val selfIndexIsZero = INPUTS(0).id == SELF.id

    val proof = getVar[Coll[Byte]](1).get

    val inputsCount = INPUTS.size

    val toAdd: Coll[(Coll[Byte], Coll[Byte])] = INPUTS.slice(1, inputsCount).map({ (b: Box) =>
        val pk = b.R4[Coll[Byte]].get
        val value = longToByteArray(b.value)
        (pk, value)
    })

    val modifiedTree = SELF.R5[AvlTree].get.insert(toAdd, proof).get

    val expectedTree = OUTPUTS(0).R5[AvlTree].get

    val properTreeModification = modifiedTree == expectedTree

    val outputsCount = OUTPUTS.size == 2

    val selfOutputCorrect = if(HEIGHT < 2000) {
        OUTPUTS(0).propositionBytes == SELF.propositionBytes
    } else {
        blake2b256(OUTPUTS(0).propositionBytes) == nextStageScriptHash
    }

    val feeOutputCorrect = (OUTPUTS(1).value <= 1) && (OUTPUTS(1).propositionBytes == feeBytes)

    val outputsCorrect = outputsCount && feeOutputCorrect && selfOutputCorrect

    selfIndexIsZero && outputsCorrect && properTreeModification

A Kibocsátási Szakasz

Ennek a szakasznak csak egy költési tranzakciója van, hogy eljusson a következő szakaszba (a visszavonási szakaszba). A költési tranzakció a következő módosításokat végzi. Először is, megváltoztatja a szótáron engedélyezett műveletek listáját "csak beszúrások"-ról "csak eltávolítások"-ra, mivel a következő szakasz (visszavonás) csak a szótárból való bejegyzések eltávolításával foglalkozik.

Másodszor, a szerződés ellenőrzi, hogy a megfelelő mennyiségű ICO token került kibocsátásra. Az Ergo-ban engedélyezett, hogy tranzakciónként egy új típusú tokent bocsássanak ki, és a token azonosítójának meg kell egyeznie az első bemeneti doboz (egyedi) azonosítójával. A kibocsátási al-szerződés ellenőrzi, hogy új token került kibocsátásra, és annak mennyisége megegyezik az ICO által eddig összegyűjtött nanoErg mennyiségével.

Harmadszor, a szerződés ellenőrzi, hogy a költési tranzakció valóban újra létrehozza a dobozt a következő szakaszhoz tartozó védő szkripttel, a visszavonási szakaszhoz.

Végül a projektnek vissza kell vonnia a begyűjtött Ergeket, és természetesen minden költési tranzakciónak díjat kell fizetnie. Így az al-szerződés ellenőrzi, hogy a költési tranzakciónak valóban 3 kimenete van (egy-egy a projekt token dobozához, az Ergek visszavonásához és a díj dobozához), és hogy az első kimenet a kibocsátott tokeneket hordozza. Mivel nem határozzuk meg a projekt pénzének visszavonásának részleteit, megköveteljük a projekt aláírását a költési tranzakción.

    val openTree = SELF.R5[AvlTree].get
    
    val closedTree = OUTPUTS(0).R5[AvlTree].get
    
    val digestPreserved = openTree.digest == closedTree.digest
    val keyLengthPreserved = openTree.keyLength == closedTree.keyLength
    val valueLengthPreserved = openTree.valueLengthOpt == closedTree.valueLengthOpt
    val treeIsClosed = closedTree.enabledOperations == 4
    
    val tokenId: Coll[Byte] = INPUTS(0).id
    
    val tokensIssued = OUTPUTS(0).tokens(0)._2
    
    val outputsCountCorrect = OUTPUTS.size == 3
    val secondOutputNoTokens = OUTPUTS(0).tokens.size == 1 && OUTPUTS(1).tokens.size == 0 && OUTPUTS(2).tokens.size == 0
    
    val correctTokensIssued = SELF.value == tokensIssued
    
    val correctTokenId = OUTPUTS(0).R4[Coll[Byte]].get == tokenId && OUTPUTS(0).tokens(0)._1 == tokenId
    
    val valuePreserved = outputsCountCorrect && secondOutputNoTokens && correctTokensIssued && correctTokenId
    val stateChanged = blake2b256(OUTPUTS(0).propositionBytes) == nextStageScriptHash
    
    val treeIsCorrect = digestPreserved && valueLengthPreserved && keyLengthPreserved && treeIsClosed
    
    projectPubKey && treeIsCorrect && valuePreserved && stateChanged

A Visszavonási Szakasz

Ebben a szakaszban a befektetők jogosultak a projekt tokenjeinek visszavonására, amelyeket egy előre meghatározott védő szkript véd (amelynek hash-e a szótárban van tárolva). Tegyük fel, hogy a visszavonás N méretű tételekben történik. Egy visszavonási tranzakció tehát N + 2 kimenettel rendelkezik, ahol az első kimenet a visszavonási al-szerződést és az egyenleg tokenjeit hordozza, az utolsó kimenet a díjat fizeti, és a fennmaradó N kimenet védő szkriptekkel és token értékekkel rendelkezik a szótár szerint. A szerződés két bizonyítékot követel meg a szótár elemeihez: az egyik bizonyítja, hogy a visszavonásra szánt értékek valóban a szótárban vannak, a második pedig azt bizonyítja, hogy az eredményül kapott szótár nem tartalmazza a visszavont értékeket. Az al-szerződés az alábbiakban található.

    val removeProof = getVar[Coll[Byte]](2).get
    val lookupProof = getVar[Coll[Byte]](3).get
    val withdrawIndexes = getVar[Coll[Int]](4).get

    val out0 = OUTPUTS(0)

    val tokenId: Coll[Byte] = SELF.R4[Coll[Byte]].get

    val withdrawals = withdrawIndexes.map({(idx: Int) =>
        val b = OUTPUTS(idx)
        if(b.tokens(0)._1 == tokenId) {
            (blake2b256(b.propositionBytes), b.tokens(0)._2)
        } else {
            (blake2b256(b.propositionBytes), 0L)
        }
    })

    val withdrawValues = withdrawals.map({(t: (Coll[Byte], Long)) => t._2})

    val withdrawTotal = withdrawValues.fold(0L, { (l1: Long, l2: Long) => l1 + l2 })

    val toRemove = withdrawals.map({(t: (Coll[Byte], Long)) => t._1})

    val initialTree = SELF.R5[AvlTree].get

    val removedValues = initialTree.getMany(toRemove, lookupProof).map({(o: Option[Coll[Byte]]) => byteArrayToLong(o.get)})
    val valuesCorrect = removedValues == withdrawValues

    val modifiedTree = initialTree.remove(toRemove, removeProof).get

    val expectedTree = out0.R5[AvlTree].get

    val selfTokensCorrect = SELF.tokens(0)._1 == tokenId
    val selfOutTokensAmount = SELF.tokens(0)._2
    val soutTokensCorrect = out0.tokens(0)._1 == tokenId
    val soutTokensAmount = out0.tokens(0)._2

    val tokensPreserved = selfTokensCorrect && soutTokensCorrect && (soutTokensAmount + withdrawTotal == selfOutTokensAmount)

    val properTreeModification = modifiedTree == expectedTree

    val selfOutputCorrect = out0.propositionBytes == SELF.propositionBytes

    properTreeModification && valuesCorrect && selfOutputCorrect && tokensPreserved

Lehetséges Fejlesztések

Kérjük, vegye figyelembe, hogy sok árnyalatot figyelmen kívül hagy a példaszerződésünk. Például bárki, aki figyeli a blokkláncot, jogosult a szerződés végrehajtására és megfelelő költési tranzakciók létrehozására a finanszírozási és visszavonási szakaszok során. A valóságban a projekttől vagy egy megbízható döntőbíróval további aláírás is használható.

Ezenkívül a visszavonási szerződésben nem szerepel önmegsemmisítési eset, így az évtizedekig vagy akár évszázadokig is élhet, amíg a bányászok általi tárolási bérleti mechanizmus révén el nem pusztítják. A finanszírozási szakaszban ésszerű lenne, ha a projekt egy további bemenetet adna meg, amelynek értéke megegyezik a díj kimenetének értékével. És így tovább.

Share post

Ergo Infrastructure DAO: Az Ergo Ökoszisztéma Gerincének Decentralizálása

Ergo Infrastructure DAO: Az Ergo Ökoszisztéma Gerincének Decentralizálása

Az Ergo küldetése mindig is a decentralizáción alapult, nemcsak a konszenzus rétegén, hanem az egész stack-en.

Ergo Platform

2025. augusztus 13.

Mew Finance: Egy Játékos DeFi Eszközkészlet az Ergo Ökoszisztémához

Mew Finance: Egy Játékos DeFi Eszközkészlet az Ergo Ökoszisztémához

A Mew Finance egy decentralizált alkalmazáscsomag az Ergo Blockchain-en.

Ergo Platform

2025. augusztus 12.

Lithos: A Bányászat Decentralizálása On-Chain Poolokkal

Lithos: A Bányászat Decentralizálása On-Chain Poolokkal

A Lithos egy új protokoll, amely a bányászati poolok működésének átalakítására készült azáltal, hogy azokat on-chain helyezi, telj.

Ergo Platform

2025. július 24.

Sigma 6.0: Egy Okosabb, Rugalmasabb Ergo

Sigma 6.0: Egy Okosabb, Rugalmasabb Ergo

Sigma 6.0 egy jelentős javasolt frissítés az Ergo blokklánc számára.

Ergo Platform

2025. július 23.

Rosen Jövőjének Formálása: Közösségi Felhívás Öt Kulcsfontosságú Kincstári Javaslatra

Rosen Jövőjének Formálása: Közösségi Felhívás Öt Kulcsfontosságú Kincstári Javaslatra

A Rosen társalapítója, Armeanio, öt új javaslatot nyújtott be a Rosen Kincstárhoz.

Ergo Platform

2025. július 9.

Ergo kibővített UTXO-ja és a mesterséges gazdasági intelligencia felemelkedése

Ergo kibővített UTXO-ja és a mesterséges gazdasági intelligencia felemelkedése

Gyakorlati vízió az autonóm gazdasági ügynökök számára Az autonóm gazdasági ügynökök az Ergo blokkláncon hasznos munkát végeznek .

Ergo Platform

2025. május 12.

ErgoHACK X: Mesterséges Intelligencia az Ergo Blockchain-en

ErgoHACK X: Mesterséges Intelligencia az Ergo Blockchain-en

Ünnepeljük a Decentralizált Innováció Egy Évtizedét Csatlakozz a 10.

Ergo Platform

2025. április 10.