Ein Lokales Austauschhandelssystem Auf Basis Von Ergo
22. April 2019

Ein lokales Austauschhandelssystem (LETS) ist eine lokale gegenseitige Kreditvereinigung, in der Mitglieder gemeinsam
Kreditgeld individuell schaffen dürfen, wobei alle Geschäfte im System in ein gemeinsames Hauptbuch geschrieben werden.
Als Beispiel nehmen wir an, dass Alice mit einem Kontostand von null bereit ist, einen Liter Rohmilch von Bob zu kaufen.
Zuerst einigen sie sich auf einen Preis, zum Beispiel nehmen wir an, der Preis beträgt etwa 2 Euro (da Alice und Bob
in Irland leben). Nachdem der Deal in ein Hauptbuch geschrieben wurde, wird Alices Kontostand -2 (minus
zwei) Euro und Bobs Kontostand 2 Euro. Dann kann Bob seine 2 Euro ausgeben, zum Beispiel für
hausgemachtes Bier von Charlie. Oft setzen solche Systeme Grenzen für negative Salden und manchmal
sogar für positive, um den Austausch in der Gemeinschaft zu fördern.
Historisch gesehen wurden solche Systeme in Krisenzeiten populär. Das erste System wurde 1981 von Michael Linton in
einer kanadischen Stadt gegründet, die in einer Depression feststeckte. Lokale Austauschhandelssysteme waren während
der argentinischen Großen Depression von 1998-2002 äußerst beliebt. Die meisten LETS-Gruppen bestehen aus 50 bis 250 Mitgliedern, mit papierbasierten Kreditscheinen und
Hauptbüchern, die von einem Kernkomitee verwaltet werden. Papierbasierte LETS-Währungen haben jedoch einige Probleme gezeigt, wie
Fälschungen, mögliches ungebührliches Verhalten von Systemmanagern und so weiter. Daher könnten blockchain-basierte LETS den alten Systemen überlegen sein.
Weitere Informationen zu LETS finden Sie in
"The Ecology of Money" Buch (von Richard Douthwaite) und
Wikipedia.
In diesem Artikel zeigen wir, wie LETS auf Basis von Ergo implementiert werden könnten. Nach unserem besten Wissen ist dies
die erste Implementierung einer solchen Gemeinschaftswährung auf einer Blockchain.
Unsere Referenzimplementierung
ist einfach und besteht aus zwei Verträgen, nämlich einem Verwaltungsvertrag und einem Austauschvertrag.
Wir überspringen die Ergo-Vorbereitungen, also lesen Sie bitte
den ICO-Artikel und
ErgoScript-Tutorials (grundlegend und
fortgeschritten) für den Anfang.
Dennoch werden wir in den folgenden Sätzen ein paar neue Begriffe einführen.
Wenn ein Token mit einem Betrag von eins ausgegeben wird, nennen wir es den Singleton-Token. Ebenso wird
eine Box, die den Singleton-Token enthält, als Singleton-Box bezeichnet.
Der Verwaltungsvertrag kontrolliert eine Singleton-Box, die Mitglieder des LETS-Systems hält.
Der Vertrag ermöglicht das Hinzufügen neuer Mitglieder im Tempo von einem Mitglied pro Transaktion. Die Box
speichert keine Mitglieder, sondern nur einen kleinen Digest einer authentifizierten Datenstruktur, die auf der
Mitgliederverzeichnis aufgebaut ist. Ein Mitglied ist mit einem Singleton-Token verbunden, das in einer Transaktion ausgegeben wird, die
das Mitglied zum Verzeichnis hinzufügt. Die Transaktion erstellt eine neue Mitgliederbox, die den
Singleton-Token des Mitglieds enthält. Die Mitgliederbox ist durch den Austauschvertrag geschützt. Außerdem hat die neu
erstellte Mitgliederbox ein anfängliches Guthaben, das im R4-Register vermerkt ist, und das Guthaben ist
in unserem Beispiel gleich null. Die Transaktion, die ein neues Mitglied erstellt, muss einen Nachweis der Korrektheit für
die Verzeichnisumwandlung bereitstellen.
Die Verwaltungsvertragsbox wird normalerweise von einem Komitee kontrolliert, und das Komitee könnte sich im Laufe der Zeit entwickeln. Um dies zu unterstützen, erlauben wir, dass die Komiteelogik im Register R5 residiert.
Zum Beispiel nehmen wir an, dass ein neues Komiteemitglied zusammen mit einem neuen LETS-Mitglied hinzugefügt wurde,
die Eingangsverwaltungsvertragsbox erfordert 2-aus-3-Unterschriften, und die Ausgangsbox erfordert 3-aus-4-Unterschriften.
In diesem Fall würden sich die Inhalte des R5-Registers in der Eingangs- und Ausgangsbox unterscheiden.
Der Verwaltungsvertragscode in ErgoScript mit Kommentaren ist unten angegeben. Bitte beachten Sie, dass
"userContractHash" den Hash des Austauschvertrags betrifft.
val selfOut = OUTPUTS(0)
// Verwaltungs-Skript
val managementScript = selfOut.R5[SigmaProp].get
// Die Verwaltungsskriptvorlage repliziert sich selbst, und das Verwaltungsskript ist erfüllt
val scriptCorrect = (selfOut.propositionBytes == SELF.propositionBytes) && managementScript
// Eine Ausgabetransaktion erstellt Boxen für Verzeichnis, Benutzer, Gebühr.
val outsSizeCorrect = OUTPUTS.size == 3
// Überprüft, dass das Verwaltungsetikett-Token sich selbst repliziert
val outTokenCorrect = (selfOut.tokens.size == 1) && (selfOut.tokens(0)._1 == letsToken)
// Überprüft, dass ein neues Token ausgegeben wird und dessen Betrag korrekt ist
// OUTPUTS(0) Tokens wurden bereits über outtokenCorrect überprüft
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)
// Überprüft, dass der neue Benutzer mit dem Nullguthaben erstellt wurde
val zeroUserBalance = userOut.R4[Long].get == 0
val properUserScript = blake2b256(userOut.propositionBytes) == userContractHash
// Überprüft, dass die neue Token-ID zum Verzeichnis hinzugefügt wurde
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
Das Austauschvertragsskript ist ziemlich einfach und wird unten zusammen mit Kommentaren, die seine Logik beschreiben, bereitgestellt. Im
Vertrag wird angenommen, dass eine Ausgabetransaktion für eine Austauschvertragsbox mindestens zwei Eingaben erhält,
und die ersten beiden Eingaben sollten durch das Austauschvertragsskript geschützt sein und LETS-Mitglieds-Token enthalten. Um zu überprüfen,
dass die Singleton-Mitglieds-Token in den Eingaben tatsächlich zum LETS-System gehören, stellt eine Ausgabetransaktion die Verwaltungs-
vertragsbox als erste schreibgeschützte Dateneingabe bereit und sollte auch einen Nachweis erbringen, dass die Mitglieds-Token tatsächlich zum
Verzeichnis gehören, das über das R4-Register der Verwaltungsvertragsbox authentifiziert ist. "letsToken" im Skript bezieht sich auf
den Singleton-Token der Verwaltungsbox.
// Minimaler Guthabenbetrag, der für LETS-Händler erlaubt ist
val minBalance = -20000
val lookupProof = getVar[Coll[Byte]](1).get
// Die schreibgeschützte Box, die das Verzeichnis der LETS-Mitglieder enthält
val treeHolderBox = CONTEXT.dataInputs(0)
val properLetsToken = treeHolderBox.tokens(0)._1 == letsToken
val membersTree = treeHolderBox.R4[AvlTree].get
// Eine Ausgabetransaktion nimmt zwei Boxen von LETS-Mitgliedern, die bereit sind, einen Deal zu machen,
// und gibt Boxen mit modifizierten Salden zurück.
val participant0 = INPUTS(0)
val participant1 = INPUTS(1)
val participantOut0 = OUTPUTS(0)
val participantOut1 = OUTPUTS(1)
// Überprüft, dass die Mitglieder tatsächlich zum LETS gehören
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 })
// Überprüft, dass die Änderungen des LETS-Mitgliedsguthabens während des Deals korrekt sind
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
// Überprüft, dass die Mitgliederboxen ihre Skripte speichern.
// todo: hier könnte eine Optimierung vorgenommen werden
val script0Saved = participantOut0.propositionBytes == participant0.propositionBytes
val script1Saved = participantOut1.propositionBytes == participant1.propositionBytes
val scriptsSaved = script0Saved && script1Saved
// Mitgliedsspezifischer Boxenschutz
val selfPubKey = SELF.R5[SigmaProp].get
selfPubKey && properLetsToken && membersExist && diffCorrect && scriptsSaved
Beachten Sie, dass beide Verträge auf viele Arten modifiziert werden könnten, um neue Systeme mit unterschiedlichen Eigenschaften zu erhalten. Hoffentlich wird
dieser Artikel eines Tages fortgesetzt!
Share post
13. August 2025
12. August 2025
9. Juli 2025
12. Mai 2025
9. Dezember 2024
19. August 2024
