Skip to content

Commit

Permalink
Merge pull request #1989 from ergoplatform/v5.0.11
Browse files Browse the repository at this point in the history
Candidate for 5.0.11 release
  • Loading branch information
kushti committed May 31, 2023
2 parents 49b9f0f + 2863949 commit 8ee9718
Show file tree
Hide file tree
Showing 19 changed files with 147 additions and 80 deletions.
19 changes: 6 additions & 13 deletions avldb/src/main/scala/scorex/db/KVStoreReader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -95,27 +95,20 @@ trait KVStoreReader extends AutoCloseable {
* @param end - end of the range (inclusive)
* @return
*/
def getRange(start: K, end: K, limit: Int = Int.MaxValue): Seq[(K, V)] = {
def getRange(start: K, end: K, limit: Int = Int.MaxValue): Array[(K, V)] = {
val ro = new ReadOptions()
ro.snapshot(db.getSnapshot)
val iter = db.iterator(ro)
try {
def check(key:Array[Byte]) = {
if (ByteArrayUtils.compare(key, end) <= 0) {
true
} else {
false
}
}
iter.seek(start)
val bf = mutable.ArrayBuffer.empty[(K, V)]
var elemCounter = 0
while (iter.hasNext && check(iter.peekNext.getKey) && elemCounter < limit) {
while (iter.hasNext && elemCounter < limit) {
val next = iter.next()
val key = next.getKey
val value = next.getValue
elemCounter += 1
bf += (key -> value)
if(ByteArrayUtils.compare(next.getKey, end) <= 0) {
elemCounter += 1
bf += (next.getKey -> next.getValue)
} else elemCounter = limit // break
}
bf.toArray[(K,V)]
} finally {
Expand Down
22 changes: 13 additions & 9 deletions src/main/resources/api/openapi.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
openapi: "3.0.2"

info:
version: "5.0.10"
version: "5.0.11"
title: Ergo Node API
description: API docs for Ergo Node. Models are shared between all Ergo products
contact:
Expand Down Expand Up @@ -3016,7 +3016,7 @@ paths:
application/json:
schema:
type: string
example: '02c9e71790399816b3e40b2207e9ade19a9b7fe0600186cfb8e2b115bfdb34b57f38cd3c9f2890d11720eb3bb993993f00ededf812a590d2993df094a7ca4f0213e4820e1ab831eed5dc5c72665396d3a01d2a12900f1c3ab77700b284ae24fa8e8f7754f86f2282c795db6b0b17df1c29cc0552e59d01f7d777c638a813333277271c2f8b4d99d01ff0e6ee8695697bdd5b568089395620d7198c6093ce8bc59b928611b1b12452c05addaa42f4beff6a0a6fe90000000380d0dbc3f40210090402040005c801040205c8010500040004000e2003faf2cb329f2e90d6d23b58d91bbb6c046aa143261cc21f52fbe2824bfcbf04d807d601e4c6a70408d602b2a5730000d603e4c6a70601d604e4c6a7080ed605e4c6a70505d606e4c6a70705d60795720399c1a7c1720299c17202c1a7eb027201d1ededededededededed93c27202c2a793e4c672020408720193e4c6720205059572039d9c72057eb272047301000573029d9c72057eb2720473030005730494e4c672020601720393e4c672020705720693e4c67202080e720493e4c67202090ec5a79572039072079c720672059272079c72067205917207730595ef720393b1db630872027306d801d608b2db63087202730700ed938c7208017308938c7208027206c8df35000508cd030c8f9c4dc08f3c006fa85a47c9156dedbede000a8b764c6e374fd097e873ba0405c8a8c105010105dc8b020e0266608cdea8baf0380008cd030c8f9c4dc08f3c006fa85a47c9156dedbede000a8b764c6e374fd097e873ba04c8df350000c0843d1005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304c8df350000'
example: '"02c9e71790399816b3e40b2207e9ade19a9b7fe0600186cfb8e2b115bfdb34b57f38cd3c9f2890d11720eb3bb993993f00ededf812a590d2993df094a7ca4f0213e4820e1ab831eed5dc5c72665396d3a01d2a12900f1c3ab77700b284ae24fa8e8f7754f86f2282c795db6b0b17df1c29cc0552e59d01f7d777c638a813333277271c2f8b4d99d01ff0e6ee8695697bdd5b568089395620d7198c6093ce8bc59b928611b1b12452c05addaa42f4beff6a0a6fe90000000380d0dbc3f40210090402040005c801040205c8010500040004000e2003faf2cb329f2e90d6d23b58d91bbb6c046aa143261cc21f52fbe2824bfcbf04d807d601e4c6a70408d602b2a5730000d603e4c6a70601d604e4c6a7080ed605e4c6a70505d606e4c6a70705d60795720399c1a7c1720299c17202c1a7eb027201d1ededededededededed93c27202c2a793e4c672020408720193e4c6720205059572039d9c72057eb272047301000573029d9c72057eb2720473030005730494e4c672020601720393e4c672020705720693e4c67202080e720493e4c67202090ec5a79572039072079c720672059272079c72067205917207730595ef720393b1db630872027306d801d608b2db63087202730700ed938c7208017308938c7208027206c8df35000508cd030c8f9c4dc08f3c006fa85a47c9156dedbede000a8b764c6e374fd097e873ba0405c8a8c105010105dc8b020e0266608cdea8baf0380008cd030c8f9c4dc08f3c006fa85a47c9156dedbede000a8b764c6e374fd097e873ba04c8df350000c0843d1005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304c8df350000"'
responses:
'200':
description: JSON with ID of the new transaction
Expand Down Expand Up @@ -3072,7 +3072,7 @@ paths:
application/json:
schema:
type: string
example: '02c9e71790399816b3e40b2207e9ade19a9b7fe0600186cfb8e2b115bfdb34b57f38cd3c9f2890d11720eb3bb993993f00ededf812a590d2993df094a7ca4f0213e4820e1ab831eed5dc5c72665396d3a01d2a12900f1c3ab77700b284ae24fa8e8f7754f86f2282c795db6b0b17df1c29cc0552e59d01f7d777c638a813333277271c2f8b4d99d01ff0e6ee8695697bdd5b568089395620d7198c6093ce8bc59b928611b1b12452c05addaa42f4beff6a0a6fe90000000380d0dbc3f40210090402040005c801040205c8010500040004000e2003faf2cb329f2e90d6d23b58d91bbb6c046aa143261cc21f52fbe2824bfcbf04d807d601e4c6a70408d602b2a5730000d603e4c6a70601d604e4c6a7080ed605e4c6a70505d606e4c6a70705d60795720399c1a7c1720299c17202c1a7eb027201d1ededededededededed93c27202c2a793e4c672020408720193e4c6720205059572039d9c72057eb272047301000573029d9c72057eb2720473030005730494e4c672020601720393e4c672020705720693e4c67202080e720493e4c67202090ec5a79572039072079c720672059272079c72067205917207730595ef720393b1db630872027306d801d608b2db63087202730700ed938c7208017308938c7208027206c8df35000508cd030c8f9c4dc08f3c006fa85a47c9156dedbede000a8b764c6e374fd097e873ba0405c8a8c105010105dc8b020e0266608cdea8baf0380008cd030c8f9c4dc08f3c006fa85a47c9156dedbede000a8b764c6e374fd097e873ba04c8df350000c0843d1005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304c8df350000'
example: '"02c9e71790399816b3e40b2207e9ade19a9b7fe0600186cfb8e2b115bfdb34b57f38cd3c9f2890d11720eb3bb993993f00ededf812a590d2993df094a7ca4f0213e4820e1ab831eed5dc5c72665396d3a01d2a12900f1c3ab77700b284ae24fa8e8f7754f86f2282c795db6b0b17df1c29cc0552e59d01f7d777c638a813333277271c2f8b4d99d01ff0e6ee8695697bdd5b568089395620d7198c6093ce8bc59b928611b1b12452c05addaa42f4beff6a0a6fe90000000380d0dbc3f40210090402040005c801040205c8010500040004000e2003faf2cb329f2e90d6d23b58d91bbb6c046aa143261cc21f52fbe2824bfcbf04d807d601e4c6a70408d602b2a5730000d603e4c6a70601d604e4c6a7080ed605e4c6a70505d606e4c6a70705d60795720399c1a7c1720299c17202c1a7eb027201d1ededededededededed93c27202c2a793e4c672020408720193e4c6720205059572039d9c72057eb272047301000573029d9c72057eb2720473030005730494e4c672020601720393e4c672020705720693e4c67202080e720493e4c67202090ec5a79572039072079c720672059272079c72067205917207730595ef720393b1db630872027306d801d608b2db63087202730700ed938c7208017308938c7208027206c8df35000508cd030c8f9c4dc08f3c006fa85a47c9156dedbede000a8b764c6e374fd097e873ba0405c8a8c105010105dc8b020e0266608cdea8baf0380008cd030c8f9c4dc08f3c006fa85a47c9156dedbede000a8b764c6e374fd097e873ba04c8df350000c0843d1005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304c8df350000"'
responses:
'200':
description: JSON with ID of the new transaction
Expand Down Expand Up @@ -5781,7 +5781,8 @@ paths:
application/json:
description: adderess associated with transactions
schema:
$ref: '#/components/schemas/ErgoAddress'
type: string
example: '"3WwbzW6u8hKWBcL1W7kNVMr25s2UHfSBnYtwSHvrRQt7DdPuoXrt"'
parameters:
- in: query
name: offset
Expand Down Expand Up @@ -5946,7 +5947,8 @@ paths:
application/json:
description: adderess associated with boxes
schema:
$ref: '#/components/schemas/ErgoAddress'
type: string
example: '"3WwbzW6u8hKWBcL1W7kNVMr25s2UHfSBnYtwSHvrRQt7DdPuoXrt"'
parameters:
- in: query
name: offset
Expand Down Expand Up @@ -6005,7 +6007,8 @@ paths:
application/json:
description: adderess associated with unspent boxes
schema:
$ref: '#/components/schemas/ErgoAddress'
type: string
example: '"3WwbzW6u8hKWBcL1W7kNVMr25s2UHfSBnYtwSHvrRQt7DdPuoXrt"'
parameters:
- in: query
name: offset
Expand Down Expand Up @@ -6106,7 +6109,7 @@ paths:
description: hex encoded ergotree
schema:
type: string
example: '100204a00b08cd021cf943317b0fdb50f60892a46b9132b9ced337c7de79248b104b293d9f1f078eea02d192a39a8cc7a70173007301'
example: '"100204a00b08cd021cf943317b0fdb50f60892a46b9132b9ced337c7de79248b104b293d9f1f078eea02d192a39a8cc7a70173007301"'
parameters:
- in: query
name: offset
Expand Down Expand Up @@ -6160,7 +6163,7 @@ paths:
description: hex encoded ergotree
schema:
type: string
example: '100204a00b08cd021cf943317b0fdb50f60892a46b9132b9ced337c7de79248b104b293d9f1f078eea02d192a39a8cc7a70173007301'
example: '"100204a00b08cd021cf943317b0fdb50f60892a46b9132b9ced337c7de79248b104b293d9f1f078eea02d192a39a8cc7a70173007301"'
parameters:
- in: query
name: offset
Expand Down Expand Up @@ -6259,7 +6262,8 @@ paths:
application/json:
description: adderess with balance
schema:
$ref: '#/components/schemas/ErgoAddress'
type: string
example: '"3WwbzW6u8hKWBcL1W7kNVMr25s2UHfSBnYtwSHvrRQt7DdPuoXrt"'
responses:
'200':
description: balance information
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ scorex {
nodeName = "ergo-node"

# Network protocol version to be sent in handshakes
appVersion = 5.0.10
appVersion = 5.0.11

# Network agent name. May contain information about client code
# stack, starting from core code-base up to the end graphical interface.
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/mainnet.conf
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ scorex {
network {
magicBytes = [1, 0, 2, 4]
bindAddress = "0.0.0.0:9030"
nodeName = "ergo-mainnet-5.0.7"
nodeName = "ergo-mainnet-"${scorex.network.appVersion}
nodeName = ${?NODENAME}
knownPeers = [
"213.239.193.208:9030",
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/testnet.conf
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ scorex {
network {
magicBytes = [2, 0, 2, 3]
bindAddress = "0.0.0.0:9022"
nodeName = "ergo-testnet-5.0.4"
nodeName = "ergo-testnet-"${scorex.network.appVersion}
nodeName = ${?NODENAME}
knownPeers = [
"213.239.193.208:9022",
Expand Down
23 changes: 16 additions & 7 deletions src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import org.ergoplatform.nodeView.history.extra.IndexedErgoAddressSerializer.hash
import org.ergoplatform.nodeView.history.extra._
import org.ergoplatform.nodeView.mempool.ErgoMemPoolReader
import org.ergoplatform.settings.ErgoSettings
import scorex.core.api.http.ApiError.BadRequest
import scorex.core.api.http.ApiError.{BadRequest, InternalError}
import scorex.core.api.http.ApiResponse
import scorex.core.settings.RESTApiSettings
import scorex.util.{ModifierId, bytesToId}
Expand Down Expand Up @@ -55,15 +55,16 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting

private val ergoAddress: Directive1[ErgoAddress] = entity(as[String]).flatMap(handleErgoAddress)

private def handleErgoAddress(value: String): Directive1[ErgoAddress] = {
ergoAddressEncoder.fromString(value) match {
private def handleErgoAddress(value: String): Directive1[ErgoAddress] =
ergoAddressEncoder.fromString(fromJsonOrPlain(value)) match {
case Success(addr) => provide(addr)
case _ => reject(ValidationRejection("Wrong address format"))
}
}

override val route: Route = pathPrefix("blockchain") {
getIndexedHeightR ~
override val route: Route =
if(ergoSettings.nodeSettings.extraIndex)
pathPrefix("blockchain") {
getIndexedHeightR ~
getTxByIdR ~
getTxByIndexR ~
getTxsByAddressR ~
Expand All @@ -77,7 +78,11 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting
getBoxesByErgoTreeUnspentR ~
getTokenInfoByIdR ~
getAddressBalanceTotalR
}
}
else
pathPrefix("blockchain") {
indexerNotEnabledR
}

private def getHistory: Future[ErgoHistoryReader] =
(readersHolder ? GetDataFromHistory[ErgoHistoryReader](r => r)).mapTo[ErgoHistoryReader]
Expand Down Expand Up @@ -114,6 +119,10 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting
ApiResponse(getIndexedHeightF)
}

private def indexerNotEnabledR: Route = get {
InternalError("Extra indexing is not enabled")
}

private def getTxByIdR: Route = (get & pathPrefix("transaction" / "byId") & modifierId) { id =>
ApiResponse(getTxByIdF(id))
}
Expand Down
10 changes: 9 additions & 1 deletion src/main/scala/org/ergoplatform/http/api/ErgoBaseApiRoute.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.ergoplatform.settings.{Algos, ErgoSettings}
import scorex.core.api.http.{ApiError, ApiRoute}
import scorex.util.{ModifierId, bytesToId}
import akka.pattern.ask
import io.circe.syntax.EncoderOps
import org.ergoplatform.nodeView.ErgoNodeViewHolder.ReceivableMessages.LocallyGeneratedTransaction
import org.ergoplatform.nodeView.mempool.ErgoMemPool.ProcessingOutcome
import org.ergoplatform.nodeView.mempool.ErgoMemPool.ProcessingOutcome._
Expand All @@ -37,10 +38,17 @@ trait ErgoBaseApiRoute extends ApiRoute with ApiCodecs {
}
}

def fromJsonOrPlain(str: String): String =
str.asJson.as[String] match {
case Right(value) if value.startsWith("\"") && value.endsWith("\"") =>
value.substring(1, value.length - 1)
case _ => str
}

val ergoTree: Directive1[ErgoTree] = entity(as[String]).flatMap(handleErgoTree)

private def handleErgoTree(value: String): Directive1[ErgoTree] = {
Base16.decode(value) match {
Base16.decode(fromJsonOrPlain(value)) match {
case Success(bytes) => provide(ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes))
case _ => reject(ValidationRejection("Invalid hex data"))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ case class TransactionsApiRoute(readersHolder: ActorRef,
* Validate and broadcast transaction given as hex-encoded bytes
*/
def sendTransactionAsBytesR: Route = (path("bytes") & pathEnd & post & entity(as[String])) { txBytesStr =>
Base16.decode(txBytesStr).flatMap(ErgoTransactionSerializer.parseBytesTry) match {
Base16.decode(fromJsonOrPlain(txBytesStr)).flatMap(ErgoTransactionSerializer.parseBytesTry) match {
case Success(tx) =>
validateTransactionAndProcess(tx)(validTx => sendLocalTransactionRoute(nodeViewActorRef, validTx))
case Failure(e) =>
Expand All @@ -124,7 +124,7 @@ case class TransactionsApiRoute(readersHolder: ActorRef,
* Check transaction given as hex-encoded bytes
*/
def checkTransactionAsBytesR: Route = (path("checkBytes") & post & entity(as[String])) { txBytesStr =>
Base16.decode(txBytesStr).flatMap(ErgoTransactionSerializer.parseBytesTry) match {
Base16.decode(fromJsonOrPlain(txBytesStr)).flatMap(ErgoTransactionSerializer.parseBytesTry) match {
case Success(tx) =>
validateTransactionAndProcess(tx)(validTx => ApiResponse(validTx.transaction.id))
case Failure(e) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import org.ergoplatform.nodeView.wallet.requests.{ExternalSecret, TransactionGen
import org.ergoplatform.nodeView.wallet.scanning.{Scan, ScanRequest}
import org.ergoplatform.settings.{ErgoSettings, Parameters}
import org.ergoplatform.wallet.Constants.ScanId
import org.ergoplatform.wallet.boxes.{BoxSelector, ErgoBoxSerializer}
import org.ergoplatform.wallet.boxes.{BoxSelector, ErgoBoxSerializer, TrackedBox}
import org.ergoplatform.wallet.interface4j.SecretString
import org.ergoplatform.wallet.interpreter.{ErgoProvingInterpreter, TransactionHintsBag}
import org.ergoplatform.wallet.mnemonic.Mnemonic
Expand All @@ -26,6 +26,7 @@ import sigmastate.Values.SigmaBoolean
import sigmastate.basics.DLogProtocol.DLogProverInput

import java.io.FileNotFoundException
import scala.collection.compat.immutable.ArraySeq
import scala.util.{Failure, Success, Try}

/**
Expand Down Expand Up @@ -417,14 +418,15 @@ class ErgoWalletServiceImpl(override val ergoSettings: ErgoSettings) extends Erg
}

override def getScanUnspentBoxes(state: ErgoWalletState, scanId: ScanId, considerUnconfirmed: Boolean, minHeight: Int, maxHeight: Int): Seq[WalletBox] = {
val unconfirmed = if (considerUnconfirmed) {
state.offChainRegistry.offChainBoxes.filter(_.scans.contains(scanId))
} else {
Seq.empty
}
val unconfirmed: Seq[TrackedBox] =
if (considerUnconfirmed) {
state.offChainRegistry.offChainBoxes.filter(_.scans.contains(scanId))
} else {
ArraySeq.empty[TrackedBox]
}

val currentHeight = state.fullHeight
val unspentBoxes = state.registry.unspentBoxesByInclusionHeight(scanId, minHeight, maxHeight)
val unspentBoxes: Seq[TrackedBox] = state.registry.unspentBoxesByInclusionHeight(scanId, minHeight, maxHeight)
(unspentBoxes ++ unconfirmed).map(tb => WalletBox(tb, currentHeight)).sortBy(_.trackedBox.inclusionHeightOpt)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ case class ErgoWalletState(
// State context used to sign transactions and check that coins found in the blockchain are indeed belonging
// to the wallet (by executing testing transactions against them).
// The state context is being updated by listening to state updates.
def stateContext: ErgoStateContext = storage.readStateContext(parameters)
def stateContext: ErgoStateContext = storage.getStateContext(parameters)

/**
* @return height of the last block scanned by the wallet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import org.ergoplatform.wallet.boxes.TrackedBox
import scorex.util.{ModifierId, ScorexLogging}
import scorex.util.bytesToId

import scala.collection.compat.immutable.ArraySeq
import scala.collection.immutable.TreeSet
import scala.collection.mutable
import scala.util.Try

Expand Down Expand Up @@ -94,7 +96,7 @@ object WalletScanLogic extends ScorexLogging {
tb.copy(scans = Set(PaymentsScanId))
}

val initialScanResults = ScanResults(resolvedBoxes, Seq.empty, Seq.empty)
val initialScanResults = ScanResults(resolvedBoxes, ArraySeq.empty, ArraySeq.empty)

// Wallet unspent outputs, we fetch them only when Bloom filter shows that some outputs may be spent
val unspentBoxes = mutable.Map[ModifierId, TrackedBox]()
Expand Down Expand Up @@ -168,7 +170,7 @@ object WalletScanLogic extends ScorexLogging {
//data needed to update the offchain-registry
val walletUnspent = registry.walletUnspentBoxes()
val newOnChainIds = scanRes.outputs.map(x => encodedBoxId(x.box.id))
val updatedOffchainRegistry = offChainRegistry.updateOnBlock(height, walletUnspent, newOnChainIds)
val updatedOffchainRegistry = offChainRegistry.updateOnBlock(height, walletUnspent, newOnChainIds.to[TreeSet])

(registry, updatedOffchainRegistry, outputsFilter)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package org.ergoplatform.nodeView.wallet.persistence

import org.ergoplatform.nodeView.wallet.IdUtils._
import org.ergoplatform.nodeView.wallet.IdUtils.{EncodedBoxId, encodedBoxId}
import org.ergoplatform.wallet.boxes.TrackedBox
import scorex.util.{ModifierId, bytesToId}

case class Balance(id: EncodedBoxId,
value: Long,
assets: Map[EncodedTokenId, Long])
assets: Map[ModifierId, Long])

object Balance {
def apply(tb: TrackedBox): Balance = Balance(encodedBoxId(tb.box.id), tb.box.value,
tb.box.additionalTokens.toArray.map(x => encodedTokenId(x._1) -> x._2).toMap)
tb.box.additionalTokens.toArray.map(x => (bytesToId(x._1), x._2)).toMap)
}

0 comments on commit 8ee9718

Please sign in to comment.