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 Érmeajánlat) í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ód mennyiséggel.

1. rész. Előzetes információk

Fontos tervezési döntés egy kriptovaluta protokollban, hogy meghatározzuk, hogy egy költési tranzakció valójában mit költ el. Két lehetőség van itt. Az első egy UTXO-alapú modell, mint a Bitcoinban, ahol egy tranzakció egyszeri eszköz konténereket (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 konténerek, amelyeket dobozoknak neveznek, kerülnek felhasználásra. Érdekes módon, egy Ergo tranzakciónak lehetnek olyan adat-bemenetei 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 script 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őleges komplexitású 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 fogunk meghatározni egy többlépcsős szerződés használatával egy ICO-val, ahol három szakaszunk van (finanszírozás, token kibocsátás, visszavonás).

Most képzeljünk el egy ICO-t, amelyben ezrek vesznek részt. 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 tranzakciónak, amely aktiválja a védő script 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 adathalmazon 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 Érmeajánlathoz (ICO) kapcsolódóan. 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 script, 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 scripteket tartalmazzák. A befektetői scriptek és bemeneti értékek hozzáadódnak 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, ezt követően 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ások, törlések, frissítések, vagy minden művelet 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 token értékekkel, amelyeket a fából vesznek. 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 dobozok sorozatát használják e célok elérésére.

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 védő script segítségével, amelyet az alábbiakban ismertetünk. Ez a szakasz legalább 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 scriptjét, ahogyan azt a következő szakaszban leírjuk (a kisebb magasságú tranzakcióknak ugyanazzal a script-tel 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 script hash-t az R4 regiszterben. Ez a hash képviseli a visszavonási scriptet, amelyet később a visszavonási fázisban fognak használni. A hash-eknek, valamint az összes befektetési bemenet pénzügyi értékének hozzá kell adódnia 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, é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 be fogják foglalni. Í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öltheti 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 script 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 egy ú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ő script-tel, 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 dobozhoz), é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ő script 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ónak tehát N + 2 kimenete van, 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ő scripteket és token értékeket tartalmaz 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 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 a 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.