Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions appkit/src/test/scala/org/ergoplatform/appkit/BabelFeeSpec.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.ergoplatform.appkit

import org.ergoplatform.appkit.babelfee.{BabelFeeBoxContract, BabelFeeBoxState, BabelFeeOperations}
import org.ergoplatform.appkit.impl.ErgoTreeContract
import org.ergoplatform.sdk.{ErgoId, ErgoToken, SecretString}
import org.scalatest.matchers.should.Matchers
import org.scalatest.propspec.AnyPropSpec
Expand Down Expand Up @@ -104,6 +105,39 @@ class BabelFeeSpec extends AnyPropSpec with Matchers with ScalaCheckDrivenProper
}
}

property("babel fee box with non-positive price is rejected") {
val ergoClient = createMockedErgoClient(MockData(Nil, Nil))
ergoClient.execute { ctx: BlockchainContext =>
val creator = address

// builds a babel fee box directly (bypassing BabelFeeBoxStateBuilder, which
// validates the price) the way a box created outside appkit appears on chain
def babelBoxWithPrice(price: Long): InputBox = {
ctx.newTxBuilder.outBoxBuilder
.value(Parameters.OneErg)
.contract(new ErgoTreeContract(
new BabelFeeBoxContract(ErgoId.create(mockTokenId)).getErgoTree, ctx.getNetworkType))
.registers(ErgoValue.of(SigmaProp.createFromAddress(creator)), ErgoValue.of(price))
.build().convertToInputWith(mockTokenId, 0)
}

// a price of zero divides by zero in getMaxTokenAmountToBuy and
// calcTokensToSellForErgAmount, a negative price makes them return nonsense:
// both must be rejected when the state is parsed from a box
intercept[IllegalStateException] {
new BabelFeeBoxState(babelBoxWithPrice(0))
}
intercept[IllegalStateException] {
new BabelFeeBoxState(babelBoxWithPrice(-1))
}

// a regular price still parses and calculates as before
val state = new BabelFeeBoxState(babelBoxWithPrice(Parameters.MinFee))
state.getPricePerToken shouldBe Parameters.MinFee
state.calcTokensToSellForErgAmount(Parameters.MinFee) shouldBe 1
}
}

property("fetch babel fee boxes") {
val ergoClient = createMockedErgoClient(MockData(Nil, Nil))
ergoClient.execute { ctx: BlockchainContext =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ public BabelFeeBoxState(TransactionBox ergoBox) {
List<ErgoValue<?>> registers = ergoBox.getRegisters();
boxCreator = new SigmaProp((sigma.SigmaProp) registers.get(0).getValue());
pricePerToken = (Long) registers.get(1).getValue();
if (pricePerToken <= 0) {
// a box can be created outside appkit with any register values, so unlike
// BabelFeeBoxStateBuilder this parse path cannot assume a valid price:
// zero would divide by zero in getMaxTokenAmountToBuy and
// calcTokensToSellForErgAmount, a negative price makes them return nonsense
throw new IllegalStateException("Price per token of babel fee box must be greater than 0, but was " + pricePerToken);
}
this.tokenId = new BabelFeeBoxContract(ergoBox.getErgoTree()).getTokenId();

if (!ergoBox.getTokens().isEmpty()) {
Expand All @@ -52,6 +59,8 @@ public BabelFeeBoxState(TransactionBox ergoBox) {
}

BabelFeeBoxState(long pricePerToken, ErgoId tokenId, SigmaProp boxCreator, long value, long tokenAmount) {
if (pricePerToken <= 0)
throw new IllegalArgumentException("pricePerToken must be greater than 0");
this.pricePerToken = pricePerToken;
this.tokenId = tokenId;
this.boxCreator = boxCreator;
Expand Down