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

org.plasmalabs.sdk.codecs.PropositionTemplateCodecs.scala Maven / Gradle / Ivy

The newest version!
package org.plasmalabs.sdk.codecs

import cats.Monad
import cats.implicits.{catsSyntaxEitherId, catsSyntaxOptionId, toBifunctorOps}
import org.plasmalabs.sdk.builders.locks.PropositionTemplate
import org.plasmalabs.sdk.builders.locks.PropositionTemplate._
import org.plasmalabs.sdk.utils.Encoding.{decodeFromBase58, encodeToBase58}
import com.google.protobuf.ByteString
import io.circe.syntax.EncoderOps
import io.circe.{Decoder, DecodingFailure, Encoder, HCursor, Json}
import org.plasmalabs.quivr.models.{Data, Digest}

object PropositionTemplateCodecs {
  def encodePropositionTemplate[F[_]: Monad](template: PropositionTemplate[F]): Json = template.asJson

  def decodePropositionTemplate[F[_]: Monad](template: Json): Either[DecodingFailure, PropositionTemplate[F]] =
    template.as[PropositionTemplate[F]]

  /**
   * JSON encoder for a Generic Proposition Template
   */
  implicit def propositionTemplateToJson[F[_]: Monad]: Encoder[PropositionTemplate[F]] =
    new Encoder[PropositionTemplate[F]] {

      override def apply(a: PropositionTemplate[F]): Json =
        Json
          .obj("type" -> Json.fromString(a.propositionType.label))
          .deepMerge(a match {
            case locked: LockedTemplate[F]       => locked.asJson
            case height: HeightTemplate[F]       => height.asJson
            case tick: TickTemplate[F]           => tick.asJson
            case digest: DigestTemplate[F]       => digest.asJson
            case signature: SignatureTemplate[F] => signature.asJson
            case and: AndTemplate[F]             => and.asJson
            case or: OrTemplate[F]               => or.asJson
            case not: NotTemplate[F]             => not.asJson
            case threshold: ThresholdTemplate[F] => threshold.asJson
            case _                               => Json.Null
          })
    }

  /**
   * JSON decoder for a generic Proposition Template
   */
  implicit def propositionTemplateFromJson[F[_]: Monad]: Decoder[PropositionTemplate[F]] =
    new Decoder[PropositionTemplate[F]] {

      override def apply(c: HCursor): Decoder.Result[PropositionTemplate[F]] =
        c.downField("type").as[String] match {
          case Right(PropositionTemplate.types.Locked.label)    => c.as[LockedTemplate[F]]
          case Right(PropositionTemplate.types.Height.label)    => c.as[HeightTemplate[F]]
          case Right(PropositionTemplate.types.Tick.label)      => c.as[TickTemplate[F]]
          case Right(PropositionTemplate.types.Digest.label)    => c.as[DigestTemplate[F]]
          case Right(PropositionTemplate.types.Signature.label) => c.as[SignatureTemplate[F]]
          case Right(PropositionTemplate.types.And.label)       => c.as[AndTemplate[F]]
          case Right(PropositionTemplate.types.Or.label)        => c.as[OrTemplate[F]]
          case Right(PropositionTemplate.types.Not.label)       => c.as[NotTemplate[F]]
          case Right(PropositionTemplate.types.Threshold.label) => c.as[ThresholdTemplate[F]]
          case _ => Left(DecodingFailure("Unknown Proposition Type", c.history))
        }
    }

  /**
   * JSON encoder for a Locked Proposition Template
   */
  implicit def lockedTemplateToJson[F[_]: Monad]: Encoder[LockedTemplate[F]] = new Encoder[LockedTemplate[F]] {

    override def apply(a: LockedTemplate[F]): Json =
      if (a.data.isEmpty) Json.obj()
      else Json.obj("data" -> Json.fromString(encodeToBase58(a.data.get.value.toByteArray)))
  }

  /**
   * JSON decoder for a Locked Proposition Template
   */
  implicit def lockedTemplateFromJson[F[_]: Monad]: Decoder[LockedTemplate[F]] = new Decoder[LockedTemplate[F]] {

    override def apply(c: HCursor): Decoder.Result[LockedTemplate[F]] = c.downField("data").as[String] match {
      case Left(_) => LockedTemplate[F](None).asRight
      case Right(data) =>
        decodeFromBase58(data)
          .map(d => LockedTemplate[F](Data(ByteString.copyFrom(d)).some))
          .leftMap(DecodingFailure.fromThrowable(_, c.history))
    }
  }

  /**
   * JSON encoder for a Height Proposition Template
   */
  implicit def heightTemplateToJson[F[_]: Monad]: Encoder[HeightTemplate[F]] = new Encoder[HeightTemplate[F]] {

    override def apply(a: HeightTemplate[F]): Json = Json.obj(
      "chain" -> Json.fromString(a.chain),
      "min"   -> Json.fromLong(a.min),
      "max"   -> Json.fromLong(a.max)
    )
  }

  /**
   * JSON decoder for a Height Proposition Template
   */
  implicit def heightTemplateFromJson[F[_]: Monad]: Decoder[HeightTemplate[F]] = new Decoder[HeightTemplate[F]] {

    override def apply(c: HCursor): Decoder.Result[HeightTemplate[F]] =
      for {
        chain <- c.downField("chain").as[String]
        min   <- c.downField("min").as[Long]
        max   <- c.downField("max").as[Long]
      } yield HeightTemplate[F](chain, min, max)
  }

  /**
   * JSON encoder for a Tick Proposition Template
   */
  implicit def tickTemplateToJson[F[_]: Monad]: Encoder[TickTemplate[F]] = new Encoder[TickTemplate[F]] {

    override def apply(a: TickTemplate[F]): Json = Json.obj(
      "min" -> Json.fromLong(a.min),
      "max" -> Json.fromLong(a.max)
    )
  }

  /**
   * JSON decoder for a Tick Proposition Template
   */
  implicit def tickTemplateFromJson[F[_]: Monad]: Decoder[TickTemplate[F]] = new Decoder[TickTemplate[F]] {

    override def apply(c: HCursor): Decoder.Result[TickTemplate[F]] =
      for {
        min <- c.downField("min").as[Long]
        max <- c.downField("max").as[Long]
      } yield TickTemplate[F](min, max)
  }

  /**
   * JSON encoder for a Digest Proposition Template
   */
  implicit def digestTemplateToJson[F[_]: Monad]: Encoder[DigestTemplate[F]] = new Encoder[DigestTemplate[F]] {

    override def apply(a: DigestTemplate[F]): Json =
      Json.obj(
        "routine" -> Json.fromString(a.routine),
        "digest"  -> Json.fromString(encodeToBase58(a.digest.value.toByteArray))
      )
  }

  /**
   * JSON decoder for a Digest Proposition Template
   */
  implicit def digestTemplateFromJson[F[_]: Monad]: Decoder[DigestTemplate[F]] = new Decoder[DigestTemplate[F]] {

    override def apply(c: HCursor): Decoder.Result[DigestTemplate[F]] = {
      val decodeResult = for {
        routine <- c.downField("routine").as[String]
        digest  <- c.downField("digest").as[String]
      } yield (routine, decodeFromBase58(digest))
      decodeResult match {
        case Left(err) => err.asLeft
        case Right((routine, Right(digestBytes))) =>
          DigestTemplate[F](routine, Digest(ByteString.copyFrom(digestBytes))).asRight
        case Right((_, Left(err))) => DecodingFailure.fromThrowable(err, c.history).asLeft
      }
    }
  }

  /**
   * JSON encoder for a Signature Proposition Template
   */
  implicit def signatureTemplateToJson[F[_]: Monad]: Encoder[SignatureTemplate[F]] = new Encoder[SignatureTemplate[F]] {

    override def apply(a: SignatureTemplate[F]): Json = Json.obj(
      "routine"   -> Json.fromString(a.routine),
      "entityIdx" -> Json.fromInt(a.entityIdx)
    )
  }

  /**
   * JSON decoder for a Signature Proposition Template
   */
  implicit def signatureTemplateFromJson[F[_]: Monad]: Decoder[SignatureTemplate[F]] =
    new Decoder[SignatureTemplate[F]] {

      override def apply(c: HCursor): Decoder.Result[SignatureTemplate[F]] =
        for {
          routine   <- c.downField("routine").as[String]
          entityIdx <- c.downField("entityIdx").as[Int]
        } yield SignatureTemplate[F](routine, entityIdx)
    }

  /**
   * JSON encoder for a And Proposition Template
   */
  implicit def andTemplateToJson[F[_]: Monad]: Encoder[AndTemplate[F]] = new Encoder[AndTemplate[F]] {

    override def apply(a: AndTemplate[F]): Json = Json.obj(
      "left"  -> a.leftTemplate.asJson,
      "right" -> a.rightTemplate.asJson
    )
  }

  /**
   * JSON decoder for a And Proposition Template
   */
  implicit def andTemplateFromJson[F[_]: Monad]: Decoder[AndTemplate[F]] = new Decoder[AndTemplate[F]] {

    override def apply(c: HCursor): Decoder.Result[AndTemplate[F]] =
      for {
        left  <- c.downField("left").as[PropositionTemplate[F]]
        right <- c.downField("right").as[PropositionTemplate[F]]
      } yield AndTemplate[F](left, right)
  }

  /**
   * JSON encoder for a Or Proposition Template
   */
  implicit def orTemplateToJson[F[_]: Monad]: Encoder[OrTemplate[F]] = new Encoder[OrTemplate[F]] {

    override def apply(a: OrTemplate[F]): Json = Json.obj(
      "left"  -> a.leftTemplate.asJson,
      "right" -> a.rightTemplate.asJson
    )
  }

  /**
   * JSON decoder for a Or Proposition Template
   */
  implicit def orTemplateFromJson[F[_]: Monad]: Decoder[OrTemplate[F]] = new Decoder[OrTemplate[F]] {

    override def apply(c: HCursor): Decoder.Result[OrTemplate[F]] =
      for {
        left  <- c.downField("left").as[PropositionTemplate[F]]
        right <- c.downField("right").as[PropositionTemplate[F]]
      } yield OrTemplate[F](left, right)
  }

  /**
   * JSON encoder for a Not Proposition Template
   */
  implicit def notTemplateToJson[F[_]: Monad]: Encoder[NotTemplate[F]] = new Encoder[NotTemplate[F]] {

    override def apply(a: NotTemplate[F]): Json = Json.obj(
      "innerTemplate" -> a.innerTemplate.asJson
    )
  }

  /**
   * JSON decoder for a Not Proposition Template
   */
  implicit def notTemplateFromJson[F[_]: Monad]: Decoder[NotTemplate[F]] = new Decoder[NotTemplate[F]] {

    override def apply(c: HCursor): Decoder.Result[NotTemplate[F]] =
      for {
        innerTemplate <- c.downField("innerTemplate").as[PropositionTemplate[F]]
      } yield NotTemplate[F](innerTemplate)
  }

  /**
   * JSON encoder for a Threshold Proposition Template
   */
  implicit def thresholdTemplateToJson[F[_]: Monad]: Encoder[ThresholdTemplate[F]] = new Encoder[ThresholdTemplate[F]] {

    override def apply(a: ThresholdTemplate[F]): Json = Json.obj(
      "threshold"      -> Json.fromInt(a.threshold),
      "innerTemplates" -> a.innerTemplates.asJson
    )
  }

  /**
   * JSON decoder for a Threshold Proposition Template
   */
  implicit def thresholdTemplateFromJson[F[_]: Monad]: Decoder[ThresholdTemplate[F]] =
    new Decoder[ThresholdTemplate[F]] {

      override def apply(c: HCursor): Decoder.Result[ThresholdTemplate[F]] =
        for {
          threshold      <- c.downField("threshold").as[Int]
          innerTemplates <- c.downField("innerTemplates").as[Seq[PropositionTemplate[F]]]
        } yield ThresholdTemplate[F](innerTemplates, threshold)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy