Ein vertrauensloses lokales Austauschhandelssystem
29. Mai 2019

Ein Local Exchange Trading System (LETS) zielt darauf ab, die lokale Wirtschaft zu entwickeln und wird normalerweise von Menschen in einer Umgebung genutzt, die sich in der Nähe zueinander befinden. Für einen kurzen Überblick über LETS siehe diesen Link, der auch eine ErgoScript-Implementierung eines von einem Komitee verwalteten LETS beschreibt. Wir nennen ein solches System verwaltet oder genehmigt, da es von einem Komitee vertrauenswürdiger Mitglieder abhängt, um neue Mitglieder in das LETS aufzunehmen.
Hier beschreiben wir ein vertrauensloses LETS, d.h. eines, bei dem kein Verwaltungskomitee für die Aufnahme erforderlich ist.
Übersicht
LETS umfasst mehrere Parteien, die sich darauf einigen, eine Form von "lokaler Währung" zu verwenden, die normalerweise im Verhältnis 1:1 an die Hauptwährung des Landes gebunden ist. Angenommen, unser LETS basiert in einem europäischen Land, in dem die Währung Euro ist, und der Austausch erfolgt in "lokalen Euro", die als gleichwertig zu nationalen Euro angesehen werden.
Jeder Benutzer im LETS hat ein Konto, das den LETS-Saldo dieses Benutzers (in lokalen Euro) enthält. Bei der Aufnahme hat jeder Benutzer einen Saldo von null. Der Saldo wird in einem (möglicherweise dezentralen) Hauptbuch gespeichert. Ein interessantes Merkmal von LETS ist, dass ein Benutzer mit einem Saldo von null auch Geld "abheben" kann, jedoch nur, um einen anderen LETS-Benutzer zu bezahlen. Zu jedem Zeitpunkt ist die Summe der LETS-Salden aller Benutzer null.
Als Beispiel möchte Alice mit einem Saldo von null einen Liter Milch für 2 Euro von Bob kaufen, der ebenfalls ein Mitglied von LETS mit einem Saldo von null ist. Sie überweist 2 Euro von ihrem Konto auf Bobs, wodurch ihr Saldo -2 und Bobs +2 wird. Bob kann dann einen Teil oder den gesamten Saldo an einen anderen LETS-Benutzer im Austausch für Waren oder Dienstleistungen übertragen.
Vertrauensloses LETS
Da wir ein vertrauensloses LETS wünschen, können wir uns nicht auf eine vertrauenswürdige Gruppe von Personen verlassen, um Benutzer aufzunehmen. Beachten Sie, dass wir dennoch ein Komitee haben werden, um einige Aufgaben wie die Festlegung der LETS-Parameter (lokale Währung, maximale Anzahl von Mitgliedern usw.) und die Erhebung einer Aufnahmegebühr zu übernehmen.
Wir nehmen nur einen vertrauenswürdigen Preis-Orakel an, das den aktuellen Kurs von Euro zu Ergs angibt, identifiziert durch eine globale ID (rateTokenID), und eine Singleton-Box, die genau ein Token mit dieser ID enthält. Eine Singleton-Box, die hier beschrieben wird, ist eine Box, die ein Singleton-Token enthält, d.h. ein Token, von dem nur eine Menge existiert. Diese Box enthält auch den Kurs von Ergs zu Euro zu einem bestimmten Zeitpunkt. Der Kurs wird aktualisiert, indem diese Box ausgegeben und eine andere Singleton-Box mit dem neuen Kurs erstellt wird.
Zu jedem Zeitpunkt wird unser LETS eindeutig durch eine globale Token-Box definiert, die einige Mitgliedschafts-Token mit der ID letsTokenID enthält. Diese Box definiert die LETS-Parameter wie den Standort, die Währungseinheit, rateTokenID usw. Die Token-Box wird zunächst mit, sagen wir, 10000 Mitgliedschafts-Token gestartet. Benutzer können diese Box ausgeben und ihre individuellen LETS-Boxen als Ausgaben der Transaktion erstellen, sodass jede solche Ausgabe genau ein Mitgliedschafts-Token hat und die verbleibenden Mitgliedschafts-Token in einer neu erstellten Token-Box abgelegt werden.
Eine LETS-Box repräsentiert ein LETS-Mitglied und muss in jeder Transaktion verwendet werden. Zur Vereinfachung beschränkt dieser Artikel alle LETS-Transaktionen auf genau zwei Mitglieder, wobei einer der Absender und der andere der Empfänger ist, sodass der Absender einen positiven Betrag der LETS-Währung (lokale Euro) an den Empfänger überträgt. Eine solche Transaktion verbraucht die Boxen des Mitglieds und erstellt sie als Ausgabe mit dem aktualisierten Saldo.
Die Basisvariante
Um Spam und DDoS-Angriffe zu verhindern, verlangen wir, dass mindestens eine bestimmte Mindestanzahl von Ergs (minErgsToJoin) in der neu erstellten Box des Mitglieds gesperrt wird. Die Ergs werden gesperrt, bis mindestens minWithdrawTime Anzahl von Blöcken abgebaut wurden. Eine Box darf einen negativen LETS-Saldo bis zu dem Betrag haben, der durch die gesperrten Ergs gedeckt werden kann (unter Verwendung des Kurses zum Zeitpunkt des Handels).
// eine tokenBox speichert die Mitgliedschafts-Token und hat dieses Skript
val tokenBox = OUTPUTS(0) // die erste Ausgabe muss ebenfalls eine tokenBox sein
// erste Ausgabe enthält verbleibende LETS-Token
def isLets(b:Box) = { // gibt true zurück, wenn b eine LETS-Box ist
// Eine LETS-Box muss genau 1 Mitgliedschafts-Token in tokens(0) haben
b.tokens(0)._1 == letsTokenID && b.tokens(0)._2 == 1 &&
blake2b256(b.propositionBytes) == memberBoxScriptHash &&
SELF.R4[Long].get == 0 && // starte die Box mit einem Saldo von null LETS
b.value >= minErgsToJoin && // die Box muss einige Mindest-Ergs enthalten
b.R6[Long].get <= HEIGHT // speichere die Erstellungs-Höhe in R6
}
// wie viele lets-Boxen in der tx erstellt
val numLetsBoxes = OUTPUTS.filter({(b:Box) => isLets(b)}).size
// In der Transaktion wird Folgendes für die Token-Box beibehalten ...
tokenBox.tokens(0)._1 == SELF.tokens(0)._1 && // Token-ID
tokenBox.tokens(0)._2 == SELF.tokens(0)._2 - numLetsBoxes && // Menge
tokenBox.propositionBytes == SELF.propositionBytes // Skript
Die Box eines LETS-Mitglieds wird durch das folgende Skript geschützt, dessen Hash memberBoxScriptHash oben verwendet wird. Das Skript erfordert genau ein (Absender, Empfänger) Paar pro Transaktion.
val validRateOracle = CONTEXT.dataInputs(0).tokens(0)._1 == rateTokenID
val rate = CONTEXT.dataInputs(0).R4[Int].get
val inBalance = SELF.R4[Long].get // LETS-Saldo des aktuellen Inputs
val pubKey = SELF.R5[SigmaProp].get // Eigentümer des aktuellen Inputs
val createdAt = SELF.R6[Long].get // Höhe, bei der der aktuelle Input abgebaut wurde
val index = getVar[Int](0).get // Index der entsprechenden Ausgabe
val out = OUTPUTS(index)
val outBalance = out.R4[Long].get // LETS-Saldo der Ausgabe
// Eine LETS-Box ist eine, die dasselbe Skript wie die aktuelle Box hat
val isMemberBox = {(b:Box) => b.propositionBytes == SELF.propositionBytes}
val letsInputs = INPUTS.filter(isMemberBox) // alle LETS-Eingangsboxen
val letsOutputs = OUTPUTS.filter(isMemberBox) // alle LETS-Ausgangsboxen
// Der aktuelle Input gehört dem Empfänger, wenn sein LETS-Saldo steigt
// Es können einige Ergs in der Eingangsbox des Empfängers sein. Wir müssen sicherstellen, dass
// die Ausgangsbox des Empfängers auch den gleichen Betrag an Ergs wie der Input enthält
val receiver = outBalance > inBalance && out.value == SELF.value
val getBalance = {(b:Box) => b.R4[Long].get} // gibt LETS-Saldo einer Box zurück
val letsBalIn = letsInputs.map(getBalance).fold(0L, {(l:Long, r:Long) => l + r})
val letsBalOut = letsOutputs.map(getBalance).fold(0L, {(l:Long, r:Long) => l + r})
// Die Absenderbox kann weniger Ergs enthalten (der Absender kann Ergs abheben, vorausgesetzt,
// dass jeder negative LETS-Saldo des Absenders in out durch ausreichende Ergs gedeckt ist)
val correctErgs = out.value >= -outBalance * rate && (
out.value >= SELF.value || SELF.R6[Long].get + minWithdrawTime > HEIGHT
)
// Für den Empfänger berühren wir den Erg-Saldo nicht,
// da ein Empfänger nicht aktiv an der Transaktion beteiligt ist
inBalance != outBalance && // es sollte eine Transaktion stattfinden; der Saldo muss sich ändern
SELF.tokens(0)._1 == letsTokenID && // der aktuelle Input hat das richtige Token
out.tokens(0)._1 == letsTokenID && // die entsprechende Ausgabe hat das richtige Token
validRateOracle && // das Orakel, das den Kurs bereitstellt, hat das richtige "Kurstoken"
letsBalIn == letsBalOut && // der gesamte LETS-Saldo wird in der Transaktion beibehalten
letsInputs.size == 2 && letsOutputs.size == 2 && // nur zwei LETS-Eingaben, Ausgaben
out.propositionBytes == SELF.propositionBytes && // out ist eine LETS-Box ...
out.R5[SigmaProp].get == pubKey && // ... mit dem richtigen öffentlichen Schlüssel
out.R6[Long].get == SELF.R6[Long].get && // ... und Erstellungs-Höhe
(receiver || // entweder gehört der aktuelle Input dem Empfänger ...
(pubKey && correctErgs) // ... oder out hat die richtigen Ergs und die tx hat eine Signatur
)
Die Transaktion, die eine Box mit dem obigen Skript ausgibt, erfordert:
- Die Summe des LETS-Saldos der Eingaben und Ausgaben wird beibehalten
- Es gibt zwei LETS-Eingaben und zwei LETS-Ausgaben
- Die öffentlichen Schlüssel (in R5 gespeichert) werden in der entsprechenden Ausgabe beibehalten
- Die Erstellungs-Höhe (in R6 gespeichert) wird in der entsprechenden Ausgabe beibehalten
Wir sagen, dass ein öffentlicher Schlüssel der Empfänger ist, wenn das LETS-Saldo seiner Ausgabe höher ist als das seiner Eingabe.
Die letzte Bedingung erfordert, dass entweder die Eingangs- und Ausgangsboxen dem Empfänger gehören (damit die Ergs erhalten bleiben), oder, falls sie dem Absender gehören, eine Signatur bereitgestellt wird und die Ausgabe durch die erforderliche Anzahl von Ergs gedeckt ist, wenn ihr LETS-Saldo negativ ist. Darüber hinaus erfordert es, dass der Erg-Saldo des Absenders nicht reduziert werden kann, bis mindestens minWithdrawTime Anzahl von Blöcken abgebaut wurden, nachdem die Ergs gesperrt wurden.
Im Vergleich zum verwalteten LETS hat das obige System folgende Unterschiede:
- Kein Mitgliedschaftsprotokoll: Im Gegensatz zum verwalteten LETS speichern wir hier keine Mitgliedschaftsinformationen.
- Mehrere Boxen: Eine Person kann mehrere Mitgliedschaftsboxen erstellen, was erlaubt ist. Wir verlangen nur, dass jeder negative Saldo durch die entsprechende Anzahl von Ergs, die darin gesperrt sind, gedeckt ist.
LETS-1: Nullsumme, Sicherheiten
Das obige ist die Basisvariante, die wir LETS-1 nennen. Sie hat folgende Merkmale:
- Zeitlich gesperrte Aufnahmegebühr: Um Spam-Angriffe zu verhindern, muss ein Mitglied zum Zeitpunkt der Aufnahme eine bestimmte Mindestgebühr in Ergs zahlen. Diese Gebühr ist rückerstattbar, jedoch nur nach einer vordefinierten Anzahl von Blöcken.
- Nullsumme: Die Summe der LETS-Salden aller Mitgliedsboxen ist null. Mitgliedsboxen dürfen einen negativen Saldo haben, solange dies innerhalb eines bestimmten Limits liegt.
- Sicherheiten: Für die Ausgabe des Absenders werden Ergs als Sicherheiten verwendet, um den negativen LETS-Saldo zum aktuellen Wechselkurs zu decken.
Die folgenden sind einige Variationen von LETS-1.
LETS-2: Nullsumme, Keine Sicherheiten
Dies ist eine leichte Variation von LETS-1 wie folgt:
- Nicht rückerstattbare Aufnahmegebühr: Ähnlich wie bei LETS-1 ist eine Aufnahmegebühr erforderlich, um Spam-Angriffe zu verhindern. Im Gegensatz zu LETS-1 ist diese Gebühr jedoch nicht rückerstattbar und muss an ein vordefiniertes Verwaltungskomitee gesendet werden.
- Nullsumme: Wie in LETS-1.
LETS-3: Positive Summe, Sicherheiten
Die obigen beiden Varianten erfordern, dass der gesamte LETS-Saldo immer null ist. Hier betrachten wir einen positiven Wert für diese Summe. Insbesondere hat diese Variante folgende Eigenschaften:
- Zeitlich gesperrte Aufnahmegebühr: Wie in LETS-1.
- Positive Summe: Der LETS-Saldo jedes Mitglieds muss immer nicht negativ sein. Dies stellt sicher, dass die Summe der LETS-Salden aller Mitgliedsboxen positiv ist. Der anfängliche LETS-Saldo wird auf einen positiven Wert basierend auf der Aufnahmegebühr zum aktuellen Kurs festgelegt, begrenzt auf einen maximalen Wert.
- Sicherheiten: Jede Reduzierung des Erg-Saldos des Absenders muss mit einer Reduzierung des entsprechenden LETS-Saldos zum aktuellen Wechselkurs einhergehen.
Wir können auch das Auffüllen des LETS-Saldos während einer Transaktion durch Hinzufügen des entsprechenden Betrags an Ergs zulassen.
LETS-4: Positive Summe, Keine Sicherheiten
Dies ist ähnlich wie LETS-3, jedoch mit einigen kleinen Variationen:
- Nicht rückerstattbare Aufnahmegebühr: Wie in LETS-2
- Positive Summe: Wie in LETS-3
Die folgende Tabelle fasst die Varianten zusammen:
| Nullsumme | Positive Summe | |
|---|---|---|
| Sicherheiten | LETS-1 | LETS-3 |
| Keine Sicherheiten | LETS-2 | LETS-4 |
Wir haben LETS-Transaktionen betrachtet, die ein einzelnes Absender-Empfänger-Paar betreffen. Fortgeschrittenere Modelle können mehrere Absender und Empfänger zulassen und müssen nicht in Paaren sein.
Share post
13. August 2025
12. August 2025
9. Juli 2025
12. Mai 2025
9. Dezember 2024
19. August 2024
