From 24fc88870620b25893efe38badb14e1498768ee8 Mon Sep 17 00:00:00 2001 From: "fateme.r" Date: Sat, 30 Dec 2023 12:54:08 +0330 Subject: [PATCH 1/7] Remove dependency of commitment box on trigger wid list All needed information in commitment box is retrieved from the input and output of the transaction. --- .../scala/rosen/bridge/scripts/Commitment.es | 34 ++++++++++++------- .../rosen/bridge/scripts/EventTrigger.es | 1 + src/test/scala/testUtils/Boxes.scala | 3 +- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/main/scala/rosen/bridge/scripts/Commitment.es b/src/main/scala/rosen/bridge/scripts/Commitment.es index a66ca74..4e07826 100644 --- a/src/main/scala/rosen/bridge/scripts/Commitment.es +++ b/src/main/scala/rosen/bridge/scripts/Commitment.es @@ -9,25 +9,29 @@ val eventTriggerHash = fromBase64("EVENT_TRIGGER_SCRIPT_HASH"); val repoNFT = fromBase64("REPO_NFT"); - val event = if (blake2b256(INPUTS(0).propositionBytes) == eventTriggerHash) INPUTS(0) else OUTPUTS(0) + val trigger = if (blake2b256(INPUTS(0).propositionBytes) == eventTriggerHash) INPUTS(0) else OUTPUTS(0) val myWID = SELF.R4[Coll[Coll[Byte]]].get - val WIDs = event.R4[Coll[Coll[Byte]]].get - val paddedData = event.R5[Coll[Coll[Byte]]].get.fold(Coll(0.toByte), { (a: Coll[Byte], b: Coll[Byte]) => a ++ b } ) - val eventData = paddedData.slice(1, paddedData.size) + val eventData = trigger.R5[Coll[Coll[Byte]]].get.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b}) if(blake2b256(INPUTS(0).propositionBytes) == eventTriggerHash){ + val WIDs = OUTPUTS.filter{(box:Box) + => box.tokens.size > 0 && box.tokens(0)._1 == SELF.tokens(0)._1 + } + .slice(0, trigger.R7[Int].get) + .map{(box:Box) => box.R4[Coll[Coll[Byte]]].get(0)} // Reward Distribution (for missed commitments) // [EventTrigger, Commitments[], BridgeWallet] => [WatcherPermits[], BridgeWallet] - val permitBox = OUTPUTS.filter {(box:Box) => + val permitBoxes = OUTPUTS.filter {(box:Box) => + blake2b256(box.propositionBytes) == SELF.R7[Coll[Byte]].get && box.R4[Coll[Coll[Byte]]].isDefined && box.R4[Coll[Coll[Byte]]].get == myWID - }(0) + } val WIDExists = WIDs.exists {(WID: Coll[Byte]) => myWID == Coll(WID)} sigmaProp( allOf( Coll( - blake2b256(permitBox.propositionBytes) == SELF.R7[Coll[Byte]].get, - permitBox.tokens(0)._1 == SELF.tokens(0)._1, - permitBox.tokens(0)._2 == SELF.tokens(0)._2, + permitBoxes.size == 1, + permitBoxes(0).tokens(0)._1 == SELF.tokens(0)._1, + permitBoxes(0).tokens(0)._2 == SELF.tokens(0)._2, // check for duplicates WIDExists == false, // validate commitment @@ -39,12 +43,16 @@ } else if (blake2b256(OUTPUTS(0).propositionBytes) == eventTriggerHash){ // Event Trigger Creation // [Commitments[]] + [Repo(DataInput)] => [EventTrigger] + val WIDs = INPUTS.filter{ + (box:Box) => box.tokens.size > 0 && box.tokens(0)._1 == SELF.tokens(0)._1 + } + .map{(box:Box) => box.R4[Coll[Coll[Byte]]].get(0)} val commitmentBoxes = INPUTS.filter { (box: Box) => SELF.propositionBytes == box.propositionBytes } val myWIDCommitments = commitmentBoxes.filter{ (box: Box) => box.R4[Coll[Coll[Byte]]].get == myWID } val EventBoxErgs = commitmentBoxes.map { (box: Box) => box.value }.fold(0L, { (a: Long, b: Long) => a + b }) val myWIDExists = WIDs.exists{ (WID: Coll[Byte]) => Coll(WID) == myWID } val repo = CONTEXT.dataInputs(0) - val requestId = blake2b256(event.R5[Coll[Coll[Byte]]].get(0)) + val requestId = blake2b256(trigger.R5[Coll[Coll[Byte]]].get(0)) val repoR6 = repo.R6[Coll[Long]].get val maxCommitment = repoR6(3) val requiredCommitmentFromFormula: Long = repoR6(2) + repoR6(1) * (repo.R4[Coll[Coll[Byte]]].get.size - 1L) / 100L @@ -63,7 +71,7 @@ OUTPUTS(0).value >= EventBoxErgs, myWIDCommitments.size == 1, myWIDExists, - event.R6[Coll[Byte]].get == SELF.R7[Coll[Byte]].get, + trigger.R6[Coll[Byte]].get == SELF.R7[Coll[Byte]].get, WIDs.size == commitmentBoxes.size, // verify commitment to be correct blake2b256(eventData ++ myWID(0)) == SELF.R6[Coll[Byte]].get, @@ -73,8 +81,8 @@ commitmentBoxes.size > requiredCommitment, // Check required RWT SELF.tokens(0)._2 == repoR6(0), - event.tokens(0)._2 == repoR6(0) * commitmentBoxes.size, - event.tokens(0)._1 == SELF.tokens(0)._1 + trigger.tokens(0)._2 == repoR6(0) * commitmentBoxes.size, + trigger.tokens(0)._1 == SELF.tokens(0)._1 ) ) ) diff --git a/src/main/scala/rosen/bridge/scripts/EventTrigger.es b/src/main/scala/rosen/bridge/scripts/EventTrigger.es index 12b2969..ef54063 100644 --- a/src/main/scala/rosen/bridge/scripts/EventTrigger.es +++ b/src/main/scala/rosen/bridge/scripts/EventTrigger.es @@ -3,6 +3,7 @@ // R4: Coll[Coll[Byte]] [WID[]] // R5: Coll[Coll[Byte]] Event data // R6: Coll[Byte] Permit contract script digest + // R7: Int Watchers Count // ----------------- TOKENS // 0: RWT diff --git a/src/test/scala/testUtils/Boxes.scala b/src/test/scala/testUtils/Boxes.scala index b837f42..17edafa 100644 --- a/src/test/scala/testUtils/Boxes.scala +++ b/src/test/scala/testUtils/Boxes.scala @@ -302,7 +302,8 @@ object Boxes { .registers( ErgoValueBuilder.buildFor(Colls.fromArray(WID.map(item => Colls.fromArray(item)).toArray)), ErgoValueBuilder.buildFor(Colls.fromArray(commitment.partsArray().map(item => Colls.fromArray(item)))), - ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))) + ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))), + ErgoValueBuilder.buildFor(WID.size) ).build() } From 2b585c05a682f90ec09dd50b82f6a303d4a5b5ba Mon Sep 17 00:00:00 2001 From: "fateme.r" Date: Sat, 30 Dec 2023 17:08:03 +0330 Subject: [PATCH 2/7] Replace wid list with its digest in trigger --- .../scala/rosen/bridge/scripts/Commitment.es | 25 ++++++++++-------- .../rosen/bridge/scripts/EventTrigger.es | 26 +++++++++++-------- src/test/scala/testUtils/Boxes.scala | 3 ++- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/main/scala/rosen/bridge/scripts/Commitment.es b/src/main/scala/rosen/bridge/scripts/Commitment.es index 4e07826..701889f 100644 --- a/src/main/scala/rosen/bridge/scripts/Commitment.es +++ b/src/main/scala/rosen/bridge/scripts/Commitment.es @@ -11,7 +11,7 @@ val repoNFT = fromBase64("REPO_NFT"); val trigger = if (blake2b256(INPUTS(0).propositionBytes) == eventTriggerHash) INPUTS(0) else OUTPUTS(0) val myWID = SELF.R4[Coll[Coll[Byte]]].get - val eventData = trigger.R5[Coll[Coll[Byte]]].get.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b}) + val eventData = trigger.R4[Coll[Coll[Byte]]].get.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b}) if(blake2b256(INPUTS(0).propositionBytes) == eventTriggerHash){ val WIDs = OUTPUTS.filter{(box:Box) => box.tokens.size > 0 && box.tokens(0)._1 == SELF.tokens(0)._1 @@ -43,16 +43,18 @@ } else if (blake2b256(OUTPUTS(0).propositionBytes) == eventTriggerHash){ // Event Trigger Creation // [Commitments[]] + [Repo(DataInput)] => [EventTrigger] - val WIDs = INPUTS.filter{ - (box:Box) => box.tokens.size > 0 && box.tokens(0)._1 == SELF.tokens(0)._1 + val commitmentBoxes = INPUTS.filter{ + (box: Box) => + SELF.propositionBytes == box.propositionBytes && + box.tokens.size > 0 && + box.tokens(0)._1 == SELF.tokens(0)._1 } - .map{(box:Box) => box.R4[Coll[Coll[Byte]]].get(0)} - val commitmentBoxes = INPUTS.filter { (box: Box) => SELF.propositionBytes == box.propositionBytes } + val WIDs = commitmentBoxes.map{(box:Box) => box.R4[Coll[Coll[Byte]]].get(0)} + val widListDigest = blake2b256(WIDs.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b})) val myWIDCommitments = commitmentBoxes.filter{ (box: Box) => box.R4[Coll[Coll[Byte]]].get == myWID } val EventBoxErgs = commitmentBoxes.map { (box: Box) => box.value }.fold(0L, { (a: Long, b: Long) => a + b }) - val myWIDExists = WIDs.exists{ (WID: Coll[Byte]) => Coll(WID) == myWID } val repo = CONTEXT.dataInputs(0) - val requestId = blake2b256(trigger.R5[Coll[Coll[Byte]]].get(0)) + val requestId = blake2b256(trigger.R4[Coll[Coll[Byte]]].get(0)) val repoR6 = repo.R6[Coll[Long]].get val maxCommitment = repoR6(3) val requiredCommitmentFromFormula: Long = repoR6(2) + repoR6(1) * (repo.R4[Coll[Coll[Byte]]].get.size - 1L) / 100L @@ -67,12 +69,13 @@ //check repo repo.tokens(0)._1 == repoNFT, repo.tokens(1)._1 == SELF.tokens(0)._1, - - OUTPUTS(0).value >= EventBoxErgs, + // prevent duplicate commitments myWIDCommitments.size == 1, - myWIDExists, + // verify trigger params + trigger.value >= EventBoxErgs, trigger.R6[Coll[Byte]].get == SELF.R7[Coll[Byte]].get, - WIDs.size == commitmentBoxes.size, + trigger.R7[Int].get == commitmentBoxes.size, + trigger.R5[Coll[Byte]].get == widListDigest, // verify commitment to be correct blake2b256(eventData ++ myWID(0)) == SELF.R6[Coll[Byte]].get, // check event id diff --git a/src/main/scala/rosen/bridge/scripts/EventTrigger.es b/src/main/scala/rosen/bridge/scripts/EventTrigger.es index ef54063..0d90cda 100644 --- a/src/main/scala/rosen/bridge/scripts/EventTrigger.es +++ b/src/main/scala/rosen/bridge/scripts/EventTrigger.es @@ -1,7 +1,7 @@ { // ----------------- REGISTERS - // R4: Coll[Coll[Byte]] [WID[]] - // R5: Coll[Coll[Byte]] Event data + // R4: Coll[Coll[Byte]] Event data + // R5: Coll[Byte] WID list digest // R6: Coll[Byte] Permit contract script digest // R7: Int Watchers Count // ----------------- TOKENS @@ -29,20 +29,24 @@ ) ) } - val WIDs: Coll[Coll[Byte]] = SELF.R4[Coll[Coll[Byte]]].get - val mergeBoxes = OUTPUTS.slice(0, WIDs.size) - val checkAllWIDs = WIDs.zip(mergeBoxes).forall { - (data: (Coll[Byte], Box)) => { - Coll(data._1) == data._2.R4[Coll[Coll[Byte]]].get && - data._2.propositionBytes == OUTPUTS(0).propositionBytes && - data._2.tokens(0)._1 == SELF.tokens(0)._1 && - data._2.tokens(0)._2 == SELF.tokens(0)._2 / WIDs.size + val watcherCount = SELF.R7[Int].get + val rewards = OUTPUTS.filter{(box:Box) + => box.tokens.size > 0 && box.tokens(0)._1 == SELF.tokens(0)._1 + } + .slice(0, watcherCount) + val WIDs = rewards.map{(box:Box) => box.R4[Coll[Coll[Byte]]].get(0)} + val widListDigest = blake2b256(WIDs.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b})) + val checkAllWIDs = rewards.forall { + (data: Box) => { + data.propositionBytes == OUTPUTS(0).propositionBytes && + data.tokens(0)._1 == SELF.tokens(0)._1 && + data.tokens(0)._2 == SELF.tokens(0)._2 / watcherCount } } sigmaProp( allOf( Coll( - WIDs.size == mergeBoxes.size, + SELF.R5[Coll[Byte]].get == widListDigest, checkAllWIDs, fraudScriptCheck, ) diff --git a/src/test/scala/testUtils/Boxes.scala b/src/test/scala/testUtils/Boxes.scala index 17edafa..48c59fc 100644 --- a/src/test/scala/testUtils/Boxes.scala +++ b/src/test/scala/testUtils/Boxes.scala @@ -6,6 +6,7 @@ import org.ergoplatform.appkit.{Address, BlockchainContext, ErgoContract, ErgoTo import rosen.bridge.Contracts import scorex.util.encode.Base16 import sigmastate.eval.Colls +import scorex.util.encode.{Base16, Base64} import java.nio.ByteBuffer import scala.collection.JavaConverters._ @@ -300,8 +301,8 @@ object Boxes { .contract(contracts.WatcherTriggerEvent._1) .tokens(new ErgoToken(networkConfig._2.tokens.RWTId, RWTCount)) .registers( - ErgoValueBuilder.buildFor(Colls.fromArray(WID.map(item => Colls.fromArray(item)).toArray)), ErgoValueBuilder.buildFor(Colls.fromArray(commitment.partsArray().map(item => Colls.fromArray(item)))), + ErgoValueBuilder.buildFor(Colls.fromArray(scorex.crypto.hash.Blake2b256(WID.reduce((a, b) => a ++ b)))), ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))), ErgoValueBuilder.buildFor(WID.size) ).build() From 73c45ea103f16580b2c2471c847da210fe29e933 Mon Sep 17 00:00:00 2001 From: "fateme.r" Date: Sat, 13 Jan 2024 21:07:35 +0330 Subject: [PATCH 3/7] Refactor register data types and fixed tests Tests used to check the transaction build and sign to throw error, but transaction should be built successfully and only transaction signing should reduced to false in attack scenarios. --- .../scala/rosen/bridge/scripts/Commitment.es | 26 +- .../rosen/bridge/scripts/EventTrigger.es | 8 +- src/main/scala/rosen/bridge/scripts/Permit.es | 4 +- src/test/scala/contracts/ContractTest.scala | 810 +++++++++--------- src/test/scala/testUtils/Boxes.scala | 6 +- 5 files changed, 426 insertions(+), 428 deletions(-) diff --git a/src/main/scala/rosen/bridge/scripts/Commitment.es b/src/main/scala/rosen/bridge/scripts/Commitment.es index 701889f..6cb5412 100644 --- a/src/main/scala/rosen/bridge/scripts/Commitment.es +++ b/src/main/scala/rosen/bridge/scripts/Commitment.es @@ -1,7 +1,7 @@ { // ----------------- REGISTERS - // R4: Coll[Coll[Byte]] = [WID] - // R5: Coll[Coll[Byte]] = [Request ID (Hash(TxId))] + // R4: Coll[Byte] = [WID] + // R5: Coll[Byte] = Event ID (Hash(TxId)) // R6: Coll[Byte] = Event Data Digest // R7: Coll[Byte] = Permit Script Digest // ----------------- TOKENS @@ -10,7 +10,7 @@ val eventTriggerHash = fromBase64("EVENT_TRIGGER_SCRIPT_HASH"); val repoNFT = fromBase64("REPO_NFT"); val trigger = if (blake2b256(INPUTS(0).propositionBytes) == eventTriggerHash) INPUTS(0) else OUTPUTS(0) - val myWID = SELF.R4[Coll[Coll[Byte]]].get + val myWID = SELF.R4[Coll[Byte]].get val eventData = trigger.R4[Coll[Coll[Byte]]].get.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b}) if(blake2b256(INPUTS(0).propositionBytes) == eventTriggerHash){ val WIDs = OUTPUTS.filter{(box:Box) @@ -23,9 +23,9 @@ val permitBoxes = OUTPUTS.filter {(box:Box) => blake2b256(box.propositionBytes) == SELF.R7[Coll[Byte]].get && box.R4[Coll[Coll[Byte]]].isDefined && - box.R4[Coll[Coll[Byte]]].get == myWID + box.R4[Coll[Coll[Byte]]].get(0) == myWID } - val WIDExists = WIDs.exists {(WID: Coll[Byte]) => myWID == Coll(WID)} + val WIDExists = WIDs.exists {(WID: Coll[Byte]) => myWID == WID} sigmaProp( allOf( Coll( @@ -35,7 +35,7 @@ // check for duplicates WIDExists == false, // validate commitment - blake2b256(eventData ++ myWID(0)) == SELF.R6[Coll[Byte]].get + blake2b256(eventData ++ myWID) == SELF.R6[Coll[Byte]].get ) ) ) @@ -49,12 +49,12 @@ box.tokens.size > 0 && box.tokens(0)._1 == SELF.tokens(0)._1 } - val WIDs = commitmentBoxes.map{(box:Box) => box.R4[Coll[Coll[Byte]]].get(0)} + val WIDs = commitmentBoxes.map{(box:Box) => box.R4[Coll[Byte]].get} val widListDigest = blake2b256(WIDs.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b})) - val myWIDCommitments = commitmentBoxes.filter{ (box: Box) => box.R4[Coll[Coll[Byte]]].get == myWID } + val myWIDCommitments = commitmentBoxes.filter{ (box: Box) => box.R4[Coll[Byte]].get == myWID } val EventBoxErgs = commitmentBoxes.map { (box: Box) => box.value }.fold(0L, { (a: Long, b: Long) => a + b }) val repo = CONTEXT.dataInputs(0) - val requestId = blake2b256(trigger.R4[Coll[Coll[Byte]]].get(0)) + val eventId = blake2b256(trigger.R4[Coll[Coll[Byte]]].get(0)) val repoR6 = repo.R6[Coll[Long]].get val maxCommitment = repoR6(3) val requiredCommitmentFromFormula: Long = repoR6(2) + repoR6(1) * (repo.R4[Coll[Coll[Byte]]].get.size - 1L) / 100L @@ -77,9 +77,9 @@ trigger.R7[Int].get == commitmentBoxes.size, trigger.R5[Coll[Byte]].get == widListDigest, // verify commitment to be correct - blake2b256(eventData ++ myWID(0)) == SELF.R6[Coll[Byte]].get, + blake2b256(eventData ++ myWID) == SELF.R6[Coll[Byte]].get, // check event id - SELF.R5[Coll[Coll[Byte]]].get == Coll(requestId), + SELF.R5[Coll[Byte]].get == eventId, // check commitment count commitmentBoxes.size > requiredCommitment, // Check required RWT @@ -99,9 +99,9 @@ OUTPUTS(0).tokens(0)._1 == SELF.tokens(0)._1, OUTPUTS(0).tokens(0)._2 == SELF.tokens(0)._2, // check WID copied - OUTPUTS(0).R4[Coll[Coll[Byte]]].get == myWID, + OUTPUTS(0).R4[Coll[Coll[Byte]]].get(0) == myWID, // check user WID - INPUTS(1).tokens(0)._1 == myWID(0), + INPUTS(1).tokens(0)._1 == myWID, // check permit contract address blake2b256(OUTPUTS(0).propositionBytes) == SELF.R7[Coll[Byte]].get ) diff --git a/src/main/scala/rosen/bridge/scripts/EventTrigger.es b/src/main/scala/rosen/bridge/scripts/EventTrigger.es index 0d90cda..0deede9 100644 --- a/src/main/scala/rosen/bridge/scripts/EventTrigger.es +++ b/src/main/scala/rosen/bridge/scripts/EventTrigger.es @@ -3,7 +3,7 @@ // R4: Coll[Coll[Byte]] Event data // R5: Coll[Byte] WID list digest // R6: Coll[Byte] Permit contract script digest - // R7: Int Watchers Count + // R7: Int Commitment Count // ----------------- TOKENS // 0: RWT @@ -29,18 +29,18 @@ ) ) } - val watcherCount = SELF.R7[Int].get + val commitmentCount = SELF.R7[Int].get val rewards = OUTPUTS.filter{(box:Box) => box.tokens.size > 0 && box.tokens(0)._1 == SELF.tokens(0)._1 } - .slice(0, watcherCount) + .slice(0, commitmentCount) val WIDs = rewards.map{(box:Box) => box.R4[Coll[Coll[Byte]]].get(0)} val widListDigest = blake2b256(WIDs.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b})) val checkAllWIDs = rewards.forall { (data: Box) => { data.propositionBytes == OUTPUTS(0).propositionBytes && data.tokens(0)._1 == SELF.tokens(0)._1 && - data.tokens(0)._2 == SELF.tokens(0)._2 / watcherCount + data.tokens(0)._2 == SELF.tokens(0)._2 / commitmentCount } } sigmaProp( diff --git a/src/main/scala/rosen/bridge/scripts/Permit.es b/src/main/scala/rosen/bridge/scripts/Permit.es index 7b1d7bc..cc659f4 100644 --- a/src/main/scala/rosen/bridge/scripts/Permit.es +++ b/src/main/scala/rosen/bridge/scripts/Permit.es @@ -50,10 +50,10 @@ OUTPUTS(1).tokens(0)._2 == totalPermits - OUTPUTS(0).tokens(0)._2, OUTPUTS(1).tokens(0)._1 == SELF.tokens(0)._1, blake2b256(OUTPUTS(1).propositionBytes) == commitmentScriptHash, - OUTPUTS(1).R5[Coll[Coll[Byte]]].isDefined, + OUTPUTS(1).R5[Coll[Byte]].isDefined, OUTPUTS(1).R6[Coll[Byte]].isDefined, OUTPUTS(1).R7[Coll[Byte]].get == blake2b256(SELF.propositionBytes), - OUTPUTS(1).R4[Coll[Coll[Byte]]].get == WID, + OUTPUTS(1).R4[Coll[Byte]].get == WID(0), outputWithRWT == false, OUTPUTS(0).propositionBytes == SELF.propositionBytes, OUTPUTS(0).R4[Coll[Coll[Byte]]].get == WID, diff --git a/src/test/scala/contracts/ContractTest.scala b/src/test/scala/contracts/ContractTest.scala index e447796..a0aa6bc 100644 --- a/src/test/scala/contracts/ContractTest.scala +++ b/src/test/scala/contracts/ContractTest.scala @@ -5,7 +5,6 @@ import org.ergoplatform.appkit.{ErgoProver, ErgoToken} import rosen.bridge.Contracts import scorex.util.encode.Base16 import testUtils.{Boxes, Commitment, TestSuite} -import java.io.{PrintWriter, StringWriter} class ContractTest extends TestSuite { @@ -134,20 +133,20 @@ class ContractTest extends TestSuite { */ property("get permit transaction signing should throw error when creating a fake collateral not containing AWC") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 2e9.toLong, new ErgoToken(networkConfig._3.RSN, 200L)) + val otherWID = Base16.decode(Boxes.getRandomHexString()).get + val repoBox = Boxes.createRepo(ctx, 100000, 5801L, 100L, Seq(otherWID), Seq(5800L)).convertToInputWith(Boxes.getRandomHexString(), 0) + val repoOut = Boxes.createRepo(ctx, 99900, 5901L, 100L, Seq(otherWID, repoBox.getId.getBytes), Seq(5800L, 100L)) + val permitBox = Boxes.createPermitBox(ctx, 100L, repoBox.getId.getBytes) + val WID = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(repoBox.getId.getBytes, 3L)) + val watcherCollateral = Boxes.createFakeWatcherCollateralBox(ctx, 1e9.toLong, 100, repoBox.getId.getBytes) + val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) + .fee(Configs.fee) + .addOutputs(repoOut, permitBox, WID, watcherCollateral) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 2e9.toLong, new ErgoToken(networkConfig._3.RSN, 200L)) - val otherWID = Base16.decode(Boxes.getRandomHexString()).get - val repoBox = Boxes.createRepo(ctx, 100000, 5801L, 100L, Seq(otherWID), Seq(5800L)).convertToInputWith(Boxes.getRandomHexString(), 0) - val repoOut = Boxes.createRepo(ctx, 99900, 5901L, 100L, Seq(otherWID, repoBox.getId.getBytes), Seq(5800L, 100L)) - val permitBox = Boxes.createPermitBox(ctx, 100L, repoBox.getId.getBytes) - val WID = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(repoBox.getId.getBytes, 3L)) - val watcherCollateral = Boxes.createFakeWatcherCollateralBox(ctx, 1e9.toLong, 100, repoBox.getId.getBytes) - val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) - .fee(Configs.fee) - .addOutputs(repoOut, permitBox, WID, watcherCollateral) - .sendChangeTo(prover.getAddress) - .build() val signedTx = prover.sign(tx) println(signedTx.toJson(false)) } @@ -169,20 +168,20 @@ class ContractTest extends TestSuite { */ property("get permit transaction signing should throw error when stealing AWC and creating fake collateral") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 2e9.toLong, new ErgoToken(networkConfig._3.RSN, 200L)) + val otherWID = Base16.decode(Boxes.getRandomHexString()).get + val repoBox = Boxes.createRepo(ctx, 100000, 5801L, 100L, Seq(otherWID), Seq(5800L)).convertToInputWith(Boxes.getRandomHexString(), 0) + val repoOut = Boxes.createRepo(ctx, 99900, 5901L, 99L, Seq(otherWID, repoBox.getId.getBytes), Seq(5800L, 100L)) + val permitBox = Boxes.createPermitBox(ctx, 100L, repoBox.getId.getBytes) + val WID = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(repoBox.getId.getBytes, 3L), new ErgoToken(networkConfig._2.tokens.AwcNFT, 1L)) + val watcherCollateral = Boxes.createFakeWatcherCollateralBox(ctx, 1e9.toLong, 100, repoBox.getId.getBytes) + val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) + .fee(Configs.fee) + .addOutputs(repoOut, permitBox, WID, watcherCollateral) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 2e9.toLong, new ErgoToken(networkConfig._3.RSN, 200L)) - val otherWID = Base16.decode(Boxes.getRandomHexString()).get - val repoBox = Boxes.createRepo(ctx, 100000, 5801L, 100L, Seq(otherWID), Seq(5800L)).convertToInputWith(Boxes.getRandomHexString(), 0) - val repoOut = Boxes.createRepo(ctx, 99900, 5901L, 100L, Seq(otherWID, repoBox.getId.getBytes), Seq(5800L, 100L)) - val permitBox = Boxes.createPermitBox(ctx, 100L, repoBox.getId.getBytes) - val WID = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(repoBox.getId.getBytes, 3L), new ErgoToken(networkConfig._2.tokens.AwcNFT, 1L)) - val watcherCollateral = Boxes.createFakeWatcherCollateralBox(ctx, 1e9.toLong, 100, repoBox.getId.getBytes) - val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) - .fee(Configs.fee) - .addOutputs(repoOut, permitBox, WID, watcherCollateral) - .sendChangeTo(prover.getAddress) - .build() val signedTx = prover.sign(tx) println(signedTx.toJson(false)) } @@ -266,21 +265,21 @@ class ContractTest extends TestSuite { property("test extend permit using one wid token") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val WID = Base16.decode(Boxes.getRandomHexString()).get + val otherWID = Base16.decode(Boxes.getRandomHexString()).get + val otherWID2 = Base16.decode(Boxes.getRandomHexString()).get + val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 1L), new ErgoToken(networkConfig._3.RSN, 100L)) + val repoBox = Boxes.createRepo(ctx, 100000, 9659L, 100L, Seq(otherWID, WID, otherWID2), Seq(3200L, 58L, 6400L)).convertToInputWith(Boxes.getRandomHexString(), 0) + val repoOut = Boxes.createRepoWithR7(ctx, 99900, 9759L, 100L, Seq(otherWID, WID, otherWID2), Seq(3200L, 158L, 6400L), 2) + val permitBox = Boxes.createPermitBox(ctx, 100L, WID) + val WIDBox = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(WID, 1L)) + val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) + .fee(Configs.fee) + .addOutputs(repoOut, permitBox, WIDBox) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val WID = Base16.decode(Boxes.getRandomHexString()).get - val otherWID = Base16.decode(Boxes.getRandomHexString()).get - val otherWID2 = Base16.decode(Boxes.getRandomHexString()).get - val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 1L), new ErgoToken(networkConfig._3.RSN, 100L)) - val repoBox = Boxes.createRepo(ctx, 100000, 9659L, 100L, Seq(otherWID, WID, otherWID2), Seq(3200L, 58L, 6400L)).convertToInputWith(Boxes.getRandomHexString(), 0) - val repoOut = Boxes.createRepoWithR7(ctx, 99900, 9759L, 100L, Seq(otherWID, WID, otherWID2), Seq(3200L, 158L, 6400L), 2) - val permitBox = Boxes.createPermitBox(ctx, 100L, WID) - val WIDBox = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(WID, 1L)) - val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) - .fee(Configs.fee) - .addOutputs(repoOut, permitBox, WIDBox) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) } }) @@ -288,20 +287,20 @@ class ContractTest extends TestSuite { property("test extend first permit while extended permit wid has changed") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val WID = Base16.decode(Boxes.getRandomHexString()).get + val otherWID = Base16.decode(Boxes.getRandomHexString()).get + val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 2L), new ErgoToken(networkConfig._3.RSN, 100L)) + val repoBox = Boxes.createRepo(ctx, 100000, 6459L, 100L, Seq(WID, otherWID), Seq(58L, 6400L)).convertToInputWith(Boxes.getRandomHexString(), 0) + val repoOut = Boxes.createRepoWithR7(ctx, 99900, 6559L, 100L, Seq(WID, otherWID), Seq(158L, 6400L), 1) + val permitBox = Boxes.createPermitBox(ctx, 100L, otherWID) + val WIDBox = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(WID, 2L)) + val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) + .fee(Configs.fee) + .addOutputs(repoOut, permitBox, WIDBox) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val WID = Base16.decode(Boxes.getRandomHexString()).get - val otherWID = Base16.decode(Boxes.getRandomHexString()).get - val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 2L), new ErgoToken(networkConfig._3.RSN, 100L)) - val repoBox = Boxes.createRepo(ctx, 100000, 6459L, 100L, Seq(WID, otherWID), Seq(58L, 6400L)).convertToInputWith(Boxes.getRandomHexString(), 0) - val repoOut = Boxes.createRepoWithR7(ctx, 99900, 6559L, 100L, Seq(WID, otherWID), Seq(158L, 6400L), 1) - val permitBox = Boxes.createPermitBox(ctx, 100L, otherWID) - val WIDBox = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(WID, 2L)) - val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) - .fee(Configs.fee) - .addOutputs(repoOut, permitBox, WIDBox) - .sendChangeTo(prover.getAddress) - .build() val signedTx = prover.sign(tx) println(signedTx.toJson(false)) } @@ -310,20 +309,20 @@ class ContractTest extends TestSuite { property("test extend first permit while extended permit first token is not RWT") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val WID = Base16.decode(Boxes.getRandomHexString()).get + val otherWID = Base16.decode(Boxes.getRandomHexString()).get + val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 2L), new ErgoToken(networkConfig._3.RSN, 200L)) + val repoBox = Boxes.createRepo(ctx, 100000, 6459L, 100L, Seq(WID, otherWID), Seq(58L, 6400L)).convertToInputWith(Boxes.getRandomHexString(), 0) + val repoOut = Boxes.createRepoWithR7(ctx, 99900, 6559L, 100L, Seq(WID, otherWID), Seq(158L, 6400L), 1) + val permitBox = Boxes.createInvalidPermitBox(ctx, 100L, WID) + val WIDBox = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(WID, 2L)) + val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) + .fee(Configs.fee) + .addOutputs(repoOut, permitBox, WIDBox) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val WID = Base16.decode(Boxes.getRandomHexString()).get - val otherWID = Base16.decode(Boxes.getRandomHexString()).get - val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 2L), new ErgoToken(networkConfig._3.RSN, 200L)) - val repoBox = Boxes.createRepo(ctx, 100000, 6459L, 100L, Seq(WID, otherWID), Seq(58L, 6400L)).convertToInputWith(Boxes.getRandomHexString(), 0) - val repoOut = Boxes.createRepoWithR7(ctx, 99900, 6559L, 100L, Seq(WID, otherWID), Seq(158L, 6400L), 1) - val permitBox = Boxes.createInvalidPermitBox(ctx, 100L, WID) - val WIDBox = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(WID, 2L)) - val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) - .fee(Configs.fee) - .addOutputs(repoOut, permitBox, WIDBox) - .sendChangeTo(prover.getAddress) - .build() val signedTx = prover.sign(tx) println(signedTx.toJson(false)) } @@ -332,21 +331,21 @@ class ContractTest extends TestSuite { property("test extend permit while mutating other permits amount on repo") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val WID = Base16.decode(Boxes.getRandomHexString()).get + val otherWID = Base16.decode(Boxes.getRandomHexString()).get + val otherWID2 = Base16.decode(Boxes.getRandomHexString()).get + val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 2L), new ErgoToken(networkConfig._3.RSN, 100L)) + val repoBox = Boxes.createRepo(ctx, 100000, 9659L, 100L, Seq(otherWID, WID, otherWID2), Seq(3200L, 58L, 6400L)).convertToInputWith(Boxes.getRandomHexString(), 0) + val repoOut = Boxes.createRepoWithR7(ctx, 99900, 9759L, 100L, Seq(otherWID, WID, otherWID2), Seq(320L, 158L, 6400L), 2) + val permitBox = Boxes.createPermitBox(ctx, 100L, WID) + val WIDBox = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(WID, 2L)) + val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) + .fee(Configs.fee) + .addOutputs(repoOut, permitBox, WIDBox) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val WID = Base16.decode(Boxes.getRandomHexString()).get - val otherWID = Base16.decode(Boxes.getRandomHexString()).get - val otherWID2 = Base16.decode(Boxes.getRandomHexString()).get - val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 2L), new ErgoToken(networkConfig._3.RSN, 100L)) - val repoBox = Boxes.createRepo(ctx, 100000, 9659L, 100L, Seq(otherWID, WID, otherWID2), Seq(3200L, 58L, 6400L)).convertToInputWith(Boxes.getRandomHexString(), 0) - val repoOut = Boxes.createRepoWithR7(ctx, 99900, 9759L, 100L, Seq(otherWID, WID, otherWID2), Seq(320L, 158L, 6400L), 2) - val permitBox = Boxes.createPermitBox(ctx, 100L, WID) - val WIDBox = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(WID, 2L)) - val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) - .fee(Configs.fee) - .addOutputs(repoOut, permitBox, WIDBox) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) } }) @@ -354,23 +353,22 @@ class ContractTest extends TestSuite { property("test extend permit while mutating other permits WID on repo") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val WID = Base16.decode(Boxes.getRandomHexString()).get + val otherWID = Base16.decode(Boxes.getRandomHexString()).get + val otherWID2 = Base16.decode(Boxes.getRandomHexString()).get + val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 2L), new ErgoToken(networkConfig._3.RSN, 100L)) + val repoBox = Boxes.createRepo(ctx, 100000, 9659L, 100L, Seq(otherWID, WID, otherWID2), Seq(3200L, 58L, 6400L)).convertToInputWith(Boxes.getRandomHexString(), 0) + val repoOut = Boxes.createRepoWithR7(ctx, 99900, 9759L, 100L, Seq(otherWID, WID, otherWID), Seq(3200L, 158L, 6400L), 2) + val permitBox = Boxes.createPermitBox(ctx, 100L, WID) + val WIDBox = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(WID, 2L)) + val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) + .fee(Configs.fee) + .addOutputs(repoOut, permitBox, WIDBox) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val WID = Base16.decode(Boxes.getRandomHexString()).get - val otherWID = Base16.decode(Boxes.getRandomHexString()).get - val otherWID2 = Base16.decode(Boxes.getRandomHexString()).get - val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 2L), new ErgoToken(networkConfig._3.RSN, 100L)) - val repoBox = Boxes.createRepo(ctx, 100000, 9659L, 100L, Seq(otherWID, WID, otherWID2), Seq(3200L, 58L, 6400L)).convertToInputWith(Boxes.getRandomHexString(), 0) - val repoOut = Boxes.createRepoWithR7(ctx, 99900, 9759L, 100L, Seq(otherWID, WID, otherWID), Seq(3200L, 158L, 6400L), 2) - val permitBox = Boxes.createPermitBox(ctx, 100L, WID) - val WIDBox = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, Configs.minBoxValue, new ErgoToken(WID, 2L)) - val tx = ctx.newTxBuilder().addInputs(repoBox, userBox) - .fee(Configs.fee) - .addOutputs(repoOut, permitBox, WIDBox) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) - fail("transaction should not sign, the permit WID have changed") } }) } @@ -407,26 +405,26 @@ class ContractTest extends TestSuite { property("test partially return permits using one wid token") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val userWID = Base16.decode(Boxes.getRandomHexString()).get + val WIDs = Seq( + Base16.decode(Boxes.getRandomHexString()).get, + Base16.decode(Boxes.getRandomHexString()).get, + userWID, + Base16.decode(Boxes.getRandomHexString()).get + ) + val repoBox = Boxes.createRepo(ctx, 100000, 321L, 100L, WIDs, Seq(100L, 120L, 60L, 40L)).convertToInputWith(Boxes.getRandomHexString(), 0) + val permitBox = Boxes.createPermitBox(ctx, 60L, userWID).convertToInputWith(Boxes.getRandomHexString(), 0) + val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 1L)) + val repoOut = Boxes.createRepoWithR7(ctx, 100020, 301L, 100L, WIDs, Seq(100L, 120L, 40L, 40L), 3) + val permitOut = Boxes.createPermitBox(ctx, 40L, userWID) + val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 1L), new ErgoToken(networkConfig._3.RSN, 20)) + val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox) + .fee(Configs.fee) + .addOutputs(repoOut, permitOut, userOut) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val userWID = Base16.decode(Boxes.getRandomHexString()).get - val WIDs = Seq( - Base16.decode(Boxes.getRandomHexString()).get, - Base16.decode(Boxes.getRandomHexString()).get, - userWID, - Base16.decode(Boxes.getRandomHexString()).get - ) - val repoBox = Boxes.createRepo(ctx, 100000, 321L, 100L, WIDs, Seq(100L, 120L, 60L, 40L)).convertToInputWith(Boxes.getRandomHexString(), 0) - val permitBox = Boxes.createPermitBox(ctx, 60L, userWID).convertToInputWith(Boxes.getRandomHexString(), 0) - val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 1L)) - val repoOut = Boxes.createRepoWithR7(ctx, 100020, 301L, 100L, WIDs, Seq(100L, 120L, 40L, 40L), 3) - val permitOut = Boxes.createPermitBox(ctx, 40L, userWID) - val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 1L), new ErgoToken(networkConfig._3.RSN, 20)) - val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox) - .fee(Configs.fee) - .addOutputs(repoOut, permitOut, userOut) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) } }) @@ -434,27 +432,27 @@ class ContractTest extends TestSuite { property("test partially return permits when output permit WID has changed") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val userWID = Base16.decode(Boxes.getRandomHexString()).get + val otherWID = Base16.decode(Boxes.getRandomHexString()).get + val WIDs = Seq( + Base16.decode(Boxes.getRandomHexString()).get, + otherWID, + userWID, + Base16.decode(Boxes.getRandomHexString()).get + ) + val repoBox = Boxes.createRepo(ctx, 100000, 321L, 100L, WIDs, Seq(100L, 120L, 60L, 40L)).convertToInputWith(Boxes.getRandomHexString(), 0) + val permitBox = Boxes.createPermitBox(ctx, 60L, userWID).convertToInputWith(Boxes.getRandomHexString(), 0) + val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) + val repoOut = Boxes.createRepoWithR7(ctx, 100020, 301L, 100L, WIDs, Seq(100L, 120L, 40L, 40L), 3) + val permitOut = Boxes.createPermitBox(ctx, 40L, otherWID) + val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2L), new ErgoToken(networkConfig._3.RSN, 20)) + val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox) + .fee(Configs.fee) + .addOutputs(repoOut, permitOut, userOut) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val userWID = Base16.decode(Boxes.getRandomHexString()).get - val otherWID = Base16.decode(Boxes.getRandomHexString()).get - val WIDs = Seq( - Base16.decode(Boxes.getRandomHexString()).get, - otherWID, - userWID, - Base16.decode(Boxes.getRandomHexString()).get - ) - val repoBox = Boxes.createRepo(ctx, 100000, 321L, 100L, WIDs, Seq(100L, 120L, 60L, 40L)).convertToInputWith(Boxes.getRandomHexString(), 0) - val permitBox = Boxes.createPermitBox(ctx, 60L, userWID).convertToInputWith(Boxes.getRandomHexString(), 0) - val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) - val repoOut = Boxes.createRepoWithR7(ctx, 100020, 301L, 100L, WIDs, Seq(100L, 120L, 40L, 40L), 3) - val permitOut = Boxes.createPermitBox(ctx, 40L, otherWID) - val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2L), new ErgoToken(networkConfig._3.RSN, 20)) - val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox) - .fee(Configs.fee) - .addOutputs(repoOut, permitOut, userOut) - .sendChangeTo(prover.getAddress) - .build() val signedTx = prover.sign(tx) println(signedTx.toJson(false)) } @@ -463,28 +461,28 @@ class ContractTest extends TestSuite { property("test partially return permits when changing other wid permits in repo") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val userWID = Base16.decode(Boxes.getRandomHexString()).get + val otherWID = Base16.decode(Boxes.getRandomHexString()).get + val WIDs = Seq( + Base16.decode(Boxes.getRandomHexString()).get, + otherWID, + userWID, + Base16.decode(Boxes.getRandomHexString()).get + ) + val repoBox = Boxes.createRepo(ctx, 100000, 321L, 100L, WIDs, Seq(100L, 120L, 60L, 40L)).convertToInputWith(Boxes.getRandomHexString(), 0) + val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, otherWID) + val permitBox = Boxes.createPermitBox(ctx, 60L, userWID).convertToInputWith(Boxes.getRandomHexString(), 0) + val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) + val repoOut = Boxes.createRepoWithR7(ctx, 100020, 301L, 100L, WIDs, Seq(100L, 100L, 60L, 40L), 2) + val permitOut = Boxes.createPermitBox(ctx, 40L, userWID) + val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2L), new ErgoToken(networkConfig._3.RSN, 20)) + val tx = ctx.newTxBuilder().addInputs(repoBox, userBox, WIDBox, permitBox) + .fee(Configs.fee) + .addOutputs(repoOut, permitOut, userOut) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val userWID = Base16.decode(Boxes.getRandomHexString()).get - val otherWID = Base16.decode(Boxes.getRandomHexString()).get - val WIDs = Seq( - Base16.decode(Boxes.getRandomHexString()).get, - otherWID, - userWID, - Base16.decode(Boxes.getRandomHexString()).get - ) - val repoBox = Boxes.createRepo(ctx, 100000, 321L, 100L, WIDs, Seq(100L, 120L, 60L, 40L)).convertToInputWith(Boxes.getRandomHexString(), 0) - val userBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, otherWID) - val permitBox = Boxes.createPermitBox(ctx, 60L, userWID).convertToInputWith(Boxes.getRandomHexString(), 0) - val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) - val repoOut = Boxes.createRepoWithR7(ctx, 100020, 301L, 100L, WIDs, Seq(100L, 100L, 60L, 40L), 2) - val permitOut = Boxes.createPermitBox(ctx, 40L, userWID) - val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2L), new ErgoToken(networkConfig._3.RSN, 20)) - val tx = ctx.newTxBuilder().addInputs(repoBox, userBox, WIDBox, permitBox) - .fee(Configs.fee) - .addOutputs(repoOut, permitOut, userOut) - .sendChangeTo(prover.getAddress) - .build() val signedTx = prover.sign(tx) println(signedTx.toJson(false)) } @@ -526,54 +524,54 @@ class ContractTest extends TestSuite { property("test complete return permits using one wid token") { networkConfig._1.ergoClient.execute(ctx => { - assertThrows[AnyRef] { - val prover = getProver() - val WIDs = generateRandomWIDList(6) - val amounts = Seq(100L, 120L, 140L, 20L, 40L, 250L) - for (userIndex <- 0 to 5) { - val userWID = WIDs(userIndex) - val totalPermitOut = amounts.sum - val repoBox = Boxes.createRepo(ctx, 100000L, totalPermitOut + 1L, 99L, WIDs, amounts).convertToInputWith(Boxes.getRandomHexString(), 0) - val permitBox = Boxes.createPermitBox(ctx, amounts(userIndex), userWID).convertToInputWith(Boxes.getRandomHexString(), 0) - val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 1L)) - val outputWIDs = WIDs.take(userIndex) ++ WIDs.drop(userIndex + 1) - val outAmounts = amounts.take(userIndex) ++ amounts.drop(userIndex + 1) - val repoOut = Boxes.createRepoWithR7(ctx, 100000L + amounts(userIndex), (totalPermitOut - amounts(userIndex)) + 1, 100L, outputWIDs, outAmounts, userIndex + 1) // 4 + first element in WID list is chain name - val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 1L), new ErgoToken(networkConfig._3.RSN, amounts(userIndex))) - val watcherCollateral = Boxes.createWatcherCollateralBoxInput(ctx, 1e9.toLong, 100, userWID) - val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox, watcherCollateral) - .fee(Configs.fee) - .addOutputs(repoOut, userOut) - .sendChangeTo(prover.getAddress) - .build() - prover.sign(tx) - } - } - }) - } - - property("test complete return permit while extending the wid list in repo") { - networkConfig._1.ergoClient.execute(ctx => { - assertThrows[AnyRef] { - val prover = getProver() - val WIDs = generateRandomWIDList(6) - val amounts = Seq(100L, 120L, 140L, 20L, 40L, 250L) - val userIndex = 0 + val prover = getProver() + val WIDs = generateRandomWIDList(6) + val amounts = Seq(100L, 120L, 140L, 20L, 40L, 250L) + for (userIndex <- 0 to 5) { val userWID = WIDs(userIndex) val totalPermitOut = amounts.sum val repoBox = Boxes.createRepo(ctx, 100000L, totalPermitOut + 1L, 99L, WIDs, amounts).convertToInputWith(Boxes.getRandomHexString(), 0) val permitBox = Boxes.createPermitBox(ctx, amounts(userIndex), userWID).convertToInputWith(Boxes.getRandomHexString(), 0) - val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) - val outputWIDs = WIDs.take(userIndex) ++ WIDs.drop(userIndex + 1) ++ Seq(WIDs(userIndex)) + val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 1L)) + val outputWIDs = WIDs.take(userIndex) ++ WIDs.drop(userIndex + 1) val outAmounts = amounts.take(userIndex) ++ amounts.drop(userIndex + 1) val repoOut = Boxes.createRepoWithR7(ctx, 100000L + amounts(userIndex), (totalPermitOut - amounts(userIndex)) + 1, 100L, outputWIDs, outAmounts, userIndex + 1) // 4 + first element in WID list is chain name - val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2), new ErgoToken(networkConfig._3.RSN, amounts(userIndex))) + val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 1L), new ErgoToken(networkConfig._3.RSN, amounts(userIndex))) val watcherCollateral = Boxes.createWatcherCollateralBoxInput(ctx, 1e9.toLong, 100, userWID) val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox, watcherCollateral) .fee(Configs.fee) .addOutputs(repoOut, userOut) .sendChangeTo(prover.getAddress) .build() + assertThrows[AnyRef] { + prover.sign(tx) + } + } + }) + } + + property("test complete return permit while extending the wid list in repo") { + networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val WIDs = generateRandomWIDList(6) + val amounts = Seq(100L, 120L, 140L, 20L, 40L, 250L) + val userIndex = 0 + val userWID = WIDs(userIndex) + val totalPermitOut = amounts.sum + val repoBox = Boxes.createRepo(ctx, 100000L, totalPermitOut + 1L, 99L, WIDs, amounts).convertToInputWith(Boxes.getRandomHexString(), 0) + val permitBox = Boxes.createPermitBox(ctx, amounts(userIndex), userWID).convertToInputWith(Boxes.getRandomHexString(), 0) + val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) + val outputWIDs = WIDs.take(userIndex) ++ WIDs.drop(userIndex + 1) ++ Seq(WIDs(userIndex)) + val outAmounts = amounts.take(userIndex) ++ amounts.drop(userIndex + 1) + val repoOut = Boxes.createRepoWithR7(ctx, 100000L + amounts(userIndex), (totalPermitOut - amounts(userIndex)) + 1, 100L, outputWIDs, outAmounts, userIndex + 1) // 4 + first element in WID list is chain name + val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2), new ErgoToken(networkConfig._3.RSN, amounts(userIndex))) + val watcherCollateral = Boxes.createWatcherCollateralBoxInput(ctx, 1e9.toLong, 100, userWID) + val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox, watcherCollateral) + .fee(Configs.fee) + .addOutputs(repoOut, userOut) + .sendChangeTo(prover.getAddress) + .build() + assertThrows[AnyRef] { prover.sign(tx) } }) @@ -581,26 +579,26 @@ class ContractTest extends TestSuite { property("test complete return permit while extending the rwt count list in repo") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val WIDs = generateRandomWIDList(6) + val amounts = Seq(100L, 120L, 140L, 20L, 40L, 250L) + val userIndex = 0 + val userWID = WIDs(userIndex) + val totalPermitOut = amounts.sum + val repoBox = Boxes.createRepo(ctx, 100000L, totalPermitOut + 1L, 99L, WIDs, amounts).convertToInputWith(Boxes.getRandomHexString(), 0) + val permitBox = Boxes.createPermitBox(ctx, amounts(userIndex), userWID).convertToInputWith(Boxes.getRandomHexString(), 0) + val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) + val outputWIDs = WIDs.take(userIndex) ++ WIDs.drop(userIndex + 1) + val outAmounts = amounts.take(userIndex) ++ amounts.drop(userIndex + 1) ++ Seq(100L) + val repoOut = Boxes.createRepoWithR7(ctx, 100000L + amounts(userIndex), (totalPermitOut - amounts(userIndex)) + 1, 100L, outputWIDs, outAmounts, userIndex + 1) // 4 + first element in WID list is chain name + val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2), new ErgoToken(networkConfig._3.RSN, amounts(userIndex))) + val watcherCollateral = Boxes.createWatcherCollateralBoxInput(ctx, 1e9.toLong, 100, userWID) + val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox, watcherCollateral) + .fee(Configs.fee) + .addOutputs(repoOut, userOut) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val WIDs = generateRandomWIDList(6) - val amounts = Seq(100L, 120L, 140L, 20L, 40L, 250L) - val userIndex = 0 - val userWID = WIDs(userIndex) - val totalPermitOut = amounts.sum - val repoBox = Boxes.createRepo(ctx, 100000L, totalPermitOut + 1L, 99L, WIDs, amounts).convertToInputWith(Boxes.getRandomHexString(), 0) - val permitBox = Boxes.createPermitBox(ctx, amounts(userIndex), userWID).convertToInputWith(Boxes.getRandomHexString(), 0) - val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) - val outputWIDs = WIDs.take(userIndex) ++ WIDs.drop(userIndex + 1) - val outAmounts = amounts.take(userIndex) ++ amounts.drop(userIndex + 1) ++ Seq(100L) - val repoOut = Boxes.createRepoWithR7(ctx, 100000L + amounts(userIndex), (totalPermitOut - amounts(userIndex)) + 1, 100L, outputWIDs, outAmounts, userIndex + 1) // 4 + first element in WID list is chain name - val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2), new ErgoToken(networkConfig._3.RSN, amounts(userIndex))) - val watcherCollateral = Boxes.createWatcherCollateralBoxInput(ctx, 1e9.toLong, 100, userWID) - val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox, watcherCollateral) - .fee(Configs.fee) - .addOutputs(repoOut, userOut) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) } }) @@ -608,26 +606,26 @@ class ContractTest extends TestSuite { property("test complete return permit while extending both rwt count and wid list in repo") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val WIDs = generateRandomWIDList(6) + val amounts = Seq(100L, 120L, 140L, 20L, 40L, 250L) + val userIndex = 0 + val userWID = WIDs(userIndex) + val totalPermitOut = amounts.sum + val repoBox = Boxes.createRepo(ctx, 100000L, totalPermitOut + 1L, 99L, WIDs, amounts).convertToInputWith(Boxes.getRandomHexString(), 0) + val permitBox = Boxes.createPermitBox(ctx, amounts(userIndex), userWID).convertToInputWith(Boxes.getRandomHexString(), 0) + val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) + val outputWIDs = WIDs.take(userIndex) ++ WIDs.drop(userIndex + 1) ++ Seq(WIDs(userIndex)) + val outAmounts = amounts.take(userIndex) ++ amounts.drop(userIndex + 1) ++ Seq(100L) + val repoOut = Boxes.createRepoWithR7(ctx, 100000L + amounts(userIndex), (totalPermitOut - amounts(userIndex)) + 1, 100L, outputWIDs, outAmounts, userIndex + 1) // 4 + first element in WID list is chain name + val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2), new ErgoToken(networkConfig._3.RSN, amounts(userIndex))) + val watcherCollateral = Boxes.createWatcherCollateralBoxInput(ctx, 1e9.toLong, 100, userWID) + val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox, watcherCollateral) + .fee(Configs.fee) + .addOutputs(repoOut, userOut) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val WIDs = generateRandomWIDList(6) - val amounts = Seq(100L, 120L, 140L, 20L, 40L, 250L) - val userIndex = 0 - val userWID = WIDs(userIndex) - val totalPermitOut = amounts.sum - val repoBox = Boxes.createRepo(ctx, 100000L, totalPermitOut + 1L, 99L, WIDs, amounts).convertToInputWith(Boxes.getRandomHexString(), 0) - val permitBox = Boxes.createPermitBox(ctx, amounts(userIndex), userWID).convertToInputWith(Boxes.getRandomHexString(), 0) - val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) - val outputWIDs = WIDs.take(userIndex) ++ WIDs.drop(userIndex + 1) ++ Seq(WIDs(userIndex)) - val outAmounts = amounts.take(userIndex) ++ amounts.drop(userIndex + 1) ++ Seq(100L) - val repoOut = Boxes.createRepoWithR7(ctx, 100000L + amounts(userIndex), (totalPermitOut - amounts(userIndex)) + 1, 100L, outputWIDs, outAmounts, userIndex + 1) // 4 + first element in WID list is chain name - val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2), new ErgoToken(networkConfig._3.RSN, amounts(userIndex))) - val watcherCollateral = Boxes.createWatcherCollateralBoxInput(ctx, 1e9.toLong, 100, userWID) - val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox, watcherCollateral) - .fee(Configs.fee) - .addOutputs(repoOut, userOut) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) } }) @@ -648,26 +646,26 @@ class ContractTest extends TestSuite { */ property("return permit transaction signing should throw error by returning a fake collateral not containing AWC") { networkConfig._1.ergoClient.execute(ctx => { + val prover = getProver() + val WIDs = generateRandomWIDList(6) + val amounts = Seq(100L, 120L, 140L, 20L, 40L, 250L) + val userIndex = 0 + val userWID = WIDs(userIndex) + val totalPermitOut = amounts.sum + val repoBox = Boxes.createRepo(ctx, 100000L, totalPermitOut + 1L, 99L, WIDs, amounts).convertToInputWith(Boxes.getRandomHexString(), 0) + val permitBox = Boxes.createPermitBox(ctx, amounts(userIndex), userWID).convertToInputWith(Boxes.getRandomHexString(), 0) + val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) + val outputWIDs = WIDs.take(userIndex) ++ WIDs.drop(userIndex + 1) + val outAmounts = amounts.take(userIndex) ++ amounts.drop(userIndex + 1) + val repoOut = Boxes.createRepoWithR7(ctx, 100000L + amounts(userIndex), (totalPermitOut - amounts(userIndex)) + 1, 99L, outputWIDs, outAmounts, userIndex + 1) // 4 + first element in WID list is chain name + val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2), new ErgoToken(networkConfig._3.RSN, amounts(userIndex))) + val watcherCollateral = Boxes.createFakeWatcherCollateralBox(ctx, 1e9.toLong, 100, userWID).convertToInputWith(Boxes.getRandomHexString(), 3) + val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox, watcherCollateral) + .fee(Configs.fee) + .addOutputs(repoOut, userOut) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val prover = getProver() - val WIDs = generateRandomWIDList(6) - val amounts = Seq(100L, 120L, 140L, 20L, 40L, 250L) - val userIndex = 0 - val userWID = WIDs(userIndex) - val totalPermitOut = amounts.sum - val repoBox = Boxes.createRepo(ctx, 100000L, totalPermitOut + 1L, 99L, WIDs, amounts).convertToInputWith(Boxes.getRandomHexString(), 0) - val permitBox = Boxes.createPermitBox(ctx, amounts(userIndex), userWID).convertToInputWith(Boxes.getRandomHexString(), 0) - val WIDBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(userWID, 2L)) - val outputWIDs = WIDs.take(userIndex) ++ WIDs.drop(userIndex + 1) - val outAmounts = amounts.take(userIndex) ++ amounts.drop(userIndex + 1) - val repoOut = Boxes.createRepoWithR7(ctx, 100000L + amounts(userIndex), (totalPermitOut - amounts(userIndex)) + 1, 99L, outputWIDs, outAmounts, userIndex + 1) // 4 + first element in WID list is chain name - val userOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(userWID, 2), new ErgoToken(networkConfig._3.RSN, amounts(userIndex))) - val watcherCollateral = Boxes.createFakeWatcherCollateralBox(ctx, 1e9.toLong, 100, userWID).convertToInputWith(Boxes.getRandomHexString(), 3) - val tx = ctx.newTxBuilder().addInputs(repoBox, permitBox, WIDBox, watcherCollateral) - .fee(Configs.fee) - .addOutputs(repoOut, userOut) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) } }) @@ -781,20 +779,20 @@ class ContractTest extends TestSuite { property("test create new commitment with RWT second place of permit tokens") { networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WID = Base16.decode(Boxes.getRandomHexString()).get + val box1 = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 1), new ErgoToken(networkConfig._3.RSN, 9)) + val permit = Boxes.createPermitBox(ctx, 10L, WID).convertToInputWith(Boxes.getRandomHexString(), 0) + val permitOut = Boxes.createInvalidMixedPermitBox(ctx, 9L, WID) + val commitmentBox = Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 1l) + val WIDOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(WID, 1)) + val tx = ctx.newTxBuilder().addInputs(permit, box1) + .fee(Configs.fee) + .sendChangeTo(prover.getAddress) + .addOutputs(permitOut, commitmentBox, WIDOut) + .build() assertThrows[AnyRef] { - val commitment = new Commitment() - val prover = getProver() - val WID = Base16.decode(Boxes.getRandomHexString()).get - val box1 = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong, new ErgoToken(WID, 1), new ErgoToken(networkConfig._3.RSN, 9)) - val permit = Boxes.createPermitBox(ctx, 10L, WID).convertToInputWith(Boxes.getRandomHexString(), 0) - val permitOut = Boxes.createInvalidMixedPermitBox(ctx, 9L, WID) - val commitmentBox = Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 1l) - val WIDOut = Boxes.createBoxCandidateForUser(ctx, prover.getAddress, 1e8.toLong, new ErgoToken(WID, 1)) - val tx = ctx.newTxBuilder().addInputs(permit, box1) - .fee(Configs.fee) - .sendChangeTo(prover.getAddress) - .addOutputs(permitOut, commitmentBox, WIDOut) - .build() val signedTx = prover.sign(tx) println(signedTx.toJson(false)) } @@ -928,20 +926,20 @@ class ContractTest extends TestSuite { property("test cant create event trigger for lower than minimum required watcher") { networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WIDs = generateRandomWIDList(7) + val repo = Boxes.createRepo(ctx, 1000L, 10001L, 100L, WIDs, Seq(10L, 30L, 20L, 25L, 5L, 4L, 6L)).convertToInputWith(Boxes.getRandomHexString(), 1) + val commitments = WIDs.slice(0, 3).map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 10L).convertToInputWith(Boxes.getRandomHexString(), 1)) + val trigger = Boxes.createTriggerEventBox(ctx, WIDs.slice(0, 3), commitment, 30L) + val feeBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong) + val tx = ctx.newTxBuilder().addInputs(commitments ++ Seq(feeBox): _*) + .fee(Configs.fee) + .addOutputs(trigger) + .addDataInputs(repo) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val commitment = new Commitment() - val prover = getProver() - val WIDs = generateRandomWIDList(7) - val repo = Boxes.createRepo(ctx, 1000L, 10001L, 100L, WIDs, Seq(10L, 30L, 20L, 25L, 5L, 4L, 6L)).convertToInputWith(Boxes.getRandomHexString(), 1) - val commitments = WIDs.slice(0, 3).map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 10L).convertToInputWith(Boxes.getRandomHexString(), 1)) - val trigger = Boxes.createTriggerEventBox(ctx, WIDs.slice(0, 3), commitment, 30L) - val feeBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong) - val tx = ctx.newTxBuilder().addInputs(commitments ++ Seq(feeBox): _*) - .fee(Configs.fee) - .addOutputs(trigger) - .addDataInputs(repo) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) } }) @@ -949,30 +947,30 @@ class ContractTest extends TestSuite { property("test create event trigger with repo box of different chain") { networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WIDs = generateRandomWIDList(7) + val repo = Boxes.createRepoWithTokens( + ctx, + 1000L, + 10001L, + 100L, + WIDs, + Seq(10L, 30L, 20L, 25L, 5L, 4L, 6L), + networkConfig._3.RepoNFT, + Boxes.getRandomHexString(), + networkConfig._2.tokens.AwcNFT + ).convertToInputWith(Boxes.getRandomHexString(), 1) + val commitments = WIDs.slice(0, 3).map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 10L).convertToInputWith(Boxes.getRandomHexString(), 1)) + val trigger = Boxes.createTriggerEventBox(ctx, WIDs.slice(0, 3), commitment, 30L) + val feeBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong) + val tx = ctx.newTxBuilder().addInputs(commitments ++ Seq(feeBox): _*) + .fee(Configs.fee) + .addOutputs(trigger) + .addDataInputs(repo) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val commitment = new Commitment() - val prover = getProver() - val WIDs = generateRandomWIDList(7) - val repo = Boxes.createRepoWithTokens( - ctx, - 1000L, - 10001L, - 100L, - WIDs, - Seq(10L, 30L, 20L, 25L, 5L, 4L, 6L), - networkConfig._3.RepoNFT, - Boxes.getRandomHexString(), - networkConfig._2.tokens.AwcNFT - ).convertToInputWith(Boxes.getRandomHexString(), 1) - val commitments = WIDs.slice(0, 3).map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 10L).convertToInputWith(Boxes.getRandomHexString(), 1)) - val trigger = Boxes.createTriggerEventBox(ctx, WIDs.slice(0, 3), commitment, 30L) - val feeBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong) - val tx = ctx.newTxBuilder().addInputs(commitments ++ Seq(feeBox): _*) - .fee(Configs.fee) - .addOutputs(trigger) - .addDataInputs(repo) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) } }) @@ -980,30 +978,30 @@ class ContractTest extends TestSuite { property("test create event trigger with invalid repo box (invalid nft and valid rwt)") { networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WIDs = generateRandomWIDList(7) + val repo = Boxes.createRepoWithTokens( + ctx, + 1000L, + 10001L, + 100L, + WIDs, + Seq(10L, 30L, 20L, 25L, 5L, 4L, 6L), + Boxes.getRandomHexString(), + networkConfig._2.tokens.RWTId, + networkConfig._2.tokens.AwcNFT + ).convertToInputWith(Boxes.getRandomHexString(), 1) + val commitments = WIDs.slice(0, 3).map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 10L).convertToInputWith(Boxes.getRandomHexString(), 1)) + val trigger = Boxes.createTriggerEventBox(ctx, WIDs.slice(0, 3), commitment, 30L) + val feeBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong) + val tx = ctx.newTxBuilder().addInputs(commitments ++ Seq(feeBox): _*) + .fee(Configs.fee) + .addOutputs(trigger) + .addDataInputs(repo) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val commitment = new Commitment() - val prover = getProver() - val WIDs = generateRandomWIDList(7) - val repo = Boxes.createRepoWithTokens( - ctx, - 1000L, - 10001L, - 100L, - WIDs, - Seq(10L, 30L, 20L, 25L, 5L, 4L, 6L), - Boxes.getRandomHexString(), - networkConfig._2.tokens.RWTId, - networkConfig._2.tokens.AwcNFT - ).convertToInputWith(Boxes.getRandomHexString(), 1) - val commitments = WIDs.slice(0, 3).map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 10L).convertToInputWith(Boxes.getRandomHexString(), 1)) - val trigger = Boxes.createTriggerEventBox(ctx, WIDs.slice(0, 3), commitment, 30L) - val feeBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong) - val tx = ctx.newTxBuilder().addInputs(commitments ++ Seq(feeBox): _*) - .fee(Configs.fee) - .addOutputs(trigger) - .addDataInputs(repo) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) } }) @@ -1011,20 +1009,20 @@ class ContractTest extends TestSuite { property("test create event trigger for all watchers with wrong trigger RWT sum") { networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WIDs = generateRandomWIDList(5) + val repo = Boxes.createRepo(ctx, 1000L, 10001L, 100L, WIDs, Seq(10L, 30L, 20L, 35L, 5L)).convertToInputWith(Boxes.getRandomHexString(), 1) + val commitments = WIDs.map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 10L).convertToInputWith(Boxes.getRandomHexString(), 1)) + val trigger = Boxes.createTriggerEventBox(ctx, WIDs, commitment, 48L) + val feeBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong) + val tx = ctx.newTxBuilder().addInputs(commitments ++ Seq(feeBox): _*) + .fee(Configs.fee) + .addOutputs(trigger) + .addDataInputs(repo) + .sendChangeTo(prover.getAddress) + .build() assertThrows[AnyRef] { - val commitment = new Commitment() - val prover = getProver() - val WIDs = generateRandomWIDList(5) - val repo = Boxes.createRepo(ctx, 1000L, 10001L, 100L, WIDs, Seq(10L, 30L, 20L, 35L, 5L)).convertToInputWith(Boxes.getRandomHexString(), 1) - val commitments = WIDs.map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 10L).convertToInputWith(Boxes.getRandomHexString(), 1)) - val trigger = Boxes.createTriggerEventBox(ctx, WIDs, commitment, 48L) - val feeBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong) - val tx = ctx.newTxBuilder().addInputs(commitments ++ Seq(feeBox): _*) - .fee(Configs.fee) - .addOutputs(trigger) - .addDataInputs(repo) - .sendChangeTo(prover.getAddress) - .build() prover.sign(tx) } }) @@ -1071,34 +1069,34 @@ class ContractTest extends TestSuite { property("test guard payment with wrong permit RWT count") { networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WIDs = generateRandomWIDList(7) + val secrets = (0 until 7).map(ind => Utils.randBigInt.bigInteger) + val guards = secrets.map(item => ctx.newProverBuilder().withDLogSecret(item).build()) + val guardsPks = guards.map(item => item.getAddress.getPublicKey.pkBytes).toArray + val userFee: Long = math.floor((commitment.fee * 0.6) / WIDs.length).toLong + val guardBox = Boxes.createGuardNftBox(ctx, guardsPks, 5, 6).convertToInputWith(Boxes.getRandomHexString(), 0) + val lockBox = Boxes.createLockBox( + ctx, + 1e9.toLong, + new ErgoToken(commitment.targetChainTokenId, userFee * WIDs.length) + ).convertToInputWith(Boxes.getRandomHexString(), 0) + val eventTrigger = Boxes.createTriggerEventBox(ctx, WIDs, commitment, 70L).convertToInputWith(Boxes.getRandomHexString(), 1) + val newPermits = WIDs.map(item => { + Boxes.createPermitBox(ctx, 9, item, new ErgoToken(commitment.targetChainTokenId, userFee)) + }) + val inputs = Seq(eventTrigger, lockBox) + val unsignedTx = ctx.newTxBuilder().addInputs(inputs: _*) + .addDataInputs(guardBox) + .fee(Configs.fee) + .sendChangeTo(prover.getAddress) + .addOutputs(newPermits: _*) + .build() + val multiSigProverBuilder = ctx.newProverBuilder() + secrets.map(item => multiSigProverBuilder.withDLogSecret(item)) + val multiSigProver = multiSigProverBuilder.build() assertThrows[AnyRef] { - val commitment = new Commitment() - val prover = getProver() - val WIDs = generateRandomWIDList(7) - val secrets = (0 until 7).map(ind => Utils.randBigInt.bigInteger) - val guards = secrets.map(item => ctx.newProverBuilder().withDLogSecret(item).build()) - val guardsPks = guards.map(item => item.getAddress.getPublicKey.pkBytes).toArray - val userFee: Long = math.floor((commitment.fee * 0.6) / WIDs.length).toLong - val guardBox = Boxes.createGuardNftBox(ctx, guardsPks, 5, 6).convertToInputWith(Boxes.getRandomHexString(), 0) - val lockBox = Boxes.createLockBox( - ctx, - 1e9.toLong, - new ErgoToken(commitment.targetChainTokenId, userFee * WIDs.length) - ).convertToInputWith(Boxes.getRandomHexString(), 0) - val eventTrigger = Boxes.createTriggerEventBox(ctx, WIDs, commitment, 70L).convertToInputWith(Boxes.getRandomHexString(), 1) - val newPermits = WIDs.map(item => { - Boxes.createPermitBox(ctx, 9, item, new ErgoToken(commitment.targetChainTokenId, userFee)) - }) - val inputs = Seq(eventTrigger, lockBox) - val unsignedTx = ctx.newTxBuilder().addInputs(inputs: _*) - .addDataInputs(guardBox) - .fee(Configs.fee) - .sendChangeTo(prover.getAddress) - .addOutputs(newPermits: _*) - .build() - val multiSigProverBuilder = ctx.newProverBuilder() - secrets.map(item => multiSigProverBuilder.withDLogSecret(item)) - val multiSigProver = multiSigProverBuilder.build() multiSigProver.sign(unsignedTx) } }) @@ -1148,37 +1146,37 @@ class ContractTest extends TestSuite { property("test guard payment with not merged wrong commitment") { networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WIDs = generateRandomWIDList(7) + val notMergedWIDs = generateRandomWIDList(1) + val allWIDs = WIDs ++ notMergedWIDs + val notMergedCommitments = notMergedWIDs.map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 11L).convertToInputWith(Boxes.getRandomHexString(), 1)) + val secrets = (0 until 7).map(ind => Utils.randBigInt.bigInteger) + val guards = secrets.map(item => ctx.newProverBuilder().withDLogSecret(item).build()) + val guardsPks = guards.map(item => item.getAddress.getPublicKey.pkBytes).toArray + val eventTrigger = Boxes.createTriggerEventBox(ctx, WIDs, commitment, 70L).convertToInputWith(Boxes.getRandomHexString(), 1) + val userFee: Long = math.floor((commitment.fee * 0.6) / allWIDs.length).toLong + val guardBox = Boxes.createGuardNftBox(ctx, guardsPks, 5, 6).convertToInputWith(Boxes.getRandomHexString(), 0) + val lockBox = Boxes.createLockBox( + ctx, + 1e9.toLong, + new ErgoToken(commitment.targetChainTokenId, userFee * (WIDs ++ notMergedWIDs).length) + ).convertToInputWith(Boxes.getRandomHexString(), 0) + val newPermits = (WIDs ++ notMergedWIDs).map(item => { + Boxes.createPermitBox(ctx, 10, item, new ErgoToken(commitment.targetChainTokenId, userFee)) + }) + val inputs = Seq(eventTrigger) ++ notMergedCommitments ++ Seq(lockBox) + val unsignedTx = ctx.newTxBuilder().addInputs(inputs: _*) + .fee(Configs.fee) + .addDataInputs(guardBox) + .sendChangeTo(prover.getAddress) + .addOutputs(newPermits: _*) + .build() + val multiSigProverBuilder = ctx.newProverBuilder() + secrets.map(item => multiSigProverBuilder.withDLogSecret(item)) + val multiSigProver = multiSigProverBuilder.build() assertThrows[AnyRef] { - val commitment = new Commitment() - val prover = getProver() - val WIDs = generateRandomWIDList(7) - val notMergedWIDs = generateRandomWIDList(1) - val allWIDs = WIDs ++ notMergedWIDs - val notMergedCommitments = notMergedWIDs.map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 11L).convertToInputWith(Boxes.getRandomHexString(), 1)) - val secrets = (0 until 7).map(ind => Utils.randBigInt.bigInteger) - val guards = secrets.map(item => ctx.newProverBuilder().withDLogSecret(item).build()) - val guardsPks = guards.map(item => item.getAddress.getPublicKey.pkBytes).toArray - val eventTrigger = Boxes.createTriggerEventBox(ctx, WIDs, commitment, 70L).convertToInputWith(Boxes.getRandomHexString(), 1) - val userFee: Long = math.floor((commitment.fee * 0.6) / allWIDs.length).toLong - val guardBox = Boxes.createGuardNftBox(ctx, guardsPks, 5, 6).convertToInputWith(Boxes.getRandomHexString(), 0) - val lockBox = Boxes.createLockBox( - ctx, - 1e9.toLong, - new ErgoToken(commitment.targetChainTokenId, userFee * (WIDs ++ notMergedWIDs).length) - ).convertToInputWith(Boxes.getRandomHexString(), 0) - val newPermits = (WIDs ++ notMergedWIDs).map(item => { - Boxes.createPermitBox(ctx, 10, item, new ErgoToken(commitment.targetChainTokenId, userFee)) - }) - val inputs = Seq(eventTrigger) ++ notMergedCommitments ++ Seq(lockBox) - val unsignedTx = ctx.newTxBuilder().addInputs(inputs: _*) - .fee(Configs.fee) - .addDataInputs(guardBox) - .sendChangeTo(prover.getAddress) - .addOutputs(newPermits: _*) - .build() - val multiSigProverBuilder = ctx.newProverBuilder() - secrets.map(item => multiSigProverBuilder.withDLogSecret(item)) - val multiSigProver = multiSigProverBuilder.build() multiSigProver.sign(unsignedTx) } }) @@ -1299,22 +1297,22 @@ class ContractTest extends TestSuite { property("test guard nft box cant spend with update with 5 sign") { networkConfig._1.ergoClient.execute(ctx => { + val secrets = (0 until 7).map(ind => Utils.randBigInt.bigInteger) + val guards = secrets.map(item => ctx.newProverBuilder().withDLogSecret(item).build()) + val prover = guards(0) + val guardsPks = guards.map(item => item.getAddress.getPublicKey.pkBytes).toArray + val signBox = Boxes.createGuardNftBox(ctx, guardsPks, 5, 6).convertToInputWith(Boxes.getRandomHexString(), 1) + val box2 = Boxes.createBoxForUser(ctx, guards(0).getAddress, 1e9.toLong) + val outSignBox = Boxes.createGuardNftBox(ctx, guardsPks, 4, 6) + val outBox = Boxes.createBoxCandidateForUser(ctx, guards(1).getAddress, 1e8.toLong) + val tx = ctx.newTxBuilder().addInputs(signBox, box2) + .fee(Configs.fee) + .addOutputs(outSignBox, outBox) + .sendChangeTo(prover.getAddress) + .build() + val proverBuilder = ctx.newProverBuilder() + secrets.slice(0, 5).map(item => proverBuilder.withDLogSecret(item)) assertThrows[AnyRef] { - val secrets = (0 until 7).map(ind => Utils.randBigInt.bigInteger) - val guards = secrets.map(item => ctx.newProverBuilder().withDLogSecret(item).build()) - val prover = guards(0) - val guardsPks = guards.map(item => item.getAddress.getPublicKey.pkBytes).toArray - val signBox = Boxes.createGuardNftBox(ctx, guardsPks, 5, 6).convertToInputWith(Boxes.getRandomHexString(), 1) - val box2 = Boxes.createBoxForUser(ctx, guards(0).getAddress, 1e9.toLong) - val outSignBox = Boxes.createGuardNftBox(ctx, guardsPks, 4, 6) - val outBox = Boxes.createBoxCandidateForUser(ctx, guards(1).getAddress, 1e8.toLong) - val tx = ctx.newTxBuilder().addInputs(signBox, box2) - .fee(Configs.fee) - .addOutputs(outSignBox, outBox) - .sendChangeTo(prover.getAddress) - .build() - val proverBuilder = ctx.newProverBuilder() - secrets.slice(0, 5).map(item => proverBuilder.withDLogSecret(item)) proverBuilder.build().sign(tx) } }) diff --git a/src/test/scala/testUtils/Boxes.scala b/src/test/scala/testUtils/Boxes.scala index f1841f9..cb28965 100644 --- a/src/test/scala/testUtils/Boxes.scala +++ b/src/test/scala/testUtils/Boxes.scala @@ -292,14 +292,14 @@ object Boxes { .build() } - def createCommitment(ctx: BlockchainContext, WID: Array[Byte], RequestId: Array[Byte], commitment: Array[Byte], RWTCount: Long): OutBox = { + def createCommitment(ctx: BlockchainContext, WID: Array[Byte], eventId: Array[Byte], commitment: Array[Byte], RWTCount: Long): OutBox = { ctx.newTxBuilder().outBoxBuilder() .value(Configs.minBoxValue) .contract(contracts.Commitment._1) .tokens(new ErgoToken(networkConfig._2.tokens.RWTId, RWTCount)) .registers( - ErgoValueBuilder.buildFor(Colls.fromArray(Seq(WID).map(item => Colls.fromArray(item)).toArray)), - ErgoValueBuilder.buildFor(Colls.fromArray(Seq(RequestId).map(item => Colls.fromArray(item)).toArray)), + ErgoValueBuilder.buildFor(Colls.fromArray(WID)), + ErgoValueBuilder.buildFor(Colls.fromArray(eventId)), ErgoValueBuilder.buildFor(Colls.fromArray(commitment)), ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))), ).build() From 1ef8c22a5ab342851c763006d8b46d16d0b9d382 Mon Sep 17 00:00:00 2001 From: "fateme.r" Date: Sun, 14 Jan 2024 11:23:44 +0330 Subject: [PATCH 4/7] Add unit tests for event trigger wid list digest --- src/test/scala/contracts/ContractTest.scala | 66 +++++++++++++++++++++ src/test/scala/testUtils/Boxes.scala | 21 ++++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/test/scala/contracts/ContractTest.scala b/src/test/scala/contracts/ContractTest.scala index a0aa6bc..15be3c4 100644 --- a/src/test/scala/contracts/ContractTest.scala +++ b/src/test/scala/contracts/ContractTest.scala @@ -945,6 +945,72 @@ class ContractTest extends TestSuite { }) } + /** + * @target create trigger transaction signing should throw error when the commitment count is not valid in trigger box + * @dependencies + * @scenario + * - mock commitment wid list + * - mock repo box with the wid list as data input + * - mock commitments for an event for each wid + * - mock invalid trigger with wrong commitment count + * - build and sign the create trigger transaction + * @expected + * - sign error for invalid commitment count in trigger box + */ + property("create trigger transaction signing should throw error when the commitment count is not valid in trigger box") { + networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WIDs = generateRandomWIDList(5) + val repo = Boxes.createRepo(ctx, 1000L, 10001L, 100L, WIDs, Seq(10L, 30L, 20L, 35L, 5L)).convertToInputWith(Boxes.getRandomHexString(), 1) + val commitments = WIDs.map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 10L).convertToInputWith(Boxes.getRandomHexString(), 1)) + val trigger = Boxes.createTriggerEventBox(ctx, WIDs, commitment, 50L, Some(4)) + val feeBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong) + val tx = ctx.newTxBuilder().addInputs(commitments ++ Seq(feeBox): _*) + .fee(Configs.fee) + .addOutputs(trigger) + .addDataInputs(repo) + .sendChangeTo(prover.getAddress) + .build() + assertThrows[AnyRef] { + prover.sign(tx) + } + }) + } + + /** + * @target create trigger transaction signing should throw error when the wid list digest is invalid in trigger box + * @dependencies + * @scenario + * - mock commitment wid list + * - mock repo box with the wid list as data input + * - mock commitments for an event for each wid + * - mock invalid trigger with wrong wid list digest + * - build and sign the create trigger transaction + * @expected + * - sign error for invalid wid list digest in trigger box + */ + property("create trigger transaction signing should throw error when the wid list digest is invalid in trigger box") { + networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WIDs = generateRandomWIDList(5) + val repo = Boxes.createRepo(ctx, 1000L, 10001L, 100L, WIDs, Seq(10L, 30L, 20L, 35L, 5L)).convertToInputWith(Boxes.getRandomHexString(), 1) + val commitments = WIDs.map(WID => Boxes.createCommitment(ctx, WID, commitment.requestId(), commitment.hash(WID), 10L).convertToInputWith(Boxes.getRandomHexString(), 1)) + val trigger = Boxes.createFakeTriggerEventBox(ctx, WIDs, commitment, 50L) + val feeBox = Boxes.createBoxForUser(ctx, prover.getAddress, 1e9.toLong) + val tx = ctx.newTxBuilder().addInputs(commitments ++ Seq(feeBox): _*) + .fee(Configs.fee) + .addOutputs(trigger) + .addDataInputs(repo) + .sendChangeTo(prover.getAddress) + .build() + assertThrows[AnyRef] { + prover.sign(tx) + } + }) + } + property("test create event trigger with repo box of different chain") { networkConfig._1.ergoClient.execute(ctx => { val commitment = new Commitment() diff --git a/src/test/scala/testUtils/Boxes.scala b/src/test/scala/testUtils/Boxes.scala index cb28965..e191233 100644 --- a/src/test/scala/testUtils/Boxes.scala +++ b/src/test/scala/testUtils/Boxes.scala @@ -62,7 +62,7 @@ class Commitment { } object Boxes { - + val networkConfig: (ErgoNetwork, Network, MainTokens) = Utils.selectConfig("cardano", "mainnet") val contracts = new Contracts(networkConfig._1, (networkConfig._2, networkConfig._3)) @@ -138,6 +138,7 @@ object Boxes { def createWatcherCollateralBoxInput(ctx: BlockchainContext, erg: Long, rsn: Long, wid: Array[Byte]): InputBox = { Boxes.createWatcherCollateralBox(ctx, erg, rsn, wid).convertToInputWith(getRandomHexString(), 3) } + def createWatcherCollateralBox(ctx: BlockchainContext, erg: Long, rsn: Long, wid: Array[Byte]): OutBox = { ctx.newTxBuilder().outBoxBuilder() .value(erg) @@ -265,6 +266,7 @@ object Boxes { ) .build() } + def createInvalidPermitBox(ctx: BlockchainContext, RWTCount: Long, WID: Array[Byte], tokens: ErgoToken*): OutBox = { val txB = ctx.newTxBuilder() val tokensSeq = Seq(new ErgoToken(networkConfig._3.RSN, RWTCount)) ++ tokens.toSeq @@ -305,7 +307,7 @@ object Boxes { ).build() } - def createTriggerEventBox(ctx: BlockchainContext, WID: Seq[Array[Byte]], commitment: Commitment, RWTCount: Long): OutBox = { + def createTriggerEventBox(ctx: BlockchainContext, WID: Seq[Array[Byte]], commitment: Commitment, RWTCount: Long, commitmentCount: Option[Int] = None): OutBox = { val size = WID.length ctx.newTxBuilder().outBoxBuilder() .value(Configs.minBoxValue * size) @@ -315,6 +317,21 @@ object Boxes { ErgoValueBuilder.buildFor(Colls.fromArray(commitment.partsArray().map(item => Colls.fromArray(item)))), ErgoValueBuilder.buildFor(Colls.fromArray(scorex.crypto.hash.Blake2b256(WID.reduce((a, b) => a ++ b)))), ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))), + ErgoValueBuilder.buildFor(commitmentCount.getOrElse(WID.size)) + ).build() + } + + + def createFakeTriggerEventBox(ctx: BlockchainContext, WID: Seq[Array[Byte]], commitment: Commitment, RWTCount: Long): OutBox = { + val size = WID.length + ctx.newTxBuilder().outBoxBuilder() + .value(Configs.minBoxValue * size) + .contract(contracts.WatcherTriggerEvent._1) + .tokens(new ErgoToken(networkConfig._2.tokens.RWTId, RWTCount)) + .registers( + ErgoValueBuilder.buildFor(Colls.fromArray(commitment.partsArray().map(item => Colls.fromArray(item)))), + ErgoValueBuilder.buildFor(Colls.fromArray(scorex.crypto.hash.Blake2b256(WID.slice(1, WID.size).reduce((a, b) => a ++ b)))), + ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))), ErgoValueBuilder.buildFor(WID.size) ).build() } From ea6f9c0adf8fb02ffe090d40305b2194058d31fd Mon Sep 17 00:00:00 2001 From: "fateme.r" Date: Mon, 15 Jan 2024 11:40:21 +0330 Subject: [PATCH 5/7] Add unit tests --- .../scala/rosen/bridge/scripts/Commitment.es | 4 +- src/test/scala/contracts/ContractTest.scala | 98 +++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/main/scala/rosen/bridge/scripts/Commitment.es b/src/main/scala/rosen/bridge/scripts/Commitment.es index 6cb5412..c0e408e 100644 --- a/src/main/scala/rosen/bridge/scripts/Commitment.es +++ b/src/main/scala/rosen/bridge/scripts/Commitment.es @@ -13,13 +13,13 @@ val myWID = SELF.R4[Coll[Byte]].get val eventData = trigger.R4[Coll[Coll[Byte]]].get.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b}) if(blake2b256(INPUTS(0).propositionBytes) == eventTriggerHash){ + // Reward Distribution (for missed commitments) + // [EventTrigger, Commitments[], BridgeWallet] => [WatcherPermits[], BridgeWallet] val WIDs = OUTPUTS.filter{(box:Box) => box.tokens.size > 0 && box.tokens(0)._1 == SELF.tokens(0)._1 } .slice(0, trigger.R7[Int].get) .map{(box:Box) => box.R4[Coll[Coll[Byte]]].get(0)} - // Reward Distribution (for missed commitments) - // [EventTrigger, Commitments[], BridgeWallet] => [WatcherPermits[], BridgeWallet] val permitBoxes = OUTPUTS.filter {(box:Box) => blake2b256(box.propositionBytes) == SELF.R7[Coll[Byte]].get && box.R4[Coll[Coll[Byte]]].isDefined && diff --git a/src/test/scala/contracts/ContractTest.scala b/src/test/scala/contracts/ContractTest.scala index 15be3c4..14557d8 100644 --- a/src/test/scala/contracts/ContractTest.scala +++ b/src/test/scala/contracts/ContractTest.scala @@ -1133,6 +1133,104 @@ class ContractTest extends TestSuite { }) } + /** + * @target reward transaction signing should throw error when number of watcher rewards are less than the trigger commitment count + * @dependencies + * @scenario + * - mock commitment wid list + * - mock guards secrets, public keys and box with the guard NFT + * - mock lock box with required tokens + * - mock trigger box with wid list + * - mock output permits for all wids except one + * - build and sign the reward transaction + * @expected + * - sign error for fewer reward boxes than expected + */ + property("reward transaction signing should throw error when number of watcher rewards are less than the trigger commitment count") { + networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WIDs = generateRandomWIDList(7) + val secrets = (0 until 7).map(ind => Utils.randBigInt.bigInteger) + val guards = secrets.map(item => ctx.newProverBuilder().withDLogSecret(item).build()) + val guardsPks = guards.map(item => item.getAddress.getPublicKey.pkBytes).toArray + val userFee: Long = math.floor((commitment.fee * 0.6) / WIDs.length).toLong + val guardBox = Boxes.createGuardNftBox(ctx, guardsPks, 5, 6).convertToInputWith(Boxes.getRandomHexString(), 0) + val lockBox = Boxes.createLockBox( + ctx, + Configs.minBoxValue, + new ErgoToken(commitment.targetChainTokenId, userFee * WIDs.length) + ).convertToInputWith(Boxes.getRandomHexString(), 0) + val eventTrigger = Boxes.createTriggerEventBox(ctx, WIDs, commitment, 70L).convertToInputWith(Boxes.getRandomHexString(), 1) + val newPermits = WIDs.slice(0, WIDs.length - 1).map(item => { + Boxes.createPermitBox(ctx, 10, item, new ErgoToken(commitment.targetChainTokenId, userFee)) + }) + val inputs = Seq(eventTrigger, lockBox) + val unsignedTx = ctx.newTxBuilder().addInputs(inputs: _*) + .addDataInputs(guardBox) + .fee(Configs.fee) + .sendChangeTo(prover.getAddress) + .addOutputs(newPermits: _*) + .build() + val multiSigProverBuilder = ctx.newProverBuilder() + secrets.map(item => multiSigProverBuilder.withDLogSecret(item)) + val multiSigProver = multiSigProverBuilder.build() + assertThrows[AnyRef] { + multiSigProver.sign(unsignedTx) + } + }) + } + + /** + * @target reward transaction signing should throw error when all reporting watchers are not rewarded + * @dependencies + * @scenario + * - mock commitment wid list + * - mock guards secrets, public keys and box with the guard NFT + * - mock lock box with required tokens + * - mock trigger box with wid list + * - mock output permits for all wids except one + an extra permit for a new wid + * - build and sign the reward transaction + * @expected + * - sign error for rewarding a wrong wid + */ + property("reward transaction signing should throw error when all reporting watchers are not rewarded") { + networkConfig._1.ergoClient.execute(ctx => { + val commitment = new Commitment() + val prover = getProver() + val WIDs = generateRandomWIDList(7) + val newWID = Base16.decode(Boxes.getRandomHexString()).get + val secrets = (0 until 7).map(ind => Utils.randBigInt.bigInteger) + val guards = secrets.map(item => ctx.newProverBuilder().withDLogSecret(item).build()) + val guardsPks = guards.map(item => item.getAddress.getPublicKey.pkBytes).toArray + val userFee: Long = math.floor((commitment.fee * 0.6) / WIDs.length).toLong + val guardBox = Boxes.createGuardNftBox(ctx, guardsPks, 5, 6).convertToInputWith(Boxes.getRandomHexString(), 0) + val lockBox = Boxes.createLockBox( + ctx, + Configs.minBoxValue, + new ErgoToken(commitment.targetChainTokenId, userFee * WIDs.length) + ).convertToInputWith(Boxes.getRandomHexString(), 0) + val eventTrigger = Boxes.createTriggerEventBox(ctx, WIDs, commitment, 70L).convertToInputWith(Boxes.getRandomHexString(), 1) + val rewardingWIDs = WIDs.slice(0, WIDs.length - 1) ++ Seq(newWID) + val newPermits = rewardingWIDs.map(item => { + Boxes.createPermitBox(ctx, 10, item, new ErgoToken(commitment.targetChainTokenId, userFee)) + }) + val inputs = Seq(eventTrigger, lockBox) + val unsignedTx = ctx.newTxBuilder().addInputs(inputs: _*) + .addDataInputs(guardBox) + .fee(Configs.fee) + .sendChangeTo(prover.getAddress) + .addOutputs(newPermits: _*) + .build() + val multiSigProverBuilder = ctx.newProverBuilder() + secrets.map(item => multiSigProverBuilder.withDLogSecret(item)) + val multiSigProver = multiSigProverBuilder.build() + assertThrows[AnyRef] { + multiSigProver.sign(unsignedTx) + } + }) + } + property("test guard payment with wrong permit RWT count") { networkConfig._1.ergoClient.execute(ctx => { val commitment = new Commitment() From 6e4835793ec827506a8be973b13a4cbe6427bc8c Mon Sep 17 00:00:00 2001 From: "fateme.r" Date: Mon, 15 Jan 2024 14:31:12 +0330 Subject: [PATCH 6/7] Restore unnecessary changes --- .../scala/rosen/bridge/scripts/Commitment.es | 41 +++++++++---------- .../rosen/bridge/scripts/EventTrigger.es | 6 +-- src/main/scala/rosen/bridge/scripts/Permit.es | 4 +- src/test/scala/testUtils/Boxes.scala | 10 +++-- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/main/scala/rosen/bridge/scripts/Commitment.es b/src/main/scala/rosen/bridge/scripts/Commitment.es index c0e408e..8371b20 100644 --- a/src/main/scala/rosen/bridge/scripts/Commitment.es +++ b/src/main/scala/rosen/bridge/scripts/Commitment.es @@ -1,7 +1,7 @@ { // ----------------- REGISTERS - // R4: Coll[Byte] = [WID] - // R5: Coll[Byte] = Event ID (Hash(TxId)) + // R4: Coll[Coll[Byte]] = [WID] + // R5: Coll[Coll[Byte]] = [Request ID (Hash(TxId))] // R6: Coll[Byte] = Event Data Digest // R7: Coll[Byte] = Permit Script Digest // ----------------- TOKENS @@ -10,8 +10,8 @@ val eventTriggerHash = fromBase64("EVENT_TRIGGER_SCRIPT_HASH"); val repoNFT = fromBase64("REPO_NFT"); val trigger = if (blake2b256(INPUTS(0).propositionBytes) == eventTriggerHash) INPUTS(0) else OUTPUTS(0) - val myWID = SELF.R4[Coll[Byte]].get - val eventData = trigger.R4[Coll[Coll[Byte]]].get.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b}) + val myWID = SELF.R4[Coll[Coll[Byte]]].get + val eventData = trigger.R5[Coll[Coll[Byte]]].get.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a ++ b }) if(blake2b256(INPUTS(0).propositionBytes) == eventTriggerHash){ // Reward Distribution (for missed commitments) // [EventTrigger, Commitments[], BridgeWallet] => [WatcherPermits[], BridgeWallet] @@ -20,22 +20,21 @@ } .slice(0, trigger.R7[Int].get) .map{(box:Box) => box.R4[Coll[Coll[Byte]]].get(0)} - val permitBoxes = OUTPUTS.filter {(box:Box) => - blake2b256(box.propositionBytes) == SELF.R7[Coll[Byte]].get && + val permitBox = OUTPUTS.filter {(box:Box) => box.R4[Coll[Coll[Byte]]].isDefined && - box.R4[Coll[Coll[Byte]]].get(0) == myWID - } - val WIDExists = WIDs.exists {(WID: Coll[Byte]) => myWID == WID} + box.R4[Coll[Coll[Byte]]].get == myWID + }(0) + val WIDExists = WIDs.exists {(WID: Coll[Byte]) => myWID == Coll(WID)} sigmaProp( allOf( Coll( - permitBoxes.size == 1, - permitBoxes(0).tokens(0)._1 == SELF.tokens(0)._1, - permitBoxes(0).tokens(0)._2 == SELF.tokens(0)._2, + blake2b256(permitBox.propositionBytes) == SELF.R7[Coll[Byte]].get, + permitBox.tokens(0)._1 == SELF.tokens(0)._1, + permitBox.tokens(0)._2 == SELF.tokens(0)._2, // check for duplicates WIDExists == false, // validate commitment - blake2b256(eventData ++ myWID) == SELF.R6[Coll[Byte]].get + blake2b256(eventData ++ myWID(0)) == SELF.R6[Coll[Byte]].get ) ) ) @@ -49,12 +48,12 @@ box.tokens.size > 0 && box.tokens(0)._1 == SELF.tokens(0)._1 } - val WIDs = commitmentBoxes.map{(box:Box) => box.R4[Coll[Byte]].get} + val WIDs = commitmentBoxes.map{(box:Box) => box.R4[Coll[Coll[Byte]]].get(0)} val widListDigest = blake2b256(WIDs.fold(Coll[Byte](), {(a: Coll[Byte], b: Coll[Byte]) => a++b})) - val myWIDCommitments = commitmentBoxes.filter{ (box: Box) => box.R4[Coll[Byte]].get == myWID } + val myWIDCommitments = commitmentBoxes.filter{ (box: Box) => box.R4[Coll[Coll[Byte]]].get == myWID } val EventBoxErgs = commitmentBoxes.map { (box: Box) => box.value }.fold(0L, { (a: Long, b: Long) => a + b }) val repo = CONTEXT.dataInputs(0) - val eventId = blake2b256(trigger.R4[Coll[Coll[Byte]]].get(0)) + val eventId = blake2b256(trigger.R5[Coll[Coll[Byte]]].get(0)) val repoR6 = repo.R6[Coll[Long]].get val maxCommitment = repoR6(3) val requiredCommitmentFromFormula: Long = repoR6(2) + repoR6(1) * (repo.R4[Coll[Coll[Byte]]].get.size - 1L) / 100L @@ -75,11 +74,11 @@ trigger.value >= EventBoxErgs, trigger.R6[Coll[Byte]].get == SELF.R7[Coll[Byte]].get, trigger.R7[Int].get == commitmentBoxes.size, - trigger.R5[Coll[Byte]].get == widListDigest, + trigger.R4[Coll[Coll[Byte]]].get(0) == widListDigest, // verify commitment to be correct - blake2b256(eventData ++ myWID) == SELF.R6[Coll[Byte]].get, + blake2b256(eventData ++ myWID(0)) == SELF.R6[Coll[Byte]].get, // check event id - SELF.R5[Coll[Byte]].get == eventId, + SELF.R5[Coll[Coll[Byte]]].get == Coll(eventId), // check commitment count commitmentBoxes.size > requiredCommitment, // Check required RWT @@ -99,9 +98,9 @@ OUTPUTS(0).tokens(0)._1 == SELF.tokens(0)._1, OUTPUTS(0).tokens(0)._2 == SELF.tokens(0)._2, // check WID copied - OUTPUTS(0).R4[Coll[Coll[Byte]]].get(0) == myWID, + OUTPUTS(0).R4[Coll[Coll[Byte]]].get == myWID, // check user WID - INPUTS(1).tokens(0)._1 == myWID, + INPUTS(1).tokens(0)._1 == myWID(0), // check permit contract address blake2b256(OUTPUTS(0).propositionBytes) == SELF.R7[Coll[Byte]].get ) diff --git a/src/main/scala/rosen/bridge/scripts/EventTrigger.es b/src/main/scala/rosen/bridge/scripts/EventTrigger.es index 0deede9..2744ed0 100644 --- a/src/main/scala/rosen/bridge/scripts/EventTrigger.es +++ b/src/main/scala/rosen/bridge/scripts/EventTrigger.es @@ -1,7 +1,7 @@ { // ----------------- REGISTERS - // R4: Coll[Coll[Byte]] Event data - // R5: Coll[Byte] WID list digest + // R4: Coll[Coll[Byte]] [WID list digest] + // R5: Coll[Coll[Byte]] Event data // R6: Coll[Byte] Permit contract script digest // R7: Int Commitment Count // ----------------- TOKENS @@ -46,7 +46,7 @@ sigmaProp( allOf( Coll( - SELF.R5[Coll[Byte]].get == widListDigest, + SELF.R4[Coll[Coll[Byte]]].get(0) == widListDigest, checkAllWIDs, fraudScriptCheck, ) diff --git a/src/main/scala/rosen/bridge/scripts/Permit.es b/src/main/scala/rosen/bridge/scripts/Permit.es index cc659f4..7b1d7bc 100644 --- a/src/main/scala/rosen/bridge/scripts/Permit.es +++ b/src/main/scala/rosen/bridge/scripts/Permit.es @@ -50,10 +50,10 @@ OUTPUTS(1).tokens(0)._2 == totalPermits - OUTPUTS(0).tokens(0)._2, OUTPUTS(1).tokens(0)._1 == SELF.tokens(0)._1, blake2b256(OUTPUTS(1).propositionBytes) == commitmentScriptHash, - OUTPUTS(1).R5[Coll[Byte]].isDefined, + OUTPUTS(1).R5[Coll[Coll[Byte]]].isDefined, OUTPUTS(1).R6[Coll[Byte]].isDefined, OUTPUTS(1).R7[Coll[Byte]].get == blake2b256(SELF.propositionBytes), - OUTPUTS(1).R4[Coll[Byte]].get == WID(0), + OUTPUTS(1).R4[Coll[Coll[Byte]]].get == WID, outputWithRWT == false, OUTPUTS(0).propositionBytes == SELF.propositionBytes, OUTPUTS(0).R4[Coll[Coll[Byte]]].get == WID, diff --git a/src/test/scala/testUtils/Boxes.scala b/src/test/scala/testUtils/Boxes.scala index e191233..5a04d83 100644 --- a/src/test/scala/testUtils/Boxes.scala +++ b/src/test/scala/testUtils/Boxes.scala @@ -300,8 +300,8 @@ object Boxes { .contract(contracts.Commitment._1) .tokens(new ErgoToken(networkConfig._2.tokens.RWTId, RWTCount)) .registers( - ErgoValueBuilder.buildFor(Colls.fromArray(WID)), - ErgoValueBuilder.buildFor(Colls.fromArray(eventId)), + ErgoValueBuilder.buildFor(Colls.fromArray(Seq(WID).map(item => Colls.fromArray(item)).toArray)), + ErgoValueBuilder.buildFor(Colls.fromArray(Seq(eventId).map(item => Colls.fromArray(item)).toArray)), ErgoValueBuilder.buildFor(Colls.fromArray(commitment)), ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))), ).build() @@ -309,13 +309,14 @@ object Boxes { def createTriggerEventBox(ctx: BlockchainContext, WID: Seq[Array[Byte]], commitment: Commitment, RWTCount: Long, commitmentCount: Option[Int] = None): OutBox = { val size = WID.length + val digest = scorex.crypto.hash.Blake2b256(WID.reduce((a, b) => a ++ b)) ctx.newTxBuilder().outBoxBuilder() .value(Configs.minBoxValue * size) .contract(contracts.WatcherTriggerEvent._1) .tokens(new ErgoToken(networkConfig._2.tokens.RWTId, RWTCount)) .registers( + ErgoValueBuilder.buildFor(Colls.fromArray(Seq(digest).map(item => Colls.fromArray(item)).toArray)), ErgoValueBuilder.buildFor(Colls.fromArray(commitment.partsArray().map(item => Colls.fromArray(item)))), - ErgoValueBuilder.buildFor(Colls.fromArray(scorex.crypto.hash.Blake2b256(WID.reduce((a, b) => a ++ b)))), ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))), ErgoValueBuilder.buildFor(commitmentCount.getOrElse(WID.size)) ).build() @@ -324,13 +325,14 @@ object Boxes { def createFakeTriggerEventBox(ctx: BlockchainContext, WID: Seq[Array[Byte]], commitment: Commitment, RWTCount: Long): OutBox = { val size = WID.length + val digest = scorex.crypto.hash.Blake2b256(WID.slice(1, WID.size).reduce((a, b) => a ++ b)) ctx.newTxBuilder().outBoxBuilder() .value(Configs.minBoxValue * size) .contract(contracts.WatcherTriggerEvent._1) .tokens(new ErgoToken(networkConfig._2.tokens.RWTId, RWTCount)) .registers( + ErgoValueBuilder.buildFor(Colls.fromArray(Seq(digest).map(item => Colls.fromArray(item)).toArray)), ErgoValueBuilder.buildFor(Colls.fromArray(commitment.partsArray().map(item => Colls.fromArray(item)))), - ErgoValueBuilder.buildFor(Colls.fromArray(scorex.crypto.hash.Blake2b256(WID.slice(1, WID.size).reduce((a, b) => a ++ b)))), ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))), ErgoValueBuilder.buildFor(WID.size) ).build() From 1614a7dae975bc5afe7c3cb8642bb43977d9299d Mon Sep 17 00:00:00 2001 From: "fateme.r" Date: Wed, 17 Jan 2024 12:45:15 +0330 Subject: [PATCH 7/7] Add extra check for permit counts in reward tx --- src/main/scala/rosen/bridge/scripts/EventTrigger.es | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/rosen/bridge/scripts/EventTrigger.es b/src/main/scala/rosen/bridge/scripts/EventTrigger.es index 2744ed0..30fe559 100644 --- a/src/main/scala/rosen/bridge/scripts/EventTrigger.es +++ b/src/main/scala/rosen/bridge/scripts/EventTrigger.es @@ -46,6 +46,7 @@ sigmaProp( allOf( Coll( + rewards.size == commitmentCount, SELF.R4[Coll[Coll[Byte]]].get(0) == widListDigest, checkAllWIDs, fraudScriptCheck,