From bea700d9f329613b747045b6963c48ec9594e3ea Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 21 Jan 2025 23:00:27 +0300 Subject: [PATCH 1/5] selfRegisters check --- contracts/onchain/note.es | 2 +- contracts/onchain/reserve.es | 40 +++++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/contracts/onchain/note.es b/contracts/onchain/note.es index b1331ce..e3263b7 100644 --- a/contracts/onchain/note.es +++ b/contracts/onchain/note.es @@ -16,7 +16,7 @@ // tree contains reserveId as a key, signature as value, // and message under the signature is position in the tree, note value and token id // R5 - current holder of the note (public key given as a group element) - // R6 - current length of the chain (as long int) + // R6 - current length of the spendings chain (as long int) // // tokens: // #0 - token which amount is equal to note value at the moment of issueance, in unit of account (mg of gold). diff --git a/contracts/onchain/reserve.es b/contracts/onchain/reserve.es index 65e88e6..62df384 100644 --- a/contracts/onchain/reserve.es +++ b/contracts/onchain/reserve.es @@ -4,8 +4,9 @@ // Data: // - token #0 - identifying singleton token // - R4 - signing key (as a group element) - // - R5 - refund init height (None if not set) - // - R6 - amount to refund (None if not set) + // - R5 - refund init height (None if not set) - int + // - R6 - amount to refund (None if not set) - long + // - R7 - trees of all the note tokens issued // // Actions: // - redeem note (#0) @@ -20,11 +21,33 @@ val ownerKey = SELF.R4[GroupElement].get // reserve owner's key, used in notes and unlock/lock/refund actions val selfOut = OUTPUTS(index) + + // common checks for all the paths (not incl. ERG value check) val selfPreserved = selfOut.propositionBytes == SELF.propositionBytes && selfOut.tokens == SELF.tokens && selfOut.R4[GroupElement].get == SELF.R4[GroupElement].get + def selfRegisters(checks: (Boolean, Boolean)) = { + val refundCheck = checks._1 + val noteTreeCheck = checks._2 + + val refundRegisters = if(refundCheck) { + selfOut.R5[Int] == SELF.R5[Int] && + selfOut.R6[Long] == SELF.R6[Long] + } else { + true + } + + val noteTree = if(noteTreeCheck) { + selfOut.R7[AvlTree] == SELF.R7[AvlTree] + } else { + true + } + + refundRegisters && noteTree + } + if (action == 0) { // redemption path @@ -121,29 +144,32 @@ true } - sigmaProp(selfPreserved && properOracle && redeemCorrect && properSignature && properReceipt && positionCorrect) + sigmaProp(selfPreserved && selfRegisters((true, true)) && properOracle && redeemCorrect && properSignature && properReceipt && positionCorrect) } else if (action == 1) { // top up - sigmaProp(selfPreserved && (selfOut.value - SELF.value >= 1000000000)) // at least 1 ERG added + sigmaProp(selfPreserved && selfRegisters((true, true)) && (selfOut.value - SELF.value >= 1000000000)) // at least 1 ERG added + } else if (action == 5) { + // issue a note + sigmaProp(selfPreserved && selfRegisters((true, false))) } else { // todo: write tests for refund paths, document them if (action == 2) { // init refund val correctHeight = selfOut.R5[Int].get >= HEIGHT - 5 val correctValue = selfOut.value >= SELF.value - sigmaProp(selfPreserved && correctHeight && correctValue) && proveDlog(ownerKey) + sigmaProp(selfPreserved && selfRegisters((false, true)) && correctHeight && correctValue) && proveDlog(ownerKey) } else if (action == 3) { // cancel refund val correctHeight = !(selfOut.R5[Int].isDefined) val correctValue = selfOut.value >= SELF.value - sigmaProp(selfPreserved && correctHeight && correctValue) && proveDlog(ownerKey) + sigmaProp(selfPreserved && selfRegisters((false, true)) && correctHeight && correctValue) && proveDlog(ownerKey) } else if (action == 4) { // complete refund val refundNotificationPeriod = 14400 // 20 days val correctHeight = (SELF.R5[Int].get + refundNotificationPeriod) <= HEIGHT val refundLimit = SELF.R6[Long].get val correctValue = SELF.value - selfOut.value <= refundLimit - sigmaProp(selfPreserved && correctHeight && correctValue) && proveDlog(ownerKey) // todo: check is it ok to check no other conditions + sigmaProp(selfPreserved && selfRegisters((false, true)) && correctHeight && correctValue) && proveDlog(ownerKey) // todo: check is it ok to check no other conditions } else { sigmaProp(false) } From 1d9ae267a0a6cef3d99c442c99a6cb5b119d99f9 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 24 Jan 2025 00:31:08 +0300 Subject: [PATCH 2/5] removing refund related actions and registers --- contracts/onchain/reserve.es | 58 +++++------------------------------- 1 file changed, 7 insertions(+), 51 deletions(-) diff --git a/contracts/onchain/reserve.es b/contracts/onchain/reserve.es index 62df384..b8e3e0f 100644 --- a/contracts/onchain/reserve.es +++ b/contracts/onchain/reserve.es @@ -4,16 +4,12 @@ // Data: // - token #0 - identifying singleton token // - R4 - signing key (as a group element) - // - R5 - refund init height (None if not set) - int - // - R6 - amount to refund (None if not set) - long - // - R7 - trees of all the note tokens issued + // - R5 - trees of all the note tokens issued TODO: check preservation in actions // // Actions: // - redeem note (#0) // - top up (#1) - // - init refund (#2) - // - cancel refund (#3) - // - complete refund (#4) + // - mint note (#2) val v = getVar[Byte](0).get val action = v / 10 @@ -28,26 +24,6 @@ selfOut.tokens == SELF.tokens && selfOut.R4[GroupElement].get == SELF.R4[GroupElement].get - def selfRegisters(checks: (Boolean, Boolean)) = { - val refundCheck = checks._1 - val noteTreeCheck = checks._2 - - val refundRegisters = if(refundCheck) { - selfOut.R5[Int] == SELF.R5[Int] && - selfOut.R6[Long] == SELF.R6[Long] - } else { - true - } - - val noteTree = if(noteTreeCheck) { - selfOut.R7[AvlTree] == SELF.R7[AvlTree] - } else { - true - } - - refundRegisters && noteTree - } - if (action == 0) { // redemption path @@ -144,35 +120,15 @@ true } - sigmaProp(selfPreserved && selfRegisters((true, true)) && properOracle && redeemCorrect && properSignature && properReceipt && positionCorrect) + sigmaProp(selfPreserved && properOracle && redeemCorrect && properSignature && properReceipt && positionCorrect) } else if (action == 1) { // top up - sigmaProp(selfPreserved && selfRegisters((true, true)) && (selfOut.value - SELF.value >= 1000000000)) // at least 1 ERG added - } else if (action == 5) { + sigmaProp(selfPreserved && (selfOut.value - SELF.value >= 1000000000)) // at least 1 ERG added + } else if (action == 2) { // issue a note - sigmaProp(selfPreserved && selfRegisters((true, false))) + sigmaProp(selfPreserved) } else { - // todo: write tests for refund paths, document them - if (action == 2) { - // init refund - val correctHeight = selfOut.R5[Int].get >= HEIGHT - 5 - val correctValue = selfOut.value >= SELF.value - sigmaProp(selfPreserved && selfRegisters((false, true)) && correctHeight && correctValue) && proveDlog(ownerKey) - } else if (action == 3) { - // cancel refund - val correctHeight = !(selfOut.R5[Int].isDefined) - val correctValue = selfOut.value >= SELF.value - sigmaProp(selfPreserved && selfRegisters((false, true)) && correctHeight && correctValue) && proveDlog(ownerKey) - } else if (action == 4) { - // complete refund - val refundNotificationPeriod = 14400 // 20 days - val correctHeight = (SELF.R5[Int].get + refundNotificationPeriod) <= HEIGHT - val refundLimit = SELF.R6[Long].get - val correctValue = SELF.value - selfOut.value <= refundLimit - sigmaProp(selfPreserved && selfRegisters((false, true)) && correctHeight && correctValue) && proveDlog(ownerKey) // todo: check is it ok to check no other conditions - } else { - sigmaProp(false) - } + sigmaProp(false) } } \ No newline at end of file From b0a983b9a842dc67a266f2d5ab69786b46789e15 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sun, 26 Jan 2025 22:27:24 +0300 Subject: [PATCH 3/5] mint action, note creation height check on redemption --- contracts/onchain/reserve.es | 53 +++++++++++- src/test/scala/chaincash/ChainCashSpec.scala | 86 ++++---------------- 2 files changed, 67 insertions(+), 72 deletions(-) diff --git a/contracts/onchain/reserve.es b/contracts/onchain/reserve.es index b8e3e0f..46131cb 100644 --- a/contracts/onchain/reserve.es +++ b/contracts/onchain/reserve.es @@ -11,6 +11,9 @@ // - top up (#1) // - mint note (#2) + // we allow multiple reserves to be used in a transaction, for that, single context extension variable #0 + // is encoding both action to take and output index in following way: + val v = getVar[Byte](0).get val action = v / 10 val index = v % 10 @@ -31,6 +34,15 @@ // #1 - receipt // #2 - buyback + // Context var used: + // #1 + // #2 + // #3 + // #4 + // #5 + // #6 - note creation height + // #7 - note token proof + val g: GroupElement = groupGenerator // if set, re-redemption against receipt data is done, otherwise, a note is redeemed @@ -109,7 +121,7 @@ receiptOut.tokens(0) == noteInput.tokens(0) && receiptOut.R4[AvlTree].get == history && receiptOut.R5[Long].get == position && - receiptOut.R6[Int].get >= HEIGHT - 20 && // 20 blocks for inclusion + receiptOut.R6[Int].get >= HEIGHT - 10 && // 10 blocks for inclusion receiptOut.R6[Int].get <= HEIGHT && receiptOut.R7[GroupElement].get == ownerKey @@ -120,13 +132,46 @@ true } - sigmaProp(selfPreserved && properOracle && redeemCorrect && properSignature && properReceipt && positionCorrect) + // check note creation + val creationHeight = getVar[Long](6).get + val tokenProof = getVar[Coll[Byte]](7).get + val tokensTree = SELF.R5[AvlTree].get + + val redemptionTimeCorrect = (HEIGHT - creationHeight > 7200) && // 10 days + tokensTree.get(noteTokenId, tokenProof).get == longToByteArray(creationHeight) + + sigmaProp(selfPreserved && properOracle && redeemCorrect && properSignature && properReceipt && + positionCorrect && redemptionTimeCorrect) } else if (action == 1) { // top up + // anyone can add, so we have 1 ERG minimum to add to avoid spam sigmaProp(selfPreserved && (selfOut.value - SELF.value >= 1000000000)) // at least 1 ERG added } else if (action == 2) { - // issue a note - sigmaProp(selfPreserved) + // mint a note + + val noteTokensTreeIn = SELF.R5[AvlTree].get + + val noteTokensTreeOut = selfOut.R5[AvlTree].get + + val noteOut = OUTPUTS(index + 1) // note output is next after reserve + + val noteToken = noteOut.tokens(0) + + val noteTokenId = noteToken._1 + val noteTokenAmount = noteToken._2 + + val height = getVar[Long](1).get + + val heightCorrect = height >= HEIGHT - 10 && // 10 blocks for inclusion + height <= HEIGHT + + val proof = getVar[Coll[Byte]](2).get + val treeCorrect = noteTokensTreeIn.insert(Coll((noteTokenId, longToByteArray(height))), proof).get == noteTokensTreeOut + + // todo: check note script ? check that all the tokens locked in the not output? check that note history is empty? + // todo: or such checks can be done offchain only ? + + sigmaProp(proveDlog(ownerKey) && selfPreserved && heightCorrect && treeCorrect) } else { sigmaProp(false) } diff --git a/src/test/scala/chaincash/ChainCashSpec.scala b/src/test/scala/chaincash/ChainCashSpec.scala index a01fee7..137bda9 100644 --- a/src/test/scala/chaincash/ChainCashSpec.scala +++ b/src/test/scala/chaincash/ChainCashSpec.scala @@ -12,6 +12,7 @@ import org.scalatest.{Matchers, PropSpec} import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks import scorex.crypto.hash.Blake2b256 import scorex.util.encode.{Base16, Base64} +import scorex.util.idToBytes import sigmastate.AvlTreeFlags import sigmastate.basics.DLogProtocol.ProveDlog import sigmastate.eval._ @@ -226,16 +227,24 @@ class ChainCashSpec extends PropSpec with Matchers with ScalaCheckDrivenProperty val msg: Array[Byte] = positionBytes ++ Longs.toByteArray(noteValue) ++ Base16.decode(noteTokenId).get val sig = SigUtils.sign(msg, holderSecret) - val plasmaMap = new PlasmaMap[Array[Byte], Array[Byte]](AvlTreeFlags.InsertOnly, chainCashPlasmaParameters) + val sigMap = new PlasmaMap[Array[Byte], Array[Byte]](AvlTreeFlags.InsertOnly, chainCashPlasmaParameters) val sigBytes = GroupElementSerializer.toBytes(sig._1) ++ sig._2.toByteArray val keyBytes = positionBytes ++ reserveNFTBytes - val insertRes = plasmaMap.insert(keyBytes -> sigBytes) + val insertRes = sigMap.insert(keyBytes -> sigBytes) val _ = insertRes.proof - val historyTree = plasmaMap.ergoValue.getValue - - val lookupRes = plasmaMap.lookUp(keyBytes) + val historyTree = sigMap.ergoValue.getValue + val lookupRes = sigMap.lookUp(keyBytes) val lookupProof = lookupRes.proof + val noteCreationHeight = ctx.getHeight - 7201 + val noteTokensMap = new PlasmaMap[Array[Byte], Array[Byte]](AvlTreeFlags.InsertOnly, PlasmaParameters(32, None)) + val noteIdBytes = Base16.decode(noteTokenId).get + val noteHeightBytes = Longs.toByteArray(noteCreationHeight) + noteTokensMap.insert(noteIdBytes -> noteHeightBytes) + val noteTokensTree = noteTokensMap.ergoValue.getValue + val noteHeightLookupRes = noteTokensMap.lookUp(noteIdBytes) + val noteHeightLookupProof = noteHeightLookupRes.proof + val noteInput = ctx .newTxBuilder() @@ -256,7 +265,7 @@ class ChainCashSpec extends PropSpec with Matchers with ScalaCheckDrivenProperty .outBoxBuilder .value(minValue) .tokens(new ErgoToken(reserveNFTBytes, 1)) - .registers(ErgoValue.of(holderPk)) + .registers(ErgoValue.of(holderPk), ErgoValue.of(noteTokensTree)) .contract(ctx.compileContract(ConstantsBuilder.empty(), Constants.reserveContract)) .build() .convertToInputWith(fakeTxId2, fakeIndex) @@ -265,7 +274,9 @@ class ChainCashSpec extends PropSpec with Matchers with ScalaCheckDrivenProperty new ContextVar(1, ErgoValue.of(lookupProof.bytes)), new ContextVar(2, ErgoValue.of(Longs.toByteArray(noteValue))), new ContextVar(3, ErgoValue.of(position)), - new ContextVar(4, ErgoValue.of(false)) + new ContextVar(4, ErgoValue.of(false)), + new ContextVar(6, ErgoValue.of(noteCreationHeight.toLong)), + new ContextVar(7, ErgoValue.of(noteHeightLookupProof.bytes)) ) val buyBackInput = @@ -842,65 +853,4 @@ class ChainCashSpec extends PropSpec with Matchers with ScalaCheckDrivenProperty } } - property("refund - init") { - createMockedErgoClient(MockData(Nil, Nil)).execute { implicit ctx: BlockchainContext => - val reserveInput = - ctx - .newTxBuilder() - .outBoxBuilder - .value(minValue) - .tokens(new ErgoToken(reserveNFTBytes, 1)) - .registers(ErgoValue.of(holderPk)) - .contract(ctx.compileContract(ConstantsBuilder.empty(), Constants.reserveContract)) - .build() - .convertToInputWith(fakeTxId2, fakeIndex) - .withContextVars( - new ContextVar(0, ErgoValue.of(20: Byte)) - ) - - val fundingBox = - ctx - .newTxBuilder() - .outBoxBuilder - .value(minValue) - .contract(ctx.compileContract(ConstantsBuilder.empty(), fakeScript)) - .build() - .convertToInputWith(fakeTxId1, fakeIndex) - - val reserveOutput = createOut( - Constants.reserveContract, - minValue, - registers = Array(ErgoValue.of(holderPk), ErgoValue.of(ctx.getHeight - 2)), - tokens = Array(new ErgoToken(reserveNFT, 1)) - ) - - val inputs = Array[InputBox](fundingBox, reserveInput) - val dataInputs = Array[InputBox]() - val outputs = Array[OutBoxImpl](reserveOutput) - - createTx( - inputs, - dataInputs, - outputs, - fee = None , - changeAddress, - Array[String](holderSecret.toString()), - false - ) - } - } - - property("refund - cancel") { - // todo: - } - - - property("refund - done") { - // todo: - } - - property("top-up") { - // todo: - } - } From c9fbcd8f66a59c3105ea5c60829bd897451667fb Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sun, 2 Feb 2025 22:24:27 +0300 Subject: [PATCH 4/5] ramics -> conf, intro fixes --- contracts/onchain/registry.es | 0 contracts/onchain/reserve.es | 18 ++++++++++++------ docs/{ramics => conf}/.gitignore | 0 docs/{ramics => conf}/IEEEtran.cls | 0 docs/conf/compile.sh | 14 ++++++++++++++ docs/{ramics/ramics.tex => conf/conf.tex} | 6 +++--- docs/{ramics => conf}/sources.bib | 0 docs/ramics/compile.sh | 14 -------------- 8 files changed, 29 insertions(+), 23 deletions(-) create mode 100644 contracts/onchain/registry.es rename docs/{ramics => conf}/.gitignore (100%) rename docs/{ramics => conf}/IEEEtran.cls (100%) create mode 100755 docs/conf/compile.sh rename docs/{ramics/ramics.tex => conf/conf.tex} (98%) rename docs/{ramics => conf}/sources.bib (100%) delete mode 100755 docs/ramics/compile.sh diff --git a/contracts/onchain/registry.es b/contracts/onchain/registry.es new file mode 100644 index 0000000..e69de29 diff --git a/contracts/onchain/reserve.es b/contracts/onchain/reserve.es index 46131cb..78c45f8 100644 --- a/contracts/onchain/reserve.es +++ b/contracts/onchain/reserve.es @@ -132,13 +132,17 @@ true } - // check note creation - val creationHeight = getVar[Long](6).get - val tokenProof = getVar[Coll[Byte]](7).get - val tokensTree = SELF.R5[AvlTree].get + val redemptionTimeCorrect = if(position == 0) { + // check note creation + val creationHeight = getVar[Long](6).get + val tokenProof = getVar[Coll[Byte]](7).get + val tokensTree = SELF.R5[AvlTree].get - val redemptionTimeCorrect = (HEIGHT - creationHeight > 7200) && // 10 days + (HEIGHT - creationHeight > 7200) && // 10 days tokensTree.get(noteTokenId, tokenProof).get == longToByteArray(creationHeight) + } else { + true + } sigmaProp(selfPreserved && properOracle && redeemCorrect && properSignature && properReceipt && positionCorrect && redemptionTimeCorrect) @@ -168,10 +172,12 @@ val proof = getVar[Coll[Byte]](2).get val treeCorrect = noteTokensTreeIn.insert(Coll((noteTokenId, longToByteArray(height))), proof).get == noteTokensTreeOut + val positionCorrect = noteOut.R6[Long].get == 0L + // todo: check note script ? check that all the tokens locked in the not output? check that note history is empty? // todo: or such checks can be done offchain only ? - sigmaProp(proveDlog(ownerKey) && selfPreserved && heightCorrect && treeCorrect) + sigmaProp(proveDlog(ownerKey) && selfPreserved && heightCorrect && treeCorrect && positionCorrect) } else { sigmaProp(false) } diff --git a/docs/ramics/.gitignore b/docs/conf/.gitignore similarity index 100% rename from docs/ramics/.gitignore rename to docs/conf/.gitignore diff --git a/docs/ramics/IEEEtran.cls b/docs/conf/IEEEtran.cls similarity index 100% rename from docs/ramics/IEEEtran.cls rename to docs/conf/IEEEtran.cls diff --git a/docs/conf/compile.sh b/docs/conf/compile.sh new file mode 100755 index 0000000..f2ce08c --- /dev/null +++ b/docs/conf/compile.sh @@ -0,0 +1,14 @@ +rm conf.aux +rm conf.out +rm conf.log +rm conf.bbl +rm conf.blg +pdflatex conf +bibtex conf +pdflatex conf +pdflatex conf +rm conf.aux +rm conf.out +rm conf.log +rm conf.bbl +rm conf.blg diff --git a/docs/ramics/ramics.tex b/docs/conf/conf.tex similarity index 98% rename from docs/ramics/ramics.tex rename to docs/conf/conf.tex index 05c27a5..1938c5f 100644 --- a/docs/ramics/ramics.tex +++ b/docs/conf/conf.tex @@ -63,7 +63,7 @@ \title{Money Creation With Elastic Supply Via Trust And Blockchain Assets In Global Digital Peer-to-Peer Environment} -\author{kushti \\ \href{mailto:kushti@protonmail.ch}{kushti@protonmail.ch} \and scalahub} +% \author{kushti \\ \href{mailto:kushti@protonmail.ch}{kushti@protonmail.ch} \and scalahub} \maketitle @@ -73,7 +73,7 @@ protocol allows for elastic money creation in peer-to-peer environment. Acceptance of notes created or signed by other peers made an individual choice. Similarly to spender-signed currencies, every spender is signing and backing a note. Every signature is associated with a reserve, which can be made of any blockchain token, or be empty. A note may -be redeemed against any reserve of its signers, and then re-redeemed against a reserve associated with earlier signature. +be redeemed against any reserve of its signers, and then re-redeemed against a reserve associated with an earlier signature. We have implemented our proposal in software in form of a payment server, supporting flexible rules for notes acceptance, based on blacklist, whitelist, collateralization ratio. We have shown how to implement a local exchange trading system (LETS) @@ -82,7 +82,7 @@ \section{Introduction} -Currently, most of monetary value is created by private banks~(often, offshore banks as in so-called \"eurodollar\" +Currently, most of monetary value is created by private banks~(often, offshore banks as in so-called eurodollar system~\cite{machlup1970euro}), following central banks requirements. As an alternative, starting with Bitcoin~\cite{nakamoto2008peer} launch in 2009, a lot of cryptocurrencies and applications on top of public blockchains are experimenting with algorithmic money issuance. As another option, we also have alternative (usually, local), diff --git a/docs/ramics/sources.bib b/docs/conf/sources.bib similarity index 100% rename from docs/ramics/sources.bib rename to docs/conf/sources.bib diff --git a/docs/ramics/compile.sh b/docs/ramics/compile.sh deleted file mode 100755 index f9b6bc5..0000000 --- a/docs/ramics/compile.sh +++ /dev/null @@ -1,14 +0,0 @@ -rm ramics.aux -rm ramics.out -rm ramics.log -rm ramics.bbl -rm ramics.blg -pdflatex ramics -bibtex ramics -pdflatex ramics -pdflatex ramics -rm ramics.aux -rm ramics.out -rm ramics.log -rm ramics.bbl -rm ramics.blg From f5d2b75e9b1afc258be9fad9622e930f8b742436 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Sun, 2 Feb 2025 22:25:35 +0300 Subject: [PATCH 5/5] mint action removed --- contracts/onchain/registry.es | 9 +++++++ contracts/onchain/reserve.es | 48 +++++++---------------------------- 2 files changed, 18 insertions(+), 39 deletions(-) diff --git a/contracts/onchain/registry.es b/contracts/onchain/registry.es index e69de29..5d433bd 100644 --- a/contracts/onchain/registry.es +++ b/contracts/onchain/registry.es @@ -0,0 +1,9 @@ +{ + // + // tokens: + // #0 - note registration token + + val selfOut = OUTPUTS + + +} \ No newline at end of file diff --git a/contracts/onchain/reserve.es b/contracts/onchain/reserve.es index 78c45f8..3b9ec83 100644 --- a/contracts/onchain/reserve.es +++ b/contracts/onchain/reserve.es @@ -132,17 +132,15 @@ true } - val redemptionTimeCorrect = if(position == 0) { - // check note creation - val creationHeight = getVar[Long](6).get - val tokenProof = getVar[Coll[Byte]](7).get - val tokensTree = SELF.R5[AvlTree].get - - (HEIGHT - creationHeight > 7200) && // 10 days - tokensTree.get(noteTokenId, tokenProof).get == longToByteArray(creationHeight) - } else { - true - } + val noteRegistryInputIdx = getVar[Int](6).get + val noteRegistryInput = CONTEXT.dataInputs(noteRegistryInputIdx) + val registrationTokenCorrect = noteRegistryInput.tokens(0)._1 == fromBase16("") // todo: set value + val registrationBoxCorrect = noteRegistryInput.R4[Coll[Byte]].get == noteTokenId + val creationHeight = noteRegistryInput.R5[Int].get + + val redemptionTimeCorrect = (HEIGHT - creationHeight > 7200) && // 10 days + registrationTokenCorrect && + registrationBoxCorrect sigmaProp(selfPreserved && properOracle && redeemCorrect && properSignature && properReceipt && positionCorrect && redemptionTimeCorrect) @@ -150,34 +148,6 @@ // top up // anyone can add, so we have 1 ERG minimum to add to avoid spam sigmaProp(selfPreserved && (selfOut.value - SELF.value >= 1000000000)) // at least 1 ERG added - } else if (action == 2) { - // mint a note - - val noteTokensTreeIn = SELF.R5[AvlTree].get - - val noteTokensTreeOut = selfOut.R5[AvlTree].get - - val noteOut = OUTPUTS(index + 1) // note output is next after reserve - - val noteToken = noteOut.tokens(0) - - val noteTokenId = noteToken._1 - val noteTokenAmount = noteToken._2 - - val height = getVar[Long](1).get - - val heightCorrect = height >= HEIGHT - 10 && // 10 blocks for inclusion - height <= HEIGHT - - val proof = getVar[Coll[Byte]](2).get - val treeCorrect = noteTokensTreeIn.insert(Coll((noteTokenId, longToByteArray(height))), proof).get == noteTokensTreeOut - - val positionCorrect = noteOut.R6[Long].get == 0L - - // todo: check note script ? check that all the tokens locked in the not output? check that note history is empty? - // todo: or such checks can be done offchain only ? - - sigmaProp(proveDlog(ownerKey) && selfPreserved && heightCorrect && treeCorrect && positionCorrect) } else { sigmaProp(false) }