diff --git a/src/main/scala/rosen/bridge/scripts/Commitment.es b/src/main/scala/rosen/bridge/scripts/Commitment.es index a66ca74..8371b20 100644 --- a/src/main/scala/rosen/bridge/scripts/Commitment.es +++ b/src/main/scala/rosen/bridge/scripts/Commitment.es @@ -9,14 +9,17 @@ 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){ // 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)} val permitBox = OUTPUTS.filter {(box:Box) => box.R4[Coll[Coll[Byte]]].isDefined && box.R4[Coll[Coll[Byte]]].get == myWID @@ -39,12 +42,18 @@ } else if (blake2b256(OUTPUTS(0).propositionBytes) == eventTriggerHash){ // Event Trigger Creation // [Commitments[]] + [Repo(DataInput)] => [EventTrigger] - val commitmentBoxes = INPUTS.filter { (box: Box) => SELF.propositionBytes == box.propositionBytes } + val commitmentBoxes = INPUTS.filter{ + (box: Box) => + SELF.propositionBytes == box.propositionBytes && + 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 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(event.R5[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 @@ -59,22 +68,23 @@ //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, - event.R6[Coll[Byte]].get == SELF.R7[Coll[Byte]].get, - WIDs.size == commitmentBoxes.size, + // verify trigger params + trigger.value >= EventBoxErgs, + trigger.R6[Coll[Byte]].get == SELF.R7[Coll[Byte]].get, + trigger.R7[Int].get == commitmentBoxes.size, + trigger.R4[Coll[Coll[Byte]]].get(0) == widListDigest, // verify commitment to be correct blake2b256(eventData ++ myWID(0)) == SELF.R6[Coll[Byte]].get, // check event id - SELF.R5[Coll[Coll[Byte]]].get == Coll(requestId), + SELF.R5[Coll[Coll[Byte]]].get == Coll(eventId), // check commitment count 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..30fe559 100644 --- a/src/main/scala/rosen/bridge/scripts/EventTrigger.es +++ b/src/main/scala/rosen/bridge/scripts/EventTrigger.es @@ -1,8 +1,9 @@ { // ----------------- REGISTERS - // R4: Coll[Coll[Byte]] [WID[]] + // 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 // 0: RWT @@ -28,20 +29,25 @@ ) ) } - 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 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, 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 / commitmentCount } } sigmaProp( allOf( Coll( - WIDs.size == mergeBoxes.size, + rewards.size == commitmentCount, + SELF.R4[Coll[Coll[Byte]]].get(0) == widListDigest, checkAllWIDs, fraudScriptCheck, ) diff --git a/src/test/scala/contracts/ContractTest.scala b/src/test/scala/contracts/ContractTest.scala index e447796..14557d8 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,86 @@ 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] { + prover.sign(tx) + } + }) + } + + /** + * @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] { - 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 +1013,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 +1044,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 +1075,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) } }) @@ -1069,36 +1133,134 @@ 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() + 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 +1310,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 +1461,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 c7507a0..5a04d83 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._ @@ -61,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)) @@ -137,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) @@ -264,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 @@ -291,29 +294,47 @@ 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(Seq(eventId).map(item => Colls.fromArray(item)).toArray)), ErgoValueBuilder.buildFor(Colls.fromArray(commitment)), ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))), ).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 + 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(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 + 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(WID.map(item => Colls.fromArray(item)).toArray)), + 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(Utils.getContractScriptHash(contracts.WatcherPermit._1))) + ErgoValueBuilder.buildFor(Colls.fromArray(Utils.getContractScriptHash(contracts.WatcherPermit._1))), + ErgoValueBuilder.buildFor(WID.size) ).build() }