Un Sistema Locale di Scambio Commerciale Su Ergo
22 aprile 2019

Un sistema locale di scambio commerciale (LETS) è un'associazione locale di credito mutuale che consente ai membri di creare denaro di credito comune individualmente, con tutte le transazioni nel sistema scritte in un libro mastro comune. Come esempio, supponiamo che Alice, con un saldo di zero, sia disposta ad acquistare un litro di latte crudo da Bob. Prima, concordano un prezzo, ad esempio, supponiamo che il prezzo sia di circa 2 Euro (poiché Alice e Bob vivono in Irlanda). Dopo che l'affare è stato scritto in un libro mastro, il saldo di Alice diventa -2 (meno due) Euro, e il saldo di Bob diventa 2 Euro. Poi Bob può spendere i suoi 2 Euro, ad esempio, per birra fatta in casa da Charlie. Spesso, tali sistemi impongono limiti sui saldi negativi, e a volte anche su quelli positivi, per promuovere lo scambio nella comunità.
Storicamente, tali sistemi sono diventati popolari durante i periodi di crisi. Il primo sistema è stato istituito da Michael Linton in una città canadese bloccata in depressione nel 1981. I sistemi di scambio commerciale locale sono stati estremamente popolari durante la Grande Depressione Argentina del 1998-2002. La maggior parte dei gruppi LETS varia da 50 a 250 membri, con note di credito cartacee e un libro mastro mantenuto da un comitato centrale. Tuttavia, le valute LETS basate su carta hanno mostrato alcuni problemi, come note false, possibili comportamenti scorretti dei gestori del sistema, e così via. Pertanto, i LETS basati su blockchain potrebbero essere superiori ai vecchi sistemi. Maggiori informazioni sui LETS possono essere trovate nel "The Ecology of Money" libro (di Richard Douthwaite) e su Wikipedia.
In questo articolo mostriamo come i LETS potrebbero essere implementati su Ergo. Per quanto ne sappiamo, questa è la prima implementazione di questo tipo di valuta comunitaria su una blockchain. La nostra implementazione di riferimento è semplice e consiste in due contratti, ovvero un contratto di gestione e un contratto di scambio. Saltiamo le premesse di Ergo, quindi ti preghiamo di leggere l'articolo ICO e i tutorial di ErgoScript (base e avanzato) per i principianti. Tuttavia, stiamo per introdurre un paio di nuovi termini nelle frasi seguenti. Se un token è emesso con un importo pari a uno, lo chiamiamo token singleton. Allo stesso modo, una box che contiene il token singleton è chiamata box singleton.
Il contratto di gestione controlla una box singleton che contiene i membri del sistema LETS. Il contratto consente l'aggiunta di nuovi membri al ritmo di un membro per transazione. La box non memorizza i membri, ma solo un piccolo digest di una struttura dati autenticata costruita sopra il registro dei membri. Un membro è associato a un token singleton emesso in una transazione che aggiunge il membro al registro. La transazione crea una nuova box del membro che contiene il token singleton del membro. La box del membro è protetta dal contratto di scambio. Inoltre, la nuova box del membro creata ha un saldo iniziale scritto nel registro R4, e il saldo è pari a zero nel nostro esempio. La transazione che crea un nuovo membro deve fornire una prova di correttezza per la trasformazione del registro.
La box del contratto di gestione è solitamente controllata da un comitato, e il comitato potrebbe evolversi nel tempo. Per supportare ciò, consentiamo alla logica del comitato di risiedere nel registro R5. Ad esempio, supponiamo che un nuovo membro del comitato sia stato aggiunto insieme a un nuovo membro LETS, la box del contratto di gestione in input richiede 2-fuori-3 firme, e la box di output richiede 3-fuori-4 firme. In questo caso, i contenuti del registro R5 nella box di input e nella box di output differirebbero.
Il codice del contratto di gestione in ErgoScript con commenti è fornito di seguito. Si prega di notare che "userContractHash" riguarda l'hash del contratto di scambio.
val selfOut = OUTPUTS(0)
// Script di gestione
val managementScript = selfOut.R5[SigmaProp].get
// Il template dello script di gestione replica se stesso, e lo script di gestione è soddisfatto
val scriptCorrect = (selfOut.propositionBytes == SELF.propositionBytes) && managementScript
// Una transazione di spesa crea box per il registro, utente, tassa.
val outsSizeCorrect = OUTPUTS.size == 3
// Controlla che il token di etichetta di gestione stia replicando se stesso
val outTokenCorrect = (selfOut.tokens.size == 1) && (selfOut.tokens(0)._1 == letsToken)
// Controlla che un nuovo token sia emesso, e il suo importo sia corretto
// OUTPUTS(0) token già controllati tramite 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)
// Controlla che il nuovo utente sia stato creato con il saldo zero
val zeroUserBalance = userOut.R4[Long].get == 0
val properUserScript = blake2b256(userOut.propositionBytes) == userContractHash
// Controlla che il nuovo identificatore di token sia stato aggiunto al registro
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
Lo script del contratto di scambio è piuttosto semplice e fornito di seguito insieme a commenti che descrivono la sua logica. Nel contratto, si presume che una transazione di spesa per una box di contratto di scambio riceva almeno due input, e i primi due input dovrebbero essere protetti dallo script del contratto di scambio e contenere token dei membri LETS. Per controllare che i token dei membri singleton negli input appartengano effettivamente al sistema LETS, una transazione di spesa fornisce la box del contratto di gestione come primo input di dati in sola lettura, e deve anche fornire una prova che i token dei membri appartengano al registro autenticato tramite il registro R4 della box del contratto di gestione. "letsToken" nello script riguarda il token singleton della box di gestione.
// Saldo minimo consentito per il trader LETS
val minBalance = -20000
val lookupProof = getVar[Coll[Byte]](1).get
// La box in sola lettura che contiene il registro dei membri LETS
val treeHolderBox = CONTEXT.dataInputs(0)
val properLetsToken = treeHolderBox.tokens(0)._1 == letsToken
val membersTree = treeHolderBox.R4[AvlTree].get
// Una transazione di spesa sta prendendo due box di membri LETS disposti a fare un affare,
// e restituisce box con saldi modificati.
val participant0 = INPUTS(0)
val participant1 = INPUTS(1)
val participantOut0 = OUTPUTS(0)
val participantOut1 = OUTPUTS(1)
//Controlla che i membri appartengano effettivamente ai 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 })
// Controlla che i cambiamenti di saldo dei membri LETS durante l'affare siano corretti
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
// Controlla che le box dei membri salvino i loro script.
// todo: ottimizzazione potrebbe essere fatta qui
val script0Saved = participantOut0.propositionBytes == participant0.propositionBytes
val script1Saved = participantOut1.propositionBytes == participant1.propositionBytes
val scriptsSaved = script0Saved && script1Saved
// Protezione specifica della box del membro
val selfPubKey = SELF.R5[SigmaProp].get
selfPubKey && properLetsToken && membersExist && diffCorrect && scriptsSaved
Nota che entrambi i contratti potrebbero essere modificati in molti modi per ottenere nuovi sistemi con proprietà diverse. Quindi, si spera che un giorno questo articolo sarà continuato!
Share post
13 agosto 2025
9 luglio 2025
12 maggio 2025
7 agosto 2022




















