Um Sistema de Troca Local de Créditos em Cima do Ergo
22 de abril de 2019

Um sistema de troca local de créditos (LETS) é uma associação local de crédito mútuo onde os membros podem criar dinheiro de crédito comum individualmente, com todos os negócios no sistema registrados em um livro-razão comum. Como exemplo, suponha que Alice, com saldo zero, esteja disposta a comprar um litro de leite cru de Bob. Primeiro, eles concordam com um preço, por exemplo, suponha que o preço seja cerca de 2 Euros (já que Alice e Bob vivem na Irlanda). Após o negócio ser registrado em um livro-razão, o saldo de Alice se torna -2 (menos dois) Euros, e o saldo de Bob se torna 2 Euros. Então, Bob pode gastar seus 2 Euros, por exemplo, em cerveja caseira de Charlie. Muitas vezes, tais sistemas impõem limites em saldos negativos e, às vezes, até mesmo em positivos, para promover a troca na comunidade.
Historicamente, tais sistemas se tornaram populares durante períodos de crise. O primeiro sistema foi estabelecido por Michael Linton em uma cidade canadense presa em depressão em 1981. Sistemas de troca local de créditos foram extremamente populares durante a Grande Depressão Argentina de 1998-2002. A maioria dos grupos LETS varia de 50 a 250 membros, com notas de crédito em papel e livro-razão mantido por um comitê central. No entanto, as moedas LETS baseadas em papel mostraram alguns problemas, como notas falsificadas, possível comportamento desonesto de gerentes do sistema, e assim por diante. Portanto, LETS baseados em blockchain poderiam ser superiores aos antigos sistemas. Mais informações sobre LETS podem ser encontradas no "The Ecology of Money" livro (de Richard Douthwaite) e na Wikipedia.
Neste artigo, mostramos como LETS poderia ser implementado em cima do Ergo. Até onde sabemos, esta é a primeira implementação desse tipo de moeda comunitária em cima de uma blockchain. Nossa implementação de referência é simples e consiste em dois contratos, a saber, um contrato de gestão e um contrato de troca. Pulamos as preliminares do Ergo, então, por favor, leia o artigo ICO e os tutoriais de ErgoScript (básico e avançado) para iniciantes. No entanto, vamos introduzir alguns novos termos nas frases seguintes. Se um token é emitido com um valor igual a um, chamamos isso de token singleton. Da mesma forma, uma caixa que contém o token singleton é chamada de caixa singleton.
O contrato de gestão controla uma caixa singleton que contém os membros do sistema LETS. O contrato permite a adição de novos membros na proporção de um membro por transação. A caixa não armazena membros, mas apenas um pequeno resumo de uma estrutura de dados autenticada construída em cima do diretório dos membros. Um membro está associado a um token singleton emitido em uma transação que está adicionando o membro ao diretório. A transação cria uma nova caixa de membro que contém o token singleton do membro. A caixa do membro é protegida pelo contrato de troca. Além disso, a nova caixa de membro criada tem um saldo inicial registrado no registro R4, e o saldo é igual a zero em nosso exemplo. A transação que cria um novo membro deve fornecer uma prova de correção para a transformação do diretório.
A caixa do contrato de gestão é controlada geralmente por um comitê, e o comitê pode evoluir ao longo do tempo. Para apoiar isso, permitimos que a lógica do comitê resida no registro R5. Por exemplo, suponha que um novo membro do comitê tenha sido adicionado junto com um novo membro do LETS, a caixa de contrato de gestão de entrada requer 2 de 3 assinaturas, e a caixa de saída requer 3 de 4 assinaturas. Nesse caso, o conteúdo do registro R5 na caixa de entrada e na caixa de saída diferiria.
O código do contrato de gestão em ErgoScript com comentários é fornecido abaixo. Por favor, note que "userContractHash" se refere ao hash do contrato de troca.
val selfOut = OUTPUTS(0)
// Script de gestão
val managementScript = selfOut.R5[SigmaProp].get
// O template do script de gestão está replicando a si mesmo, e o script de gestão é satisfeito
val scriptCorrect = (selfOut.propositionBytes == SELF.propositionBytes) && managementScript
// Uma transação de gasto está criando caixas para diretório, usuário, taxa.
val outsSizeCorrect = OUTPUTS.size == 3
// Verifica se o token de rótulo de gestão está replicando a si mesmo
val outTokenCorrect = (selfOut.tokens.size == 1) && (selfOut.tokens(0)._1 == letsToken)
// Verifica se um novo token foi emitido, e seu valor está correto
// OUTPUTS(0) tokens já verificados via outtokenCorrect
val issuedTokenId = INPUTS(0).id
val userOut = OUTPUTS(1)
val correctTokenAmounts =
(userOut.tokens.size == 1 &&
userOut.tokens(0)._1 == issuedTokenId &&
userOut.tokens(0)._2 == 1 &&
OUTPUTS(2).tokens.size == 0 &&
outTokenCorrect)
// Verifica se o novo usuário foi criado com saldo zero
val zeroUserBalance = userOut.R4[Long].get == 0
val properUserScript = blake2b256(userOut.propositionBytes) == userContractHash
// Verifica se o novo identificador de token foi adicionado ao diretório
val selfTree = SELF.R4[AvlTree].get
val toAdd: Coll[(Coll[Byte], Coll[Byte])] = Coll((issuedTokenId, Coll[Byte]()))
val proof = getVar[Coll[Byte]](1).get
val modifiedTree = selfTree.insert(toAdd, proof).get
val expectedTree = selfOut.R4[AvlTree].get
val treeCorrect = modifiedTree == expectedTree
correctTokenAmounts && scriptCorrect && treeCorrect && zeroUserBalance && properUserScript
correctTokenAmounts && scriptCorrect && treeCorrect && zeroUserBalance && properUserScript correctTokenAmounts && scriptCorrect && treeCorrect && zeroUserBalance && properUserScript
O script do contrato de troca é bastante direto e fornecido abaixo junto com comentários descrevendo sua lógica. No contrato, assume-se que uma transação de gasto para uma caixa de contrato de troca está recebendo pelo menos duas entradas, e as duas primeiras entradas devem ser protegidas pelo script do contrato de troca e conter tokens de membros do LETS. Para verificar que os tokens de membros singleton nas entradas realmente pertencem ao sistema LETS, uma transação de gasto fornece a caixa do contrato de gestão como a primeira entrada de dados somente leitura e também deve fornecer uma prova de que os tokens de membros pertencem ao diretório autenticado via o registro R4 da caixa do contrato de gestão. "letsToken" no script se refere ao token singleton da caixa de gestão.
// Saldo mínimo permitido para comerciante LETS
val minBalance = -20000
val lookupProof = getVar[Coll[Byte]](1).get
// A caixa somente leitura que contém o diretório de membros do LETS
val treeHolderBox = CONTEXT.dataInputs(0)
val properLetsToken = treeHolderBox.tokens(0)._1 == letsToken
val membersTree = treeHolderBox.R4[AvlTree].get
// Uma transação de gasto está pegando duas caixas de membros do LETS dispostos a fazer um negócio,
// e retorna caixas com saldos modificados.
val participant0 = INPUTS(0)
val participant1 = INPUTS(1)
val participantOut0 = OUTPUTS(0)
val participantOut1 = OUTPUTS(1)
// Verifica se os membros realmente pertencem ao LETS
val token0 = participant0.tokens(0)._1
val token1 = participant1.tokens(0)._1
val memberTokens = Coll(token0, token1)
val membersExist = membersTree.getMany(memberTokens, lookupProof).forall({ (o: Option[Coll[Byte]]) => o.isDefined })
// Verifica se as mudanças de saldo dos membros do LETS durante o negócio estão corretas
val initialBalance0 = participant0.R4[Long].get
val initialBalance1 = participant1.R4[Long].get
val finishBalance0 = participantOut0.R4[Long].get
val finishBalance1 = participantOut1.R4[Long].get
val diff0 = finishBalance0 - initialBalance0
val diff1 = finishBalance1 - initialBalance1
val diffCorrect = diff0 == -diff1
val balancesCorrect = (finishBalance0 > minBalance) && (finishBalance1 > minBalance) && diffCorrect
// Verifica se as caixas dos membros salvam seus scripts.
// todo: otimização poderia ser feita aqui
val script0Saved = participantOut0.propositionBytes == participant0.propositionBytes
val script1Saved = participantOut1.propositionBytes == participant1.propositionBytes
val scriptsSaved = script0Saved && script1Saved
// Proteção específica da caixa do membro
val selfPubKey = SELF.R5[SigmaProp].get
selfPubKey && properLetsToken && membersExist && diffCorrect && scriptsSaved
Note que ambos os contratos poderiam ser modificados de várias maneiras para obter novos sistemas com propriedades diferentes. Portanto, esperamos que algum dia este artigo seja continuado!
Share post
13 de agosto de 2025
12 de agosto de 2025
9 de julho de 2025
12 de maio de 2025

7 de abril de 2022

8 de março de 2022


















