diff --git a/eip-0026.md b/eip-0026.md new file mode 100644 index 00000000..ff0d580d --- /dev/null +++ b/eip-0026.md @@ -0,0 +1,107 @@ +Local Exchange Trading System +============================= + +* Author: kushti, scalahub +* Track: applications +* Status: Proposed +* Created: 09-Aug-2019 +* Last edited: 17-June-2020 +* License: CC0 +* Forking: not needed + +Motivation +---------- + +Trustless LETS +-------------- + +**Registration Contract** allows new members to join by depositing collateral more than minimal value. + +``` +{ + val letsTokenId = fromBase58("") + val letsBoxScriptHash = fromBase58("") + val deadline = 1024 + val minErgsToJoin = 100000000 + + + // a tokenBox stores the membership tokens and has this script + val tokenBox = OUTPUTS(0) // the first output must also be a tokenBox + // first output contains remaining LETS tokens + + val letsBox = OUTPUTS(1) + + def isLets(b:Box) = { // returns true if b is a LETS box + // A LETS box must have exactly 1 membership token in tokens(0) + b.tokens(0)._1 == letsTokenId && b.tokens(0)._2 == 1 && + blake2b256(b.propositionBytes) == letsBoxScriptHash && + SELF.R4[Long].get == 0 && // start the box with zero LETS balance + b.value >= minErgsToJoin && // the box must contain some minimum ergs + b.R6[Long].get >= HEIGHT + deadline // store deposit deadline height in R6 + } + + // In the transaction following is preserved for the token box ... + tokenBox.tokens(0)._1 == SELF.tokens(0)._1 && // token id + tokenBox.tokens(0)._2 == SELF.tokens(0)._2 - 1 && // quantity + tokenBox.propositionBytes == SELF.propositionBytes && + isLets(letsBox) +} +``` + +**LETS contract* allows participants to perform an act of economic exchange, creating IOC (I Own Community) debt to back +the exchange + +``` +{ + val rateTokenId = fromBase58("") // oracle NFT + val letsTokenId = fromBase58("") // LETS membership token + + val validRateOracle = CONTEXT.dataInputs(0).tokens(0)._1 == rateTokenId + val rate = CONTEXT.dataInputs(0).R4[Int].get + + val inBalance = SELF.R4[Long].get // LETS balance of current input + val pubKey = SELF.R5[SigmaProp].get // owner of the current input + val deadline = SELF.R6[Long].get // minHeight to withdraw collateral, even partly + + val otherInputIndex = getVar[Short](0).get + val selfOutIndex = getVar[Short](1).get // index of the self-related output + val otherOutIndex = getVar[Short](2).get // index of the counterparty's output] + + val otherInput = INPUTS(otherInputIndex) + val selfOut = OUTPUTS(selfOutIndex) + val otherOut = OUTPUTS(otherOutIndex) + val outBalance = selfOut.R4[Long].get // LETS balance of the output + + // A LETS box is one that has the same script as the current box + + val getBalance = {(b:Box) => b.R4[Long].get} // returns LETS balance of a box + + // sender box can contain less amount of ergs (sender may withdraw ergs provided + // that any negative LETS balance of sender in out is backed by sufficient ergs) + val correctErgs = selfOut.value >= -outBalance * rate && ( + selfOut.value >= SELF.value || SELF.R6[Long].get < HEIGHT + ) + + val balancePreserved = { + getBalance(SELF) + getBalance(otherInput) == getBalance(selfOut) + getBalance(otherOut) + } + + // for the receiver, we don't touch the erg balance, + // since a receiver is not actively involved in the transaction + inBalance != outBalance && // some transaction should occur; balance must change + SELF.id != otherInput.id && + SELF.tokens(0)._1 == letsTokenId && // the current input has the right token + selfOut.tokens(0)._1 == letsTokenId && // corresponding output has the right token + validRateOracle && // oracle providing rate has the correct "rate token" + balancePreserved && // total LETS balance is preserved in the transaction + selfOut.propositionBytes == SELF.propositionBytes && // out is a LETS box ... + selfOut.R5[SigmaProp].get == pubKey && // ... with the right pub key + selfOut.R6[Long].get == SELF.R6[Long].get && // ... and creation height + (pubKey && correctErgs) // ... or out has correct ergs and tx has signature +} +``` + + + + + \ No newline at end of file