Um Exemplo de ICO em Cima do Ergo

This page is machine-translated.
Alex Chepurnoy

10 de abril de 2019

Este artigo descreve uma ICO (Oferta Inicial de Moedas) totalmente funcional implementada em ErgoScript. O exemplo abrange várias características importantes e novas da Plataforma Ergo e mostra como ela pode suportar contratos complexos com uma quantidade mínima de código.

Parte 1. Preliminares

Uma decisão de design importante em um protocolo de criptomoeda é especificar o que uma transação de gasto realmente gasta. Existem duas possibilidades aqui. A primeira é um modelo baseado em UTXO, como no Bitcoin, onde uma transação gasta contêineres de ativos de uso único (chamados de 'moedas' ou UTXOs no Bitcoin) e cria novos. A outra é um modelo baseado em contas, como no Nxt, Ethereum ou Waves, onde uma transação transfere uma certa quantidade de ativos de uma conta existente de longa duração para outra, possivelmente nova, conta de longa duração, com possíveis efeitos colaterais no caminho, como execução de contrato em Waves ou Ethereum. Nesse sentido, o Ergo é semelhante ao Bitcoin, porque usa a abordagem baseada em UTXO, onde contêineres de uso único chamados boxes estão sendo gastos. Curiosamente, uma transação Ergo também pode ter entradas de dados que não estão sendo gastas, mas sim usadas para fornecer algumas informações do conjunto atual de boxes não gastos.

Não é trivial criar uma ICO em cima de um modelo baseado em UTXO, porque, ao contrário dos modelos baseados em contas, não há armazenamento persistente explícito aqui. No entanto, o Ergo traz uma transação de gasto para o contexto de execução de um script.
Com essa pequena mudança, torna-se possível expressar dependências entre saídas e entradas de transação. Por sua vez, ao definir dependências, podemos executar até mesmo programas Turing-completos arbitrariamente complexos em cima da blockchain (veja o artigo "Moedas Auto-reproduzíveis como Máquina de Turing Universal"). Neste artigo, definiremos um cenário concreto de um contrato de múltiplas etapas usando uma ICO, onde temos três etapas (financiamento, emissão de tokens, retirada).

Agora imagine uma ICO para milhares de participantes. Ao contrário do Ethereum, o Ergo não fornece a possibilidade de armazenar grandes conjuntos de dados e transportá-los ao longo da execução do contrato. Em vez disso, permite armazenar apenas cerca de 40 bytes de cabeçalho de uma estrutura de dados, representada como um dicionário chave -> valor, autenticado de forma semelhante a uma árvore de Merkle. Para acessar alguns elementos no dicionário, ou para modificá-lo, uma transação de gasto que está acionando a execução do script de proteção deve fornecer provas de busca ou modificação. Isso dá a possibilidade de um contrato autenticar conjuntos de dados potencialmente enormes sem exigir muita memória para armazenar o estado do contrato. No entanto, armazenar espaço no estado (de contratos ativos) significaria transações maiores, mas esse problema é mais fácil do ponto de vista da escalabilidade, e a escalabilidade é uma prioridade máxima para o Ergo.

Parte 2. O Contrato ICO

Podem existir muitos cenários possíveis associados a uma Oferta Inicial de Moedas (ICO). Neste artigo, consideramos uma ICO que deseja coletar pelo menos uma certa quantia de fundos (em Ergs) para iniciar o projeto. Uma vez que o limite de financiamento é ultrapassado e o período de financiamento termina, o projeto é iniciado e os tokens ICO são emitidos pelo projeto com base no total de financiamento coletado. Na fase de retirada, que se estende para sempre, os investidores retiram tokens ICO com base na quantia que investiram durante o período de financiamento. As etapas do contrato são brevemente descritas abaixo, com detalhes fornecidos a seguir:

  • Primeiro, ocorre a época de financiamento. Ela começa com uma box do projeto autenticando um dicionário vazio. O dicionário é destinado a manter pares (investidor, saldo), onde o investidor é um script que protege a box contendo tokens retirados. Para o saldo, assumimos que 1 token é igual a 1 Ergo durante a ICO. Durante a época de financiamento, é possível apenas colocar Ergs na box do projeto.
    Uma transação de financiamento gasta a box do projeto e cria uma nova box do projeto com informações atualizadas. Para isso, uma transação de gasto para a box do projeto também tem outras entradas que contêm scripts de retirada do investidor. Scripts de investidor e valores de entrada devem ser adicionados à árvore da nova box. Podem haver muitas transações de financiamento encadeadas.
  • Em segundo lugar, o período de financiamento termina, após o qual a árvore que contém os dados dos investidores se torna somente leitura. Uma árvore autenticada pode ter diferentes operações de modificação permitidas individualmente: inserções, exclusões, atualizações, ou todas as operações podem ser proibidas (então a árvore pode estar no modo somente leitura). Além disso, essa transação cria tokens do projeto ICO que serão retirados na próxima etapa. O projeto pode retirar Ergs nesta etapa.
  • Em terceiro lugar, os investidores retiram seus tokens ICO. Para isso, uma transação de gasto cria saídas com condições de proteção e valores de tokens retirados da árvore. Os pares retirados também são removidos da árvore. Podem haver muitas transações de gasto encadeadas.

Essas três etapas devem ser vinculadas em ordem lógica. Uma sequência de boxes é usada para alcançar esses objetivos.

Parte 3. Detalhes do Contrato ICO

Agora é hora de fornecer detalhes e código ErgoScript das etapas do contrato ICO.

A Etapa de Financiamento

Na etapa de financiamento, que vem primeiro, assumimos que inicialmente um projeto cria uma box comprometendo-se a um dicionário vazio (armazenado no registro R5) com um script de proteção descrito abaixo. Esta etapa dura pelo menos até a altura 2.000. Mais concretamente, a primeira transação com altura de 2.000 ou mais deve alterar o script da box de saída conforme descrito na próxima seção (transações em alturas mais baixas devem produzir uma box com o mesmo script).

A box do projeto verifica se é sempre a primeira entrada e saída de uma transação. As outras entradas são consideradas entradas dos investidores. A entrada de um investidor contém o hash de um script no registro R4. Esse hash representa o script de retirada que será usado mais tarde na fase de retirada. Os hashes, assim como os valores monetários de todas as entradas de investimento, devem ser adicionados ao dicionário. A
transação de gasto fornece uma prova de que os dados do investidor foram de fato adicionados ao dicionário, e a prova é verificada no contrato.

Não é verificado no subcontrato de financiamento que o dicionário permite apenas inserções, e não atualizações de valores existentes ou remoções (não é difícil adicionar uma verificação explícita, no entanto).

A transação de gasto deve pagar uma taxa, caso contrário, é improvável que seja incluída em um bloco. Assim, o contrato de financiamento verifica se a transação de gasto tem duas saídas (uma para si mesma, outra para pagar a taxa), a taxa não deve ser superior a um certo limite (apenas um nanoErg em nosso exemplo), e a proposição de proteção deve ser tal que apenas um minerador possa gastar a saída (usamos apenas uma variável "feeProp" do ambiente de compilação em nosso exemplo sem fornecer detalhes). Essa "feeProp" corresponde a um padrão, embora não exigido pelo protocolo.

O código abaixo impõe as condições descritas acima. Observe que a
variável de ambiente "nextStageScriptHash" contém o hash do script da etapa de emissão serializado.

    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 Etapa de Emissão

Esta etapa tem apenas uma transação de gasto para chegar à próxima etapa (a etapa de retirada). As transações de gasto fazem as seguintes modificações. Primeiro, ela altera a lista de operações permitidas no dicionário de "apenas inserções" para "apenas remoções", já que a próxima etapa (retirada) lida apenas com a remoção de entradas do dicionário.

Em segundo lugar, o contrato verifica se a quantidade adequada de tokens ICO foi emitida. No Ergo, é permitido emitir um novo tipo de token por transação, e o identificador do token deve ser igual ao identificador (único) da primeira box de entrada. O subcontrato de emissão verifica se um novo token foi emitido, e a quantidade dele é igual à quantidade de nanoErgs coletados pela ICO até agora.

Em terceiro lugar, o contrato verifica se uma transação de gasto está realmente recriando a box com o script de proteção correspondente à próxima etapa, a etapa de retirada.

Finalmente, o projeto deve retirar os Ergs coletados, e, claro, cada transação de gasto deve pagar uma taxa. Assim, o subcontrato verifica se a transação de gasto tem de fato 3 saídas (uma para cada box de tokens do projeto, a box de retirada de Ergs e a box de taxa), e que a primeira saída e saída estão carregando os tokens emitidos. Como não especificamos os detalhes da retirada de dinheiro do projeto, exigimos uma assinatura do projeto na transação de gasto.

    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 Etapa de Retirada

Nesta etapa, os investidores são autorizados a retirar tokens do projeto protegidos por um script de guarda pré-definido (cujo hash é armazenado no dicionário). Digamos que a retirada é feita em lotes de tamanho N. Uma transação de retirada, portanto, tem N + 2 saídas, onde a primeira saída carrega o subcontrato de retirada e tokens de saldo, a última saída paga a taxa e as N saídas restantes têm scripts de proteção e valores de tokens de acordo com o dicionário. O contrato requer duas provas para os elementos do dicionário: uma provando que os valores a serem retirados estão de fato no dicionário, e a segunda provando que o dicionário resultante não possui os valores retirados. O subcontrato está abaixo.

    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

Possíveis Melhorias

Observe que existem muitas nuances que nosso contrato de exemplo está ignorando. Por exemplo, qualquer um que escute a blockchain está autorizado a executar o contrato e construir transações de gasto adequadas durante as etapas de financiamento e retirada. No mundo real, uma assinatura adicional do projeto ou de um árbitro confiável pode ser usada.

Além disso, não há caso de autodestruição considerado no contrato de retirada, então ele viverá até ser destruído por mineradores via mecanismo de aluguel de armazenamento, potencialmente por décadas ou até séculos. Para a etapa de financiamento, seria razoável ter uma entrada adicional do projeto com o valor igual ao valor da saída de taxa. E assim por diante.

Share post

Ergo Infrastructure DAO: Descentralizando a Espinha Dorsal do Ecossistema Ergo

Ergo Infrastructure DAO: Descentralizando a Espinha Dorsal do Ecossistema Ergo

A missão da Ergo sempre foi enraizada na descentralização, não apenas na camada de consenso, mas em toda a pilha.

Ergo Platform

13 de agosto de 2025

Mew Finance: Um Conjunto de Ferramentas DeFi Divertido para o Ecossistema Ergo

Mew Finance: Um Conjunto de Ferramentas DeFi Divertido para o Ecossistema Ergo

Mew Finance é um conjunto de aplicativos descentralizados na Blockchain Ergo.

Ergo Platform

12 de agosto de 2025

Lithos: Descentralizando a Mineração com Pools On-Chain

Lithos: Descentralizando a Mineração com Pools On-Chain

Lithos é um novo protocolo projetado para reformular como os pools de mineração funcionam, movendo-os para on-chain, dando aos min.

Ergo Platform

24 de julho de 2025

Sigma 6.0: Um Ergo Mais Inteligente e Flexível

Sigma 6.0: Um Ergo Mais Inteligente e Flexível

Sigma 6.0 é uma grande atualização proposta para a blockchain Ergo.

Ergo Platform

23 de julho de 2025

Moldando o Futuro de Rosen: Uma Chamada da Comunidade sobre Cinco Propostas Chave do Tesouro

Moldando o Futuro de Rosen: Uma Chamada da Comunidade sobre Cinco Propostas Chave do Tesouro

O co-fundador da Rosen, Armeanio, apresentou cinco novas propostas ao Tesouro de Rosen.

Ergo Platform

9 de julho de 2025

UTXO Estendido da Ergo e a Ascensão da Inteligência Econômica Artificial

UTXO Estendido da Ergo e a Ascensão da Inteligência Econômica Artificial

Uma Visão Prática para Agentes Econômicos Autônomos Agentes econômicos autônomos na blockchain da Ergo realizam trabalho útil em .

Ergo Platform

12 de maio de 2025

ErgoHACK X: Inteligência Artificial na Blockchain Ergo

ErgoHACK X: Inteligência Artificial na Blockchain Ergo

Celebrando uma Década de Inovação Descentralizada Participe do 10º aniversário do ErgoHACK e esteja na vanguarda da revolução da I.

Ergo Platform

10 de abril de 2025

Ergo Pulse com Charles Hoskinson

Ergo Pulse com Charles Hoskinson

“Quando olhamos para as coisas que Alex tem feito, a equipe tem feito e a comunidade tem feito, eles são logicamente consistentes .

Plataforma Ergo

13 de abril de 2022

Mais novo mercado de NFTs em Ergo está ganhando a atenção dos Ergonautas

Mais novo mercado de NFTs em Ergo está ganhando a atenção dos Ergonautas

Em Outubro de 2020, NFTs na blockchain Ergo foram lançados.

Plataforma Ergo

7 de abril de 2022

NIPoPoWs em Ergo: Inovações em Blockchain

NIPoPoWs em Ergo: Inovações em Blockchain

A blockchain Ergo está rapidamente se tornando conhecida dentro do espaço cripto como uma líder em desenvolvimento e inovação em b.

Plataforma Ergo

1 de abril de 2022

Prova de Trabalho, Energia e Ergo

Prova de Trabalho, Energia e Ergo

Introdução Prova de Trabalho (PoW, em Inglês) foi descrita no artigo original de Bitcoin como sendo composta de duas partes.

Plataforma Ergo

29 de março de 2022

Armazenando Ergo: SAFEW

Armazenando Ergo: SAFEW

Neste artigo, continuamos nossa série de guias para configurar e usar uma das muitas novas carteiras Ergo.

Plataforma Ergo

25 de março de 2022

Minerando Ergo no Windows

Minerando Ergo no Windows

Minerar Ergo como parte de uma pool de mineração é fácil, particularmente no Windows.

Plataforma Ergo

17 de março de 2022

What is a DAO (Decentralized Autonomous Organization)?

What is a DAO (Decentralized Autonomous Organization)?

Introduction A decentralized autonomous organization (DAO) is a new type of cooperative.

Ergo Platform

15 de março de 2022

Instruções: Cunhando um Token Não-Fungível (NFT) na Blockchain Ergo

Instruções: Cunhando um Token Não-Fungível (NFT) na Blockchain Ergo

O que é um NFT? Qualquer unidade de uma moeda corrente, como por exemplo o dólar estadunidense, é indistinguível de qualquer outr.

Plataforma Ergo

8 de março de 2022

Blockchain e a Motivação para Ergo

Blockchain e a Motivação para Ergo

Desde o nascimento de Bitcoin, tecnologia blockchain tem sofrido enormes avanços.

Plataforma Ergo

3 de março de 2022

Resultados do ErgoHack III

Resultados do ErgoHack III

Após um bem-sucedido ErgoHack III, o júri tomou sua decisão final! Há tantos projetos maravilhosos que participaram neste último.

Fundação Ergo

1 de março de 2022

A Adoção de Moedas Estáveis está no Horizonte?

A Adoção de Moedas Estáveis está no Horizonte?

Hoje, moedas estáveis lastreadas ao dólar americano (USD) somam quase U$185 bilhões de valor de mercado - um aumento de 500% des.

Plataforma Ergo

24 de fevereiro de 2022

DeFi em Ergo: Taxas usando Tokens Personalizados

DeFi em Ergo: Taxas usando Tokens Personalizados

Moedas de infraestrutura são importantes pois precisamos delas para pagas taxas de transações quando usamos sistemas financeiros.

Plataforma Ergo

22 de fevereiro de 2022

Explicativo Ergo: Aluguel de Armazenamento

Explicativo Ergo: Aluguel de Armazenamento

Resumo do Artigo: Aluguel de Armazenamento é uma taxa por armazenamento de longo prazo na blockchain Ergo.

Plataforma Ergo

18 de fevereiro de 2022

Uma Introdução a Privacidade e Segurança em Blockchain

Uma Introdução a Privacidade e Segurança em Blockchain

Depois que o primeiro artigo científico emergiu na internet em 2008, a tecnologia blockchain evoluiu tremendamente.

Plataforma Ergo

17 de fevereiro de 2022