From 9f9835cbd70ce1df91edf4b7b4fd49dd2fa14f05 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 7 May 2020 09:16:54 +0300 Subject: [PATCH 01/13] comments; --- .../org/ergoplatform/playgrounds/examples/DEXPlayground.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index a887c7a..8b5e190 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -30,6 +30,8 @@ object DEXPlayground { } } + // TODO: check that counter orders are sorted by token price + // TODO: only part of it is matched // TODO: for multiplse sell orders sort by price // val spendingSellOrderTokenInfo = spendingSellOrders.map { (b: Box) => From ca88e94a191f38f268c97a01e5bf1051891ce0ee Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 7 May 2020 17:22:26 +0300 Subject: [PATCH 02/13] calc full spread instead of spread per token; formatting; --- .../playgrounds/examples/DEXPlayground.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index f0ed551..cd57194 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -56,13 +56,13 @@ object DEXPlayground { b.R6[Coll[Byte]].isDefined && b.R6[Coll[Byte]].get == SELF.id && b.propositionBytes == SELF.propositionBytes } - val spreadPerToken = { + val fullSpread = { if (spendingSellOrders.size == 1) { val sellOrder = spendingSellOrders(0) val sellOrderTokenPrice = sellOrder.R5[Long].get // TODO: if both orders were in the same block who gets the spread? - if (sellOrder.creationInfo._1 >=SELF.creationInfo._1 && sellOrderTokenPrice <=tokenPrice) - tokenPrice - sellOrderTokenPrice + if (sellOrder.creationInfo._1 >= SELF.creationInfo._1 && sellOrderTokenPrice <= tokenPrice) + (tokenPrice - sellOrderTokenPrice) * returnTokenAmount else 0L } else @@ -70,11 +70,11 @@ object DEXPlayground { } val totalMatching = (SELF.value - expectedDexFee) == returnTokenAmount * tokenPrice && - returnBox.value >=returnTokenAmount * spreadPerToken + returnBox.value >= fullSpread val partialMatching = { foundNewOrderBoxes.size == 1 && foundNewOrderBoxes(0).value == (SELF.value - returnTokenAmount * tokenPrice - expectedDexFee) && - returnBox.value >=returnTokenAmount * spreadPerToken + returnBox.value >= fullSpread } val coinsSecured = partialMatching ||totalMatching @@ -514,9 +514,9 @@ object DEXPlayground { val cancelTxFee = MinTxFee val sellerReturnBox = Box( - value = sellOrderBox.value - cancelTxFee, - token = (token -> sellerAskTokenAmount), - script = contract(sellerParty.wallet.getAddress.pubKey) + value = sellOrderBox.value - cancelTxFee, + token = (token -> sellerAskTokenAmount), + script = contract(sellerParty.wallet.getAddress.pubKey) ) val cancelSellTransaction = Transaction( From fd95cc3cdcb98aaea5e30447529c98ad83f1de36 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 7 May 2020 18:06:12 +0300 Subject: [PATCH 03/13] draft buyer contract for multiple counter orders; --- .../playgrounds/examples/DEXPlayground.scala | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index cd57194..885554d 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -16,6 +16,9 @@ object DEXPlayground { val buyerContractEnv: ScriptEnv = Map("buyerPk" -> buyerPk, "tokenId" -> token.tokenId) + // TODO : check that counter orders are sorted by token price + // TODO: if both orders were in the same block who gets the spread? + // TODO: move price check (from fullSpread) to boxesAreSortedByTokenPrice? val buyerScript = s"""buyerPk || { val tokenPrice = $tokenPrice @@ -30,22 +33,13 @@ object DEXPlayground { } } - // TODO: check that counter orders are sorted by token price - - // TODO: only part of it is matched - // TODO: for multiplse sell orders sort by price - // val spendingSellOrderTokenInfo = spendingSellOrders.map { (b: Box) => - // (b.tokens(0)._2, b.R5[Long].get) - // } - // val totalSpendingSellOrdersValue = spendingSellOrderTokenInfo.fold(0L, { (acc: Long, t: (Long, Long)) => - // acc + (t._1 * t._2) - // }) - val returnBoxes = OUTPUTS.filter { (b: Box) => b.R4[Coll[Byte]].isDefined && b.R4[Coll[Byte]].get == SELF.id && b.propositionBytes == buyerPk.propBytes } - returnBoxes.size == 1 && { + val boxesAreSortedByTokenPrice = { (boxes: Coll[Box]) => true } + + returnBoxes.size == 1 && spendingSellOrders.size > 0 && boxesAreSortedByTokenPrice(spendingSellOrders) && { val returnBox = returnBoxes(0) val returnTokenAmount = if (returnBox.tokens.size == 1) returnBox.tokens(0)._2 else 0L @@ -57,16 +51,29 @@ object DEXPlayground { } val fullSpread = { - if (spendingSellOrders.size == 1) { - val sellOrder = spendingSellOrders(0) + spendingSellOrders.fold((returnTokenAmount, 0L), { (t: (Long, Long), sellOrder: Box) => + val returnTokensLeft = t._1 + val accumulatedFullSpread = t._2 val sellOrderTokenPrice = sellOrder.R5[Long].get - // TODO: if both orders were in the same block who gets the spread? - if (sellOrder.creationInfo._1 >= SELF.creationInfo._1 && sellOrderTokenPrice <= tokenPrice) - (tokenPrice - sellOrderTokenPrice) * returnTokenAmount - else - 0L - } else - 0L + val sellOrderTokenAmount = sellOrder.tokens(0)._2 + if (sellOrder.creationInfo._1 >= SELF.creationInfo._1 && sellOrderTokenPrice <= tokenPrice) { + // spread is ours + val spreadPerToken = tokenPrice - sellOrderTokenPrice + // TODO: rewrite with min(returnTokensLeft, sellOrderTokenAmount)? + if (returnTokensLeft < sellOrderTokenAmount) { + val sellOrderSpread = spreadPerToken * returnTokensLeft + (0L, accumulatedFullSpread + sellOrderSpread) + } else { + val sellOrderSpread = spreadPerToken * sellOrderTokenAmount + (returnTokensLeft - sellOrderTokenAmount, accumulatedFullSpread + sellOrderSpread) + } + } + else { + // spread is not ours + (returnTokensLeft - min(returnTokensLeft, sellOrderTokenAmount), accumulatedFullSpread) + } + })._2 + } val totalMatching = (SELF.value - expectedDexFee) == returnTokenAmount * tokenPrice && From be35c61b2c96536a804d8b7b1c8f484aec8ea84f Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 7 May 2020 18:39:04 +0300 Subject: [PATCH 04/13] rewrite buy order contract full spread accumulation; --- .../playgrounds/examples/DEXPlayground.scala | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index 885554d..a262d7d 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -16,9 +16,9 @@ object DEXPlayground { val buyerContractEnv: ScriptEnv = Map("buyerPk" -> buyerPk, "tokenId" -> token.tokenId) - // TODO : check that counter orders are sorted by token price - // TODO: if both orders were in the same block who gets the spread? + // TODO: check that counter orders are sorted by token price // TODO: move price check (from fullSpread) to boxesAreSortedByTokenPrice? + // TODO: if both orders were in the same block who gets the spread? val buyerScript = s"""buyerPk || { val tokenPrice = $tokenPrice @@ -59,14 +59,9 @@ object DEXPlayground { if (sellOrder.creationInfo._1 >= SELF.creationInfo._1 && sellOrderTokenPrice <= tokenPrice) { // spread is ours val spreadPerToken = tokenPrice - sellOrderTokenPrice - // TODO: rewrite with min(returnTokensLeft, sellOrderTokenAmount)? - if (returnTokensLeft < sellOrderTokenAmount) { - val sellOrderSpread = spreadPerToken * returnTokensLeft - (0L, accumulatedFullSpread + sellOrderSpread) - } else { - val sellOrderSpread = spreadPerToken * sellOrderTokenAmount - (returnTokensLeft - sellOrderTokenAmount, accumulatedFullSpread + sellOrderSpread) - } + val tokenAmount = min(returnTokensLeft, sellOrderTokenAmount) + val sellOrderSpread = spreadPerToken * tokenAmount + (returnTokensLeft - tokenAmount, accumulatedFullSpread + sellOrderSpread) } else { // spread is not ours From 495c5ec0a1dde6c7976daca3ebc2c0b57631b305 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Sat, 9 May 2020 12:01:57 +0300 Subject: [PATCH 05/13] remove unused import; --- .../playgrounds/examples/test/DEXPlaygroundSpec.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/playgrounds/src/test/scala/org/ergoplatform/playgrounds/examples/test/DEXPlaygroundSpec.scala b/playgrounds/src/test/scala/org/ergoplatform/playgrounds/examples/test/DEXPlaygroundSpec.scala index 6bb9bc8..5f65ae0 100644 --- a/playgrounds/src/test/scala/org/ergoplatform/playgrounds/examples/test/DEXPlaygroundSpec.scala +++ b/playgrounds/src/test/scala/org/ergoplatform/playgrounds/examples/test/DEXPlaygroundSpec.scala @@ -1,6 +1,5 @@ package org.ergoplatform.playgrounds.examples.test -import org.ergoplatform.playgrounds.examples.AssetsAtomicExchangePlayground import org.scalatest.PropSpec import org.ergoplatform.playgrounds.examples.DEXPlayground From f9fd75c5d1f6f14f937de278e1f30c146a803be3 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Sun, 10 May 2020 16:48:54 +0300 Subject: [PATCH 06/13] implement boxesAreSortedByTokenPrice; --- .../playgrounds/examples/DEXPlayground.scala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index a262d7d..6966d06 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -17,6 +17,7 @@ object DEXPlayground { Map("buyerPk" -> buyerPk, "tokenId" -> token.tokenId) // TODO: check that counter orders are sorted by token price + // TODO: show contract cost // TODO: move price check (from fullSpread) to boxesAreSortedByTokenPrice? // TODO: if both orders were in the same block who gets the spread? val buyerScript = s"""buyerPk || { @@ -37,7 +38,14 @@ object DEXPlayground { b.R4[Coll[Byte]].isDefined && b.R4[Coll[Byte]].get == SELF.id && b.propositionBytes == buyerPk.propBytes } - val boxesAreSortedByTokenPrice = { (boxes: Coll[Box]) => true } + val boxesAreSortedByTokenPrice = { (boxes: Coll[Box]) => + boxes.fold((0L, true), { (t: (Long, Boolean), box: Box) => + val prevBoxTokenPrice = t._1 + val isSorted = t._2 + val boxTokenPrice = box.R5[Long].getOrElse(0L) + (boxTokenPrice, isSorted && boxTokenPrice >= prevBoxTokenPrice) + })._2 + } returnBoxes.size == 1 && spendingSellOrders.size > 0 && boxesAreSortedByTokenPrice(spendingSellOrders) && { val returnBox = returnBoxes(0) From 65db8a89903f517f668194bc00bb0e700cb2a41c Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Sun, 10 May 2020 18:08:21 +0300 Subject: [PATCH 07/13] draft fullSpread for seller contract; draft multiple counter orders support in seller contract; expose dex fee per token in R6; --- .../playgrounds/examples/DEXPlayground.scala | 76 ++++++++++++------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index 6966d06..997e584 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -16,7 +16,7 @@ object DEXPlayground { val buyerContractEnv: ScriptEnv = Map("buyerPk" -> buyerPk, "tokenId" -> token.tokenId) - // TODO: check that counter orders are sorted by token price + // TODO: put contract type (sell/buy) in register and check in INPUTS filter? // TODO: show contract cost // TODO: move price check (from fullSpread) to boxesAreSortedByTokenPrice? // TODO: if both orders were in the same block who gets the spread? @@ -55,7 +55,7 @@ object DEXPlayground { val foundNewOrderBoxes = OUTPUTS.filter { (b: Box) => val contractParametersAreCorrect = b.R4[Coll[Byte]].get == tokenId && b.R5[Long].get == tokenPrice - b.R6[Coll[Byte]].isDefined && b.R6[Coll[Byte]].get == SELF.id && b.propositionBytes == SELF.propositionBytes + b.R7[Coll[Byte]].isDefined && b.R7[Coll[Byte]].get == SELF.id && b.propositionBytes == SELF.propositionBytes } val fullSpread = { @@ -76,7 +76,6 @@ object DEXPlayground { (returnTokensLeft - min(returnTokensLeft, sellOrderTokenAmount), accumulatedFullSpread) } })._2 - } val totalMatching = (SELF.value - expectedDexFee) == returnTokenAmount * tokenPrice && @@ -125,32 +124,53 @@ object DEXPlayground { b.R4[Coll[Byte]].isDefined && b.R4[Coll[Byte]].get == SELF.id && b.propositionBytes == sellerPk.propBytes } - returnBoxes.size == 1 && { - val returnBox = returnBoxes(0) - val spendingBuyOrders = INPUTS.filter { (b: Box) => - b.R4[Coll[Byte]].isDefined && b.R5[Long].isDefined && { - val buyOrderTokenId = b.R4[Coll[Byte]].get - buyOrderTokenId == tokenId && { - b.tokens.size == 1 && b.tokens(0)._1 == tokenId - } - } + val boxesAreSortedByTokenPrice = { (boxes: Coll[Box]) => + boxes.fold((0L, true), { (t: (Long, Boolean), box: Box) => + val prevBoxTokenPrice = t._1 + val isSorted = t._2 + val boxTokenPrice = box.R5[Long].getOrElse(0L) + (boxTokenPrice, isSorted && boxTokenPrice >= prevBoxTokenPrice) + })._2 + } + + val spendingBuyOrders = INPUTS.filter { (b: Box) => + b.R4[Coll[Byte]].isDefined && b.R5[Long].isDefined && b.R6[Long].isDefined && { + val buyOrderTokenId = b.R4[Coll[Byte]].get + buyOrderTokenId == tokenId && b.tokens.size == 0 } + } - val buyOrder = spendingBuyOrders(0) + returnBoxes.size == 1 && spendingBuyOrders.size > 0 && boxesAreSortedByTokenPrice(spendingBuyOrders) && { + val returnBox = returnBoxes(0) val foundNewOrderBoxes = OUTPUTS.filter { (b: Box) => val contractParametersAreCorrect = b.R4[Coll[Byte]].get == tokenId && b.R5[Long].get == tokenPrice val contractIsTheSame = b.propositionBytes == SELF.propositionBytes - b.R6[Coll[Byte]].isDefined && b.R6[Coll[Byte]].get == SELF.id && contractIsTheSame + b.R7[Coll[Byte]].isDefined && b.R7[Coll[Byte]].get == SELF.id && contractIsTheSame } - val buyOrderTokenPrice = buyOrder.R5[Long].get - val spreadPerToken = if (buyOrder.creationInfo._1 > SELF.creationInfo._1) - buyOrderTokenPrice - tokenPrice - else - 0L + val fullSpread = { (tokenAmount: Long) => + spendingBuyOrders.fold((tokenAmount, 0L), { (t: (Long, Long), buyOrder: Box) => + val returnTokensLeft = t._1 + val accumulatedFullSpread = t._2 + val buyOrderTokenPrice = buyOrder.R5[Long].get + val buyOrderDexFeePerToken = buyOrder.R6[Long].get + val buyOrderTokenAmount = buyOrder.value / (buyOrderTokenPrice + buyOrderDexFeePerToken) + if (buyOrder.creationInfo._1 >= SELF.creationInfo._1 && buyOrderTokenPrice <= tokenPrice) { + // spread is ours + val spreadPerToken = tokenPrice - buyOrderTokenPrice + val tokenAmountLeft = min(returnTokensLeft, buyOrderTokenAmount) + val buyOrderSpread = spreadPerToken * tokenAmountLeft + (returnTokensLeft - tokenAmountLeft, accumulatedFullSpread + buyOrderSpread) + } + else { + // spread is not ours + (returnTokensLeft - min(returnTokensLeft, buyOrderTokenAmount), accumulatedFullSpread) + } + })._2 + } - val totalMatching = (returnBox.value == selfTokenAmount * (tokenPrice + spreadPerToken)) + val totalMatching = (returnBox.value == selfTokenAmount * tokenPrice + fullSpread(selfTokenAmount)) val partialMatching = { foundNewOrderBoxes.size == 1 && { @@ -165,12 +185,12 @@ object DEXPlayground { val tokenIdIsCorrect = newOrderTokenId == tokenId val newOrderValueIsCorrect = newOrderBox.value == (SELF.value - expectedDexFee) - val returnBoxValueIsCorrect = returnBox.value == soldTokenAmount * (tokenPrice + spreadPerToken) + val returnBoxValueIsCorrect = returnBox.value == soldTokenAmount * tokenPrice + fullSpread(soldTokenAmount) tokenIdIsCorrect && soldTokenAmount >= 1 && newOrderValueIsCorrect && returnBoxValueIsCorrect } } - (totalMatching ||partialMatching) && buyOrderTokenPrice >=tokenPrice + (totalMatching || partialMatching) } }""".stripMargin @@ -229,7 +249,8 @@ object DEXPlayground { value = buyOrderBoxValue, script = buyOrderContract, registers = R4 -> token.tokenId, - R5 -> buyersBidTokenPrice + R5 -> buyersBidTokenPrice, + R6 -> buyerDexFeePerToken ) val buyOrderTransaction = Transaction( @@ -291,7 +312,8 @@ object DEXPlayground { script = newSellOrderContract, registers = R4 -> token.tokenId, R5 -> sellerAskTokenPrice, - R6 -> sellOrderTxSigned.outputs(0).id + R6 -> sellerDexFeePerToken, + R7 -> sellOrderTxSigned.outputs(0).id ) val buyerTokenAmountBought = buyerBidTokenAmount / 2 @@ -312,7 +334,8 @@ object DEXPlayground { script = newBuyOrderContract, registers = R4 -> token.tokenId, R5 -> sellerAskTokenPrice, - R6 -> buyOrderTxSigned.outputs(0).id + R6 -> buyerDexFeePerToken, + R7 -> buyOrderTxSigned.outputs(0).id ) val dexParty = blockchainSim.newParty("DEX") @@ -434,7 +457,8 @@ object DEXPlayground { value = buyOrderBoxValue, script = buyOrderContract, registers = R4 -> token.tokenId, - R5 -> buyersBidTokenPrice + R5 -> buyersBidTokenPrice, + R6 -> buyerDexFeePerToken ) val buyOrderTransaction = Transaction( From 43095cb35ee0ef8782f9377c69de262c9dc31962 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Sun, 10 May 2020 18:21:21 +0300 Subject: [PATCH 08/13] move TODOs to PR desc; --- .../org/ergoplatform/playgrounds/examples/DEXPlayground.scala | 4 ---- 1 file changed, 4 deletions(-) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index 997e584..0e768a4 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -16,10 +16,6 @@ object DEXPlayground { val buyerContractEnv: ScriptEnv = Map("buyerPk" -> buyerPk, "tokenId" -> token.tokenId) - // TODO: put contract type (sell/buy) in register and check in INPUTS filter? - // TODO: show contract cost - // TODO: move price check (from fullSpread) to boxesAreSortedByTokenPrice? - // TODO: if both orders were in the same block who gets the spread? val buyerScript = s"""buyerPk || { val tokenPrice = $tokenPrice From e9e9505bc3d6ab76b8f6364c46fd008d9c31d51c Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 11 May 2020 14:49:41 +0300 Subject: [PATCH 09/13] formatting; --- .../org/ergoplatform/playgrounds/examples/DEXPlayground.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index 0e768a4..64a7677 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -82,7 +82,7 @@ object DEXPlayground { returnBox.value >= fullSpread } - val coinsSecured = partialMatching ||totalMatching + val coinsSecured = partialMatching || totalMatching val tokenIdIsCorrect = returnBox.tokens.getOrElse(0, (Coll[Byte](), 0L))._1 == tokenId From e4798629a82e13241348f0f81769a2bb983f1710 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 18 May 2020 13:23:09 +0300 Subject: [PATCH 10/13] add missing new(residual) order box requirements(registers) --- .../playgrounds/examples/DEXPlayground.scala | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index 64a7677..a4a72e1 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -50,8 +50,13 @@ object DEXPlayground { val expectedDexFee = dexFeePerToken * returnTokenAmount val foundNewOrderBoxes = OUTPUTS.filter { (b: Box) => - val contractParametersAreCorrect = b.R4[Coll[Byte]].get == tokenId && b.R5[Long].get == tokenPrice - b.R7[Coll[Byte]].isDefined && b.R7[Coll[Byte]].get == SELF.id && b.propositionBytes == SELF.propositionBytes + val tokenIdParameterIsCorrect = b.R4[Coll[Byte]].isDefined && b.R4[Coll[Byte]].get == tokenId + val tokenPriceParameterIsCorrect = b.R5[Long].isDefined && b.R5[Long].get == tokenPrice + val dexFeePerTokenParameterIsCorrect = b.R6[Long].isDefined && b.R6[Long].get == dexFeePerToken + val contractParametersAreCorrect = tokenIdParameterIsCorrect && tokenPriceParameterIsCorrect + val referenceMe = b.R7[Coll[Byte]].isDefined && b.R7[Coll[Byte]].get == SELF.id + val guardedByTheSameContract = b.propositionBytes == SELF.propositionBytes + contractParametersAreCorrect && referenceMe && guardedByTheSameContract } val fullSpread = { @@ -329,7 +334,7 @@ object DEXPlayground { value = newBuyOrderBoxValue, script = newBuyOrderContract, registers = R4 -> token.tokenId, - R5 -> sellerAskTokenPrice, + R5 -> buyersBidTokenPrice, R6 -> buyerDexFeePerToken, R7 -> buyOrderTxSigned.outputs(0).id ) From 31b6bac7a184d3b479dd72ba3434a41fa6cf36dc Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 18 May 2020 14:25:08 +0300 Subject: [PATCH 11/13] fix missing checks for residual sell order box; --- .../playgrounds/examples/DEXPlayground.scala | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index a4a72e1..588d404 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -145,9 +145,13 @@ object DEXPlayground { val returnBox = returnBoxes(0) val foundNewOrderBoxes = OUTPUTS.filter { (b: Box) => - val contractParametersAreCorrect = b.R4[Coll[Byte]].get == tokenId && b.R5[Long].get == tokenPrice - val contractIsTheSame = b.propositionBytes == SELF.propositionBytes - b.R7[Coll[Byte]].isDefined && b.R7[Coll[Byte]].get == SELF.id && contractIsTheSame + val tokenIdParameterIsCorrect = b.R4[Coll[Byte]].isDefined && b.R4[Coll[Byte]].get == tokenId + val tokenPriceParameterIsCorrect = b.R5[Long].isDefined && b.R5[Long].get == tokenPrice + val dexFeePerTokenParameterIsCorrect = b.R6[Long].isDefined && b.R6[Long].get == dexFeePerToken + val contractParametersAreCorrect = tokenIdParameterIsCorrect && tokenPriceParameterIsCorrect + val referenceMe = b.R7[Coll[Byte]].isDefined && b.R7[Coll[Byte]].get == SELF.id + val guardedByTheSameContract = b.propositionBytes == SELF.propositionBytes + contractParametersAreCorrect && referenceMe && guardedByTheSameContract } val fullSpread = { (tokenAmount: Long) => From e42b5f14e9bfc50be27d69db44e40e17a3d7e58f Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 18 May 2020 14:36:45 +0300 Subject: [PATCH 12/13] for sell order contract require spread only if strictly "younger" than the counter order; --- .../org/ergoplatform/playgrounds/examples/DEXPlayground.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala index 588d404..a201cf5 100644 --- a/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala +++ b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala @@ -161,7 +161,7 @@ object DEXPlayground { val buyOrderTokenPrice = buyOrder.R5[Long].get val buyOrderDexFeePerToken = buyOrder.R6[Long].get val buyOrderTokenAmount = buyOrder.value / (buyOrderTokenPrice + buyOrderDexFeePerToken) - if (buyOrder.creationInfo._1 >= SELF.creationInfo._1 && buyOrderTokenPrice <= tokenPrice) { + if (buyOrder.creationInfo._1 > SELF.creationInfo._1 && buyOrderTokenPrice <= tokenPrice) { // spread is ours val spreadPerToken = tokenPrice - buyOrderTokenPrice val tokenAmountLeft = min(returnTokensLeft, buyOrderTokenAmount) From 152ede5189604b7da34535837747fc03a88eb3e2 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 2 Jun 2020 08:00:46 +0300 Subject: [PATCH 13/13] update Scastie link; --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index efb9604..e2511bd 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ Enjoy: ### DEX with partial filling contracts -[Run in Scastie](https://scastie.scala-lang.org/YCzvl8NBQwa7R0pVI5mHnA) +[Run in Scastie](https://scastie.scala-lang.org/mh3h6SrESnKJwdqZjKnVkw) -[Source code](https://github.com/ergoplatform/ergo-playgrounds/blob/c91117ae0b1434b7a554028592e30a5bba15a14b/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/AssetsAtomicExchangePlayground.scala#L1-L1) +[Source code](https://github.com/ergoplatform/ergo-playgrounds/blob/e42b5f14e9bfc50be27d69db44e40e17a3d7e58f/playgrounds/src/main/scala/org/ergoplatform/playgrounds/examples/DEXPlayground.scala#L3) ### Assets Atomic Exchange contracts