Un Sistema Local de Intercambio Comercial Sobre Ergo
22 de abril de 2019

Un sistema local de intercambio comercial (LETS) es una asociación local de crédito mutuo que permite a los miembros crear dinero de crédito común de forma individual, con todos los acuerdos en el sistema escritos en un libro de contabilidad común. Como ejemplo, supongamos que Alice, con un saldo de cero, está dispuesta a comprar un litro de leche cruda a Bob. Primero, acuerdan un precio, por ejemplo, supongamos que el precio es de aproximadamente 2 euros (ya que Alice y Bob viven en Irlanda). Después de que el acuerdo se escriba en un libro de contabilidad, el saldo de Alice se convierte en -2 (menos dos) euros, y el saldo de Bob se convierte en 2 euros. Luego, Bob puede gastar sus 2 euros, por ejemplo, en cerveza casera de Charlie. A menudo, tales sistemas imponen límites a los saldos negativos, y a veces incluso a los positivos, para promover el intercambio en la comunidad.
Históricamente, tales sistemas se hicieron populares durante tiempos de crisis. El primer sistema fue establecido por Michael Linton en una ciudad canadiense atrapada en la depresión en 1981. Los sistemas de intercambio comercial local fueron extremadamente populares durante la Gran Depresión Argentina de 1998-2002. La mayoría de los grupos LETS varían de 50 a 250 miembros, con notas de crédito en papel y un libro de contabilidad mantenido por un comité central. Sin embargo, las monedas LETS basadas en papel han mostrado algunos problemas, como notas falsificadas, posible comportamiento deshonesto de los administradores del sistema, etc. Por lo tanto, los LETS basados en blockchain podrían ser superiores a los antiguos sistemas. Más información sobre LETS se puede encontrar en el "El Ecología del Dinero" libro (por Richard Douthwaite) y en Wikipedia.
En este artículo mostramos cómo se podrían implementar los LETS sobre Ergo. Hasta donde sabemos, esta es la primera implementación de este tipo de moneda comunitaria sobre una blockchain. Nuestra implementación de referencia es simple y consiste en dos contratos, a saber, un contrato de gestión y un contrato de intercambio. Saltamos los preliminares de Ergo, así que por favor lea el artículo ICO y los tutoriales de ErgoScript (básico y avanzado) para principiantes. Sin embargo, vamos a introducir un par de nuevos términos en las siguientes oraciones. Si se emite un token con un monto igual a uno, lo llamamos el token singleton. De manera similar, una caja que contiene el token singleton se llama la caja singleton.
El contrato de gestión controla una caja singleton que contiene a los miembros del sistema LETS. El contrato permite la adición de nuevos miembros a un ritmo de un miembro por transacción. La caja no almacena miembros, sino solo un pequeño resumen de la estructura de datos autenticada construida sobre el directorio de miembros. Un miembro está asociado con un token singleton emitido en una transacción que está añadiendo al miembro al directorio. La transacción crea una nueva caja de miembro que contiene el token singleton del miembro. La caja del miembro está protegida por el contrato de intercambio. Además, la nueva caja del miembro creada tiene un saldo inicial escrito en el registro R4, y el saldo es igual a cero en nuestro ejemplo. La transacción que crea un nuevo miembro debe proporcionar una prueba de corrección para la transformación del directorio.
La caja del contrato de gestión es controlada generalmente por un comité, y el comité podría evolucionar con el tiempo. Para apoyar eso, permitimos que la lógica del comité resida en el registro R5. Por ejemplo, supongamos que se ha añadido un nuevo miembro del comité junto con un nuevo miembro de LETS, la caja del contrato de gestión de entrada requiere 2 de 3 firmas, y la caja de salida requiere 3 de 4 firmas. En este caso, el contenido del registro R5 en la caja de entrada y la caja de salida diferiría.
El código del contrato de gestión en ErgoScript con comentarios se proporciona a continuación. Tenga en cuenta que "userContractHash" se refiere al hash del contrato de intercambio.
val selfOut = OUTPUTS(0)
// Script de gestión
val managementScript = selfOut.R5[SigmaProp].get
// La plantilla del script de gestión está replicando a sí misma, y el script de gestión está satisfecho
val scriptCorrect = (selfOut.propositionBytes == SELF.propositionBytes) && managementScript
// Una transacción de gasto está creando cajas para el directorio, usuario, tarifa.
val outsSizeCorrect = OUTPUTS.size == 3
// Verifica que el token de etiqueta de gestión está replicando a sí mismo
val outTokenCorrect = (selfOut.tokens.size == 1) && (selfOut.tokens(0)._1 == letsToken)
// Verifica que se ha emitido un nuevo token, y su cantidad es correcta
// OUTPUTS(0) tokens ya verificados a través de 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 que el nuevo usuario ha sido creado con el saldo cero
val zeroUserBalance = userOut.R4[Long].get == 0
val properUserScript = blake2b256(userOut.propositionBytes) == userContractHash
// Verifica que el nuevo identificador de token ha sido añadido al directorio
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
El script del contrato de intercambio es bastante sencillo y se proporciona a continuación junto con comentarios que describen su lógica. En el contrato, se asume que una transacción de gasto para una caja de contrato de intercambio está recibiendo al menos dos entradas, y las dos primeras entradas deben estar protegidas por el script del contrato de intercambio y contener tokens de miembros de LETS. Para verificar que los tokens de miembros singleton en las entradas pertenecen efectivamente al sistema LETS, una transacción de gasto proporciona la caja del contrato de gestión como la primera entrada de datos de solo lectura, y también debe proporcionar una prueba de que los tokens de miembros pertenecen al directorio autenticado a través del registro R4 de la caja del contrato de gestión. "letsToken" en el script se refiere al token singleton de la caja de gestión.
// Saldo mínimo permitido para el comerciante de LETS
val minBalance = -20000
val lookupProof = getVar[Coll[Byte]](1).get
// La caja de solo lectura que contiene el directorio de miembros de LETS
val treeHolderBox = CONTEXT.dataInputs(0)
val properLetsToken = treeHolderBox.tokens(0)._1 == letsToken
val membersTree = treeHolderBox.R4[AvlTree].get
// Una transacción de gasto está tomando dos cajas de miembros de LETS dispuestos a hacer un trato,
// y devuelve cajas con saldos modificados.
val participant0 = INPUTS(0)
val participant1 = INPUTS(1)
val participantOut0 = OUTPUTS(0)
val participantOut1 = OUTPUTS(1)
// Verifica que los miembros pertenecen efectivamente a los 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 que los cambios en el saldo de los miembros durante el trato son correctos
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 que las cajas de los miembros guardan sus scripts.
// todo: se podría hacer una optimización aquí
val script0Saved = participantOut0.propositionBytes == participant0.propositionBytes
val script1Saved = participantOut1.propositionBytes == participant1.propositionBytes
val scriptsSaved = script0Saved && script1Saved
// Protección específica de la caja del miembro
val selfPubKey = SELF.R5[SigmaProp].get
selfPubKey && properLetsToken && membersExist && diffCorrect && scriptsSaved
Tenga en cuenta que ambos contratos podrían modificarse de muchas maneras para obtener nuevos sistemas con diferentes propiedades. ¡Así que esperamos que algún día se continúe este artículo!
Share post
13 de agosto de 2025
12 de agosto de 2025
9 de julio de 2025
12 de mayo de 2025

9 de febrero de 2022

8 de febrero de 2022

5 de febrero de 2022

1 de febrero de 2022

27 de enero de 2022

20 de enero de 2022

18 de enero de 2022

6 de enero de 2022

4 de enero de 2022

30 de diciembre de 2021

28 de diciembre de 2021

23 de diciembre de 2021








