All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wavesplatform.transaction.TxHelpers.scala Maven / Gradle / Ivy

The newest version!
package com.wavesplatform.transaction

import com.google.common.primitives.Ints
import com.wavesplatform.TestValues
import com.wavesplatform.account.*
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.common.utils.*
import com.wavesplatform.lang.directives.values.*
import com.wavesplatform.lang.script.ContractScript.ContractScriptImpl
import com.wavesplatform.lang.script.Script
import com.wavesplatform.lang.script.v1.ExprScript
import com.wavesplatform.lang.script.v1.ExprScript.ExprScriptImpl
import com.wavesplatform.lang.v1.FunctionHeader
import com.wavesplatform.lang.v1.compiler.Terms.{EXPR, FUNCTION_CALL}
import com.wavesplatform.lang.v1.compiler.TestCompiler
import com.wavesplatform.lang.v1.estimator.v3.ScriptEstimatorV3
import com.wavesplatform.state.diffs.ENOUGH_AMT
import com.wavesplatform.state.diffs.FeeValidation.{FeeConstants, FeeUnit, ScriptExtraFee}
import com.wavesplatform.state.{DataEntry, StringDataEntry}
import com.wavesplatform.test.*
import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves}
import com.wavesplatform.transaction.assets.*
import com.wavesplatform.transaction.assets.exchange.*
import com.wavesplatform.transaction.lease.{LeaseCancelTransaction, LeaseTransaction}
import com.wavesplatform.transaction.smart.InvokeScriptTransaction.Payment
import com.wavesplatform.transaction.smart.script.ScriptCompiler
import com.wavesplatform.transaction.smart.{InvokeExpressionTransaction, InvokeScriptTransaction, SetScriptTransaction}
import com.wavesplatform.transaction.transfer.MassTransferTransaction.ParsedTransfer
import com.wavesplatform.transaction.transfer.{MassTransferTransaction, TransferTransaction}
import com.wavesplatform.transaction.utils.EthConverters.*
import com.wavesplatform.transaction.utils.Signed
import monix.execution.atomic.AtomicLong
import org.web3j.crypto.ECKeyPair

object TxHelpers {
  def signer(i: Int): SeedKeyPair = KeyPair(Ints.toByteArray(i))
  def address(i: Int): Address    = signer(i).toAddress

  val defaultSigner: SeedKeyPair = signer(0)
  val defaultAddress: Address    = defaultSigner.toAddress
  val secondSigner: SeedKeyPair  = signer(1)
  val secondAddress: Address     = secondSigner.toAddress

  val defaultEthSigner: ECKeyPair = defaultSigner.toEthKeyPair

  def accountSeqGenerator(numberAccounts: Int, amount: Long): Seq[ParsedTransfer] = {
    val firstAccountNum = 100
    val lastAccountNum  = firstAccountNum + numberAccounts
    val accountsSeq = (firstAccountNum until lastAccountNum).map { num =>
      val recipient = signer(num).toAddress
      ParsedTransfer(recipient, TxNonNegativeAmount.unsafeFrom(amount))
    }
    accountsSeq
  }

  val matcher: SeedKeyPair = defaultSigner

  private[this] val lastTimestamp = AtomicLong(System.currentTimeMillis())
  def timestamp: Long             = lastTimestamp.getAndIncrement()

  @throws[IllegalArgumentException]
  def signature(sig: String): Proofs =
    Proofs(ByteStr.decodeBase58(sig).get)

  def genesis(address: Address, amount: Long = ENOUGH_AMT, timestamp: TxTimestamp = timestamp): GenesisTransaction =
    GenesisTransaction.create(address, amount, timestamp).explicitGet()

  def payment(from: KeyPair = defaultSigner, to: Address = secondAddress, amount: Long = 1.waves): PaymentTransaction =
    PaymentTransaction.create(from, to, amount, TestValues.fee, timestamp).explicitGet()

  def transfer(
      from: KeyPair = defaultSigner,
      to: AddressOrAlias = secondAddress,
      amount: Long = 1.waves,
      asset: Asset = Waves,
      fee: Long = TestValues.fee,
      feeAsset: Asset = Waves,
      attachment: ByteStr = ByteStr.empty,
      timestamp: TxTimestamp = timestamp,
      version: Byte = TxVersion.V2,
      chainId: Byte = AddressScheme.current.chainId
  ): TransferTransaction =
    TransferTransaction.selfSigned(version, from, to, asset, amount, feeAsset, fee, attachment, timestamp, chainId).explicitGet()

  def transferUnsigned(
      from: KeyPair = defaultSigner,
      to: AddressOrAlias = secondAddress,
      amount: Long = 1.waves,
      asset: Asset = Waves,
      fee: Long = TestValues.fee,
      feeAsset: Asset = Waves,
      version: Byte = TxVersion.V2
  ): TransferTransaction =
    TransferTransaction(
      version,
      from.publicKey,
      to,
      asset,
      TxPositiveAmount.unsafeFrom(amount),
      feeAsset,
      TxPositiveAmount.unsafeFrom(fee),
      ByteStr.empty,
      timestamp,
      Proofs.empty,
      to.chainId
    )

  def massTransfer(
      from: KeyPair = defaultSigner,
      to: Seq[(AddressOrAlias, Long)] = Seq(secondAddress -> 1.waves),
      asset: Asset = Waves,
      fee: Long = FeeConstants(TransactionType.MassTransfer) * FeeUnit,
      timestamp: TxTimestamp = timestamp,
      version: Byte = TxVersion.V2,
      chainId: Byte = AddressScheme.current.chainId
  ): MassTransferTransaction =
    MassTransferTransaction.selfSigned(version, from, asset,
      to.map { case (r, a) => MassTransferTransaction.ParsedTransfer(r, TxNonNegativeAmount.unsafeFrom(a)) },
      fee, timestamp, ByteStr.empty, chainId).explicitGet()

  def issue(
      issuer: KeyPair = defaultSigner,
      amount: Long = Long.MaxValue / 100,
      decimals: Byte = 0,
      name: String = "test",
      description: String = "description",
      fee: Long = 1.waves,
      script: Option[Script] = None,
      reissuable: Boolean = true,
      timestamp: TxTimestamp = timestamp,
      version: TxVersion = TxVersion.V2,
      chainId: Byte = AddressScheme.current.chainId
  ): IssueTransaction =
    IssueTransaction
      .selfSigned(version, issuer, name, description, amount, decimals, reissuable, script, fee, timestamp, chainId)
      .explicitGet()

  def reissue(
      asset: IssuedAsset,
      sender: KeyPair = defaultSigner,
      amount: Long = 1000,
      reissuable: Boolean = true,
      fee: Long = TestValues.fee,
      version: TxVersion = TxVersion.V2,
      chainId: Byte = AddressScheme.current.chainId
  ): ReissueTransaction =
    ReissueTransaction
      .selfSigned(version, sender, asset, amount, reissuable = reissuable, fee, timestamp, chainId)
      .explicitGet()

  def dataEntry(account: KeyPair, value: DataEntry[?]): DataTransaction =
    DataTransaction.selfSigned(TxVersion.V1, account, Seq(value), TestValues.fee * 3, timestamp).explicitGet()

  def dataSingle(account: KeyPair = defaultSigner, key: String = "test", value: String = "test", fee: Long = TestValues.fee): DataTransaction =
    data(account, Seq(StringDataEntry(key, value)), fee)

  def data(account: KeyPair, entries: Seq[DataEntry[?]], fee: Long = TestValues.fee * 3, version: TxVersion = TxVersion.V1): DataTransaction =
    DataTransaction.selfSigned(version, account, entries, fee, timestamp).explicitGet()

  def dataV2(
      account: KeyPair,
      entries: Seq[DataEntry[?]],
      fee: Long = TestValues.fee * 3,
      chainId: Byte = AddressScheme.current.chainId
  ): DataTransaction =
    DataTransaction.selfSigned(TxVersion.V2, account, entries, fee, timestamp, chainId).explicitGet()

  def dataWithMultipleEntries(account: KeyPair, entries: Seq[DataEntry[?]]): DataTransaction =
    DataTransaction.selfSigned(TxVersion.V1, account, entries, TestValues.fee * 3, timestamp).explicitGet()

  def burn(
      asset: IssuedAsset,
      amount: Long = 1,
      sender: KeyPair = defaultSigner,
      fee: Long = TestValues.fee,
      version: TxVersion = TxVersion.V3,
      chainId: Byte = AddressScheme.current.chainId
  ): BurnTransaction =
    BurnTransaction.selfSigned(version, sender, asset, amount, fee, timestamp, chainId).explicitGet()

  def updateAssetInfo(
      assetId: ByteStr,
      name: String = "updated_name",
      desc: String = "updated_desc",
      sender: KeyPair = defaultSigner,
      fee: Long = TestValues.fee,
      feeAsset: Asset = Waves,
      version: TxVersion = TxVersion.V1,
      chainId: Byte = AddressScheme.current.chainId
  ): UpdateAssetInfoTransaction =
    UpdateAssetInfoTransaction.selfSigned(version, sender, assetId, name, desc, timestamp, fee, feeAsset, chainId).explicitGet()

  def orderV3(orderType: OrderType, asset: Asset, feeAsset: Asset = Waves): Order = {
    order(orderType, asset, Waves, feeAsset)
  }

  def order(
      orderType: OrderType,
      amountAsset: Asset,
      priceAsset: Asset,
      feeAsset: Asset = Waves,
      amount: Long = 1L,
      price: Long = 1L,
      priceMode: OrderPriceMode = OrderPriceMode.Default,
      fee: Long = 1L,
      sender: KeyPair = defaultSigner,
      matcher: KeyPair = defaultSigner,
      timestamp: TxTimestamp = timestamp,
      expiration: TxTimestamp = timestamp + 100000,
      version: TxVersion = Order.V3,
      attachment: Option[ByteStr] = None
  ): Order = {
    Order
      .selfSigned(
        version,
        sender,
        matcher.publicKey,
        AssetPair(amountAsset, priceAsset),
        orderType,
        amount,
        price,
        timestamp,
        expiration,
        fee,
        feeAsset,
        priceMode,
        attachment
      )
      .explicitGet()
  }

  def exchangeFromOrders(
      order1: Order,
      order2: Order,
      matcher: KeyPair = defaultSigner,
      fee: Long = TestValues.fee,
      version: TxVersion = TxVersion.V2,
      chainId: Byte = AddressScheme.current.chainId
  ): ExchangeTransaction = exchangeFromOrders(order1, order2, order1.price.value, matcher, fee, version, chainId)

  def exchangeFromOrders(
      order1: Order,
      order2: Order,
      price: Long,
      matcher: KeyPair,
      fee: Long,
      version: TxVersion,
      chainId: Byte
  ): ExchangeTransaction =
    ExchangeTransaction
      .signed(
        version,
        matcher.privateKey,
        order1,
        order2,
        order1.amount.value,
        price,
        order1.matcherFee.value,
        order2.matcherFee.value,
        fee,
        timestamp,
        chainId
      )
      .explicitGet()

  def exchange(
      order1: Order,
      order2: Order,
      matcher: KeyPair = defaultSigner,
      amount: Long = 1L,
      price: Long = 1L,
      buyMatcherFee: Long = 1L,
      sellMatcherFee: Long = 1L,
      fee: Long = TestValues.fee,
      timestamp: Long = timestamp,
      version: TxVersion = TxVersion.V2,
      chainId: Byte = AddressScheme.current.chainId
  ): ExchangeTransaction =
    ExchangeTransaction
      .signed(
        version,
        matcher = matcher.privateKey,
        order1 = order1,
        order2 = order2,
        amount = amount,
        price = price,
        buyMatcherFee = buyMatcherFee,
        sellMatcherFee = sellMatcherFee,
        fee = fee,
        timestamp = timestamp,
        chainId = chainId
      )
      .explicitGet()

  def script(scriptText: String): Script = {
    val (script, _) = ScriptCompiler.compile(scriptText, ScriptEstimatorV3.latest).explicitGet()
    script
  }

  def exprScript(version: StdLibVersion)(scriptText: String): ExprScriptImpl =
    script(s"""
              |{-# STDLIB_VERSION ${version.id} #-}
              |{-# CONTENT_TYPE EXPRESSION #-}
              |
              |$scriptText
              |""".stripMargin) match {
      case es: ExprScriptImpl => es
      case other              => throw new IllegalStateException(s"Not an expression: $other")
    }

  def freeCallScript(scriptText: String, version: StdLibVersion = V6): ExprScriptImpl =
    TestCompiler(version).compileFreeCall(scriptText) match {
      case es: ExprScriptImpl => es
      case other              => throw new IllegalStateException(s"Not an expression: $other")
    }

  def scriptV5(scriptText: String): ContractScriptImpl =
    script(s"""
              |{-# STDLIB_VERSION 5 #-}
              |{-# CONTENT_TYPE DAPP #-}
              |
              |$scriptText
              |""".stripMargin) match {
      case cs: ContractScriptImpl => cs
      case other                  => throw new IllegalStateException(s"Not a contract: $other")
    }

  def scriptV6(scriptText: String): ContractScriptImpl =
    script(s"""
              |{-# STDLIB_VERSION 6 #-}
              |{-# CONTENT_TYPE DAPP #-}
              |
              |$scriptText
              |""".stripMargin) match {
      case cs: ContractScriptImpl => cs
      case other                  => throw new IllegalStateException(s"Not a contract: $other")
    }

  def estimate(script: Script): Int =
    math.toIntExact(
      Script
        .estimate(
          script,
          ScriptEstimatorV3.latest,
          fixEstimateOfVerifier = true,
          useContractVerifierLimit = false
        )
        .explicitGet()
    )

  def setScript(
      acc: KeyPair,
      script: Script,
      fee: Long = FeeConstants(TransactionType.SetScript) * FeeUnit,
      version: TxVersion = TxVersion.V1,
      chainId: Byte = AddressScheme.current.chainId,
      timestamp: TxTimestamp = timestamp
  ): SetScriptTransaction = {
    SetScriptTransaction.selfSigned(version, acc, Some(script), fee, timestamp, chainId).explicitGet()
  }

  def removeScript(
      acc: KeyPair,
      fee: Long = FeeConstants(TransactionType.SetScript) * FeeUnit,
      version: TxVersion = TxVersion.V1,
      chainId: Byte = AddressScheme.current.chainId,
      timestamp: TxTimestamp = timestamp
  ): SetScriptTransaction = {
    SetScriptTransaction.selfSigned(version, acc, None, fee, timestamp, chainId).explicitGet()
  }

  def setAssetScript(
      acc: KeyPair,
      asset: IssuedAsset,
      script: Script,
      fee: Long = FeeConstants(TransactionType.SetAssetScript) * FeeUnit + ScriptExtraFee,
      timestamp: TxTimestamp = timestamp,
      version: TxVersion = TxVersion.V1,
      chainId: Byte = AddressScheme.current.chainId
  ): SetAssetScriptTransaction = {
    SetAssetScriptTransaction.selfSigned(version, acc, asset, Some(script), fee, timestamp, chainId).explicitGet()
  }

  def invoke(
      dApp: AddressOrAlias = secondAddress,
      func: Option[String] = None,
      args: Seq[EXPR] = Nil,
      payments: Seq[Payment] = Nil,
      invoker: KeyPair = defaultSigner,
      fee: Long = FeeConstants(TransactionType.InvokeScript) * FeeUnit,
      feeAssetId: Asset = Waves,
      version: TxVersion = TxVersion.V2,
      timestamp: TxTimestamp = timestamp
  ): InvokeScriptTransaction = {
    val fc = func.map(name => functionCall(name, args*))
    Signed.invokeScript(version, invoker, dApp, fc, payments, fee, feeAssetId, timestamp)
  }

  def invokeExpression(
      expression: ExprScript,
      sender: KeyPair = defaultSigner,
      fee: Long = TestValues.fee,
      feeAssetId: Asset = Waves
  ): InvokeExpressionTransaction =
    InvokeExpressionTransaction.selfSigned(TxVersion.V1, sender, expression, fee, feeAssetId, timestamp).explicitGet()

  def functionCall(func: String, args: EXPR*): FUNCTION_CALL = {
    FUNCTION_CALL(FunctionHeader.User(func), args.toList)
  }

  def lease(
      sender: KeyPair = defaultSigner,
      recipient: AddressOrAlias = secondAddress,
      amount: Long = 10.waves,
      fee: Long = FeeConstants(TransactionType.Lease) * FeeUnit,
      timestamp: TxTimestamp = timestamp,
      version: TxVersion = TxVersion.V2
  ): LeaseTransaction = {
    LeaseTransaction.selfSigned(version, sender, recipient, amount, fee, timestamp).explicitGet()
  }

  def leaseCancel(
      leaseId: ByteStr,
      sender: KeyPair = defaultSigner,
      fee: Long = FeeConstants(TransactionType.LeaseCancel) * FeeUnit,
      timestamp: TxTimestamp = timestamp,
      version: TxVersion = TxVersion.V2,
      chainId: Byte = AddressScheme.current.chainId
  ): LeaseCancelTransaction = {
    LeaseCancelTransaction.selfSigned(version, sender, leaseId, fee, timestamp, chainId).explicitGet()
  }

  def sponsor(
      asset: IssuedAsset,
      minSponsoredAssetFee: Option[Long] = Some(TestValues.fee),
      sender: KeyPair = defaultSigner,
      fee: Long = 1.waves,
      version: TxVersion = TxVersion.V1,
      chainId: Byte = AddressScheme.current.chainId
  ): SponsorFeeTransaction = {
    SponsorFeeTransaction.selfSigned(version, sender, asset, minSponsoredAssetFee, fee, timestamp, chainId).explicitGet()
  }

  def createAlias(
      name: String = "alias",
      sender: KeyPair = defaultSigner,
      fee: Long = TestValues.fee,
      version: TxVersion = TxVersion.V2,
      chainId: Byte = AddressScheme.current.chainId
  ): CreateAliasTransaction = {
    CreateAliasTransaction.selfSigned(version, sender, name, fee, timestamp, chainId).explicitGet()
  }

  def ciFee(sc: Int = 0, nonNftIssue: Int = 0, freeCall: Boolean = false): Long =
    invokeFee(freeCall) + (sc + 1) * ScriptExtraFee - 1 + nonNftIssue * FeeConstants(TransactionType.Issue) * FeeUnit

  private def invokeFee(freeCall: Boolean) =
    if (freeCall)
      FeeUnit * FeeConstants(TransactionType.InvokeExpression)
    else
      FeeUnit * FeeConstants(TransactionType.InvokeScript)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy