From 49b6d39ab469820fd589db29763b5ce7682eb4d4 Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Thu, 1 Apr 2021 10:43:10 -0500 Subject: [PATCH] Implement Oracle Explorer Client (#2838) * WIP * Get POSt working for creating an announcement * Add ability POST oracle attestations * Add docs * Remove ExplorerMain * Update workflows to add oracleExplorerClient/test * Switch to test so it passes on CI * Add unit test, switch env to ExplorerEnv.Test * Remove extra comments * Add StringFactory to ExplorerEnv --- ...Linux_2.12_KeyManager_Wallet_DLC_Tests.yml | 2 +- ...Linux_2.13_KeyManager_Wallet_DLC_Tests.yml | 2 +- .../commons/serializers/JsonReaders.scala | 42 ++++++ build.sbt | 11 ++ .../explorer/client/SbExplorerClient.scala | 123 ++++++++++++++++++ .../bitcoins/explorer/env/ExplorerEnv.scala | 34 +++++ .../model/CreateAnnouncementExplorer.scala | 21 +++ .../explorer/model/CreateAttestations.scala | 13 ++ .../explorer/model/SbAnnouncementEvent.scala | 16 +++ .../explorer/picklers/ExplorerPicklers.scala | 10 ++ .../client/SbExplorerClientTest.scala | 101 ++++++++++++++ .../explorer/env/ExplorerEnvTest.scala | 14 ++ .../model/SbOracleEventExplorerTest.scala | 29 +++++ project/Deps.scala | 7 + 14 files changed, 423 insertions(+), 2 deletions(-) create mode 100644 oracle-explorer-client/src/main/scala/org/bitcoins/explorer/client/SbExplorerClient.scala create mode 100644 oracle-explorer-client/src/main/scala/org/bitcoins/explorer/env/ExplorerEnv.scala create mode 100644 oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/CreateAnnouncementExplorer.scala create mode 100644 oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/CreateAttestations.scala create mode 100644 oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/SbAnnouncementEvent.scala create mode 100644 oracle-explorer-client/src/main/scala/org/bitcoins/explorer/picklers/ExplorerPicklers.scala create mode 100644 oracle-explorer-client/src/test/scala/org/bitcoins/explorer/client/SbExplorerClientTest.scala create mode 100644 oracle-explorer-client/src/test/scala/org/bitcoins/explorer/env/ExplorerEnvTest.scala create mode 100644 oracle-explorer-client/src/test/scala/org/bitcoins/explorer/model/SbOracleEventExplorerTest.scala diff --git a/.github/workflows/Linux_2.12_KeyManager_Wallet_DLC_Tests.yml b/.github/workflows/Linux_2.12_KeyManager_Wallet_DLC_Tests.yml index d73794916e..15257f7a04 100644 --- a/.github/workflows/Linux_2.12_KeyManager_Wallet_DLC_Tests.yml +++ b/.github/workflows/Linux_2.12_KeyManager_Wallet_DLC_Tests.yml @@ -25,4 +25,4 @@ jobs: ~/.bitcoin-s/binaries key: ${{ runner.os }}-cache - name: run tests - run: sbt ++2.12.12 downloadBitcoind coverage keyManagerTest/test keyManager/coverageReport keyManager/coverageAggregate keyManager/coveralls feeProviderTest/test walletTest/test wallet/coverageReport wallet/coverageAggregate wallet/coveralls dlcOracleTest/test asyncUtilsTestJVM/test dlcOracle/coverageReport dlcOracle/coverageAggregate dlcOracle/coveralls + run: sbt ++2.12.12 downloadBitcoind coverage keyManagerTest/test keyManager/coverageReport keyManager/coverageAggregate keyManager/coveralls feeProviderTest/test walletTest/test wallet/coverageReport wallet/coverageAggregate wallet/coveralls dlcOracleTest/test asyncUtilsTestJVM/test oracleExplorerClient/test dlcOracle/coverageReport dlcOracle/coverageAggregate dlcOracle/coveralls diff --git a/.github/workflows/Linux_2.13_KeyManager_Wallet_DLC_Tests.yml b/.github/workflows/Linux_2.13_KeyManager_Wallet_DLC_Tests.yml index a585d2784c..db8f993cab 100644 --- a/.github/workflows/Linux_2.13_KeyManager_Wallet_DLC_Tests.yml +++ b/.github/workflows/Linux_2.13_KeyManager_Wallet_DLC_Tests.yml @@ -25,4 +25,4 @@ jobs: ~/.bitcoin-s/binaries key: ${{ runner.os }}-cache - name: run tests - run: sbt ++2.13.5 downloadBitcoind coverage keyManagerTest/test keyManager/coverageReport keyManager/coverageAggregate keyManager/coveralls feeProviderTest/test walletTest/test wallet/coverageReport wallet/coverageAggregate wallet/coveralls dlcOracleTest/test asyncUtilsTestJVM/test dlcOracle/coverageReport dlcOracle/coverageAggregate dlcOracle/coveralls + run: sbt ++2.13.5 downloadBitcoind coverage keyManagerTest/test keyManager/coverageReport keyManager/coverageAggregate keyManager/coveralls feeProviderTest/test walletTest/test wallet/coverageReport wallet/coverageAggregate wallet/coveralls dlcOracleTest/test asyncUtilsTestJVM/test oracleExplorerClient/test dlcOracle/coverageReport dlcOracle/coverageAggregate dlcOracle/coveralls diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonReaders.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonReaders.scala index 4a16ed60cb..6ca8f8bae0 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonReaders.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonReaders.scala @@ -21,6 +21,10 @@ import org.bitcoins.core.protocol.script.{ WitnessVersion, WitnessVersion0 } +import org.bitcoins.core.protocol.tlv.{ + OracleAnnouncementV0TLV, + OracleAttestmentV0TLV +} import org.bitcoins.core.protocol.transaction._ import org.bitcoins.core.protocol.{ Address, @@ -652,6 +656,44 @@ object JsonReaders { } } + implicit object OracleAnnouncementV0TLVReads + extends Reads[OracleAnnouncementV0TLV] { + + override def reads(json: JsValue): JsResult[OracleAnnouncementV0TLV] = + json match { + case JsString(s) => + OracleAnnouncementV0TLV.fromHexT(s) match { + case Success(ann) => JsSuccess(ann) + case Failure(err) => + SerializerUtil.buildJsErrorMsg( + s"Unexpected Service Identifier: $err", + json) + } + case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray | + _: JsObject) => + SerializerUtil.buildJsErrorMsg("jsstring", err) + } + } + + implicit object OracleAttestmentV0TLVReads + extends Reads[OracleAttestmentV0TLV] { + + override def reads(json: JsValue): JsResult[OracleAttestmentV0TLV] = + json match { + case JsString(s) => + OracleAttestmentV0TLV.fromHexT(s) match { + case Success(att) => JsSuccess(att) + case Failure(err) => + SerializerUtil.buildJsErrorMsg( + s"Unexpected Service Identifier: $err", + json) + } + case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray | + _: JsObject) => + SerializerUtil.buildJsErrorMsg("jsstring", err) + } + } + implicit val feeProportionalMillionthsReads: Reads[ FeeProportionalMillionths] = Reads { js => SerializerUtil.processJsNumberBigInt(FeeProportionalMillionths.fromBigInt)( diff --git a/build.sbt b/build.sbt index 5b3aa8749a..f5d12b849f 100644 --- a/build.sbt +++ b/build.sbt @@ -198,6 +198,7 @@ lazy val `bitcoin-s` = project testkitCoreJS, testkit, zmq, + oracleExplorerClient, oracleServer, oracleServerTest, serverRoutes @@ -241,6 +242,7 @@ lazy val `bitcoin-s` = project appCommonsTest, testkit, zmq, + oracleExplorerClient, oracleServer, oracleServerTest, serverRoutes @@ -741,6 +743,15 @@ lazy val dlcOracleTest = project ) .dependsOn(coreJVM % testAndCompile, dlcOracle, testkit) +lazy val oracleExplorerClient = project + .in(file("oracle-explorer-client")) + .settings(CommonSettings.settings: _*) + .settings( + name := "bitcoin-s-oracle-explorer-client", + libraryDependencies ++= Deps.oracleExplorerClient + ) + .dependsOn(coreJVM, appCommons, testkit % "test->test") + /** Given a database name, returns the appropriate * Flyway settings we apply to a project (chain, node, wallet) */ diff --git a/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/client/SbExplorerClient.scala b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/client/SbExplorerClient.scala new file mode 100644 index 0000000000..1dde163285 --- /dev/null +++ b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/client/SbExplorerClient.scala @@ -0,0 +1,123 @@ +package org.bitcoins.explorer.client + +import akka.actor.ActorSystem +import akka.http.scaladsl.model.{ + ContentTypes, + HttpEntity, + HttpMethods, + HttpRequest, + Uri +} +import akka.http.scaladsl.{Http, HttpExt} +import akka.util.ByteString +import org.bitcoins.crypto.Sha256Digest +import org.bitcoins.explorer.env.ExplorerEnv +import org.bitcoins.explorer.model.{ + CreateAnnouncementExplorer, + CreateAttestations, + SbAnnouncementEvent +} +import org.bitcoins.explorer.picklers.ExplorerPicklers +import play.api.libs.json.{JsError, JsSuccess, JsValue, Json} + +import scala.concurrent.Future + +/** A class that implements the Suredbits oracle explorer API */ +case class SbExplorerClient(env: ExplorerEnv)(implicit system: ActorSystem) { + import ExplorerPicklers._ + import system.dispatcher + private val httpClient: HttpExt = Http(system) + + /** Lists all events on oracle explorer + * @see https://gist.github.com/Christewart/a9e55d9ba582ac9a5ceffa96db9d7e1f#list-all-events + * @return + */ + def listEvents(): Future[Vector[SbAnnouncementEvent]] = { + val base = env.baseUri + val uri = Uri(base + "events") + val httpReq = HttpRequest(uri = uri) + val responseF = sendRequest(httpReq) + responseF.flatMap { response => + val result = response.validate[Vector[SbAnnouncementEvent]] + result match { + case success: JsSuccess[Vector[SbAnnouncementEvent]] => + Future.successful(success.value) + case err: JsError => + Future.failed( + new RuntimeException( + s"Failed to parse response for listevents, err=$err")) + } + } + } + + /** Gets an announcement from the oracle explorer + * @see https://gist.github.com/Christewart/a9e55d9ba582ac9a5ceffa96db9d7e1f#get-event + */ + def getEvent(announcementHash: Sha256Digest): Future[SbAnnouncementEvent] = { + val base = env.baseUri + val uri = Uri(base + s"events/${announcementHash.hex}") + val httpReq = HttpRequest(uri = uri) + val responseF = sendRequest(httpReq) + responseF.flatMap { response => + val result = response.validate[SbAnnouncementEvent] + result match { + case success: JsSuccess[SbAnnouncementEvent] => + Future.successful(success.value) + case err: JsError => + Future.failed( + new RuntimeException( + s"Failed to parse response for listevents, err=$err")) + } + } + } + + /** Creates an announcement on the oracle explorer + * @see https://gist.github.com/Christewart/a9e55d9ba582ac9a5ceffa96db9d7e1f#create-an-event + */ + def createAnnouncement( + oracleEventExplorer: CreateAnnouncementExplorer): Future[Unit] = { + val base = env.baseUri + val uri = Uri(base + s"events") + val string = oracleEventExplorer.toString + val httpReq = + HttpRequest( + uri = uri, + method = HttpMethods.POST, + entity = + HttpEntity(ContentTypes.`application/x-www-form-urlencoded`, string)) + val responseF = sendRequest(httpReq) + responseF.map(_ => ()) + } + + /** Creates an attestation for an announcement on the oracle explorer + * @see https://gist.github.com/Christewart/a9e55d9ba582ac9a5ceffa96db9d7e1f#create-an-events-attestation + */ + def createAttestations(attestations: CreateAttestations): Future[Unit] = { + val base = env.baseUri + val uri = Uri( + base + s"events/${attestations.announcementHash.hex}/attestations") + val string = attestations.toString + val httpReq = + HttpRequest( + uri = uri, + method = HttpMethods.POST, + entity = + HttpEntity(ContentTypes.`application/x-www-form-urlencoded`, string)) + val responseF = sendRequest(httpReq) + responseF.map(_ => ()) + } + + private def sendRequest(httpReq: HttpRequest): Future[JsValue] = { + + val responsePayloadF: Future[String] = { + httpClient + .singleRequest(httpReq) + .flatMap(response => + response.entity.dataBytes + .runFold(ByteString.empty)(_ ++ _) + .map(payload => payload.decodeString(ByteString.UTF_8))) + } + + responsePayloadF.map(Json.parse) + } +} diff --git a/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/env/ExplorerEnv.scala b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/env/ExplorerEnv.scala new file mode 100644 index 0000000000..c26e392571 --- /dev/null +++ b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/env/ExplorerEnv.scala @@ -0,0 +1,34 @@ +package org.bitcoins.explorer.env + +import org.bitcoins.crypto.StringFactory + +sealed trait ExplorerEnv { + def baseUri: String +} + +object ExplorerEnv extends StringFactory[ExplorerEnv] { + + case object Production extends ExplorerEnv { + override val baseUri: String = "https://oracle.suredbits.com/v1/" + } + + case object Test extends ExplorerEnv { + override val baseUri: String = "https://test.oracle.suredbits.com/v1/" + } + + /** For local testing purposes */ + case object Local extends ExplorerEnv { + override val baseUri: String = "http://localhost:9000/v1/" + } + + val all: Vector[ExplorerEnv] = Vector(Production, Test, Local) + + override def fromString(string: String): ExplorerEnv = { + val explorerEnvOpt = all.find(_.toString.toLowerCase == string) + explorerEnvOpt match { + case Some(env) => env + case None => + sys.error(s"Failed to parse explorer env from str=$string") + } + } +} diff --git a/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/CreateAnnouncementExplorer.scala b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/CreateAnnouncementExplorer.scala new file mode 100644 index 0000000000..eab775f624 --- /dev/null +++ b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/CreateAnnouncementExplorer.scala @@ -0,0 +1,21 @@ +package org.bitcoins.explorer.model + +import org.bitcoins.core.protocol.tlv.OracleAnnouncementV0TLV + +case class CreateAnnouncementExplorer( + oracleAnnouncementV0: OracleAnnouncementV0TLV, + oracleName: String, + description: String, + eventURI: Option[String]) { + + override def toString: String = { + val base = + s"oracleAnnouncementV0=${oracleAnnouncementV0.hex}&description=$description&oracleName=$oracleName" + eventURI match { + case None => base + case Some(uri) => + val uriString = s"&uri=$uri" + base + uriString + } + } +} diff --git a/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/CreateAttestations.scala b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/CreateAttestations.scala new file mode 100644 index 0000000000..32fb5e05da --- /dev/null +++ b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/CreateAttestations.scala @@ -0,0 +1,13 @@ +package org.bitcoins.explorer.model + +import org.bitcoins.core.protocol.tlv.OracleAttestmentV0TLV +import org.bitcoins.crypto.Sha256Digest + +case class CreateAttestations( + announcementHash: Sha256Digest, + attestment: OracleAttestmentV0TLV) { + + override def toString: String = { + s"attestations=${attestment.hex}" + } +} diff --git a/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/SbAnnouncementEvent.scala b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/SbAnnouncementEvent.scala new file mode 100644 index 0000000000..bb655c7260 --- /dev/null +++ b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/model/SbAnnouncementEvent.scala @@ -0,0 +1,16 @@ +package org.bitcoins.explorer.model + +import org.bitcoins.core.protocol.tlv.{ + OracleAnnouncementV0TLV, + OracleAttestmentV0TLV +} +import org.bitcoins.crypto.Sha256Digest + +case class SbAnnouncementEvent( + id: Sha256Digest, + oracleName: String, + description: String, + uri: Option[String], + announcement: OracleAnnouncementV0TLV, + attestations: Option[OracleAttestmentV0TLV], + outcome: Option[String]) diff --git a/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/picklers/ExplorerPicklers.scala b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/picklers/ExplorerPicklers.scala new file mode 100644 index 0000000000..20d76a5705 --- /dev/null +++ b/oracle-explorer-client/src/main/scala/org/bitcoins/explorer/picklers/ExplorerPicklers.scala @@ -0,0 +1,10 @@ +package org.bitcoins.explorer.picklers + +import org.bitcoins.commons.serializers.JsonReaders +import org.bitcoins.explorer.model.SbAnnouncementEvent +import play.api.libs.json.Json + +object ExplorerPicklers { + import JsonReaders._ + implicit val explorerEventRW = Json.reads[SbAnnouncementEvent] +} diff --git a/oracle-explorer-client/src/test/scala/org/bitcoins/explorer/client/SbExplorerClientTest.scala b/oracle-explorer-client/src/test/scala/org/bitcoins/explorer/client/SbExplorerClientTest.scala new file mode 100644 index 0000000000..177f4a82f3 --- /dev/null +++ b/oracle-explorer-client/src/test/scala/org/bitcoins/explorer/client/SbExplorerClientTest.scala @@ -0,0 +1,101 @@ +package org.bitcoins.explorer.client + +import org.bitcoins.core.protocol.tlv.{ + OracleAnnouncementV0TLV, + OracleAttestmentV0TLV +} +import org.bitcoins.crypto.Sha256Digest +import org.bitcoins.explorer.env.ExplorerEnv +import org.bitcoins.explorer.model.{ + CreateAnnouncementExplorer, + CreateAttestations, + SbAnnouncementEvent +} +import org.bitcoins.testkit.util.BitcoinSAsyncTest + +import scala.concurrent.Future + +class SbExplorerClientTest extends BitcoinSAsyncTest { + + behavior of "SbExplorerClient" + + val explorerClient = SbExplorerClient(ExplorerEnv.Test) + + //https://test.oracle.suredbits.com/event/57505dcdfe8746d9adf3454df538244a425f302c07642d9dc4a4f635fbf08d30 + private val announcementHex: String = + "fdd824b33cbc4081b947ea9d05e616b010b563bfdbc42a2d20effa6f169f8e4be732b10d5461fa84b5739876a0c8a7bdb717040b8ee5907fe7e60694199ba948ecd505b01d5dcdba2e64cb116cc0c375a0856298f0058b778f46bfe625ac6576204889e4fdd8224f0001efdf735567ae0a00a515e313d20029de5d7525da7b8367bc843d28b672d4db4d605bd280fdd80609000203594553024e4f1b323032312d30332d32342d73756e6e792d696e2d6368696361676f" + + private val announcement: OracleAnnouncementV0TLV = + OracleAnnouncementV0TLV.fromHex(announcementHex) + + it must "list events" in { + val eventsF: Future[Vector[SbAnnouncementEvent]] = + explorerClient.listEvents() + for { + events <- eventsF + } yield { + assert(events.nonEmpty) + } + } + + it must "get an event" in { + val hash = announcement.sha256 + val eventsF = explorerClient.getEvent(hash) + for { + event <- eventsF + } yield { + assert(event.announcement.sha256 == hash) + } + } + + it must "return failure from get an event if the event DNE" in { + val hash = Sha256Digest.empty + recoverToSucceededIf[RuntimeException] { + explorerClient.getEvent(hash) + } + } + + it must "create an event on the oracle explorer and then get that event" ignore { + + val oracleName = "Chris_Stewart_5" + val description = "2021-03-24-sunny-in-chicago" + val uriOpt = Some("https://twitter.com/Chris_Stewart_5") + + val event = + CreateAnnouncementExplorer(announcement, oracleName, description, uriOpt) + + val createdF = explorerClient.createAnnouncement(event) + for { + _ <- createdF + event <- explorerClient.getEvent(event.oracleAnnouncementV0.sha256) + } yield { + assert(event.announcement == announcement) + assert(event.attestations.isEmpty) + assert(event.uri == uriOpt) + assert(event.oracleName == oracleName) + assert(event.description == description) + } + } + + it must "post attestations for an event to the oracle explorer" ignore { + //the announcement is posted in the test case above + //which means the test case above must be run before this test case + val attestationsHex = + "fdd868821b323032312d30332d32342d73756e6e792d696e2d6368696361676f1d5dcdba2e64cb116cc0c375a0856298f0058b778f46bfe625ac6576204889e40001efdf735567ae0a00a515e313d20029de5d7525da7b8367bc843d28b672d4db4db5de4dbff689f3b742be634a9c92c615dbcf2eadbdd470f514b1ac250a30db6d03594553" + + val attestations = OracleAttestmentV0TLV.fromHex(attestationsHex) + + val announcementHash = announcement.sha256 + val create = CreateAttestations(announcementHash, attestations) + val createdF = explorerClient.createAttestations(create) + + for { + _ <- createdF + //now we must have the attesations + event <- explorerClient.getEvent(announcementHash) + } yield { + assert(event.attestations.isDefined) + assert(event.attestations.get == attestations) + } + } +} diff --git a/oracle-explorer-client/src/test/scala/org/bitcoins/explorer/env/ExplorerEnvTest.scala b/oracle-explorer-client/src/test/scala/org/bitcoins/explorer/env/ExplorerEnvTest.scala new file mode 100644 index 0000000000..29738408c8 --- /dev/null +++ b/oracle-explorer-client/src/test/scala/org/bitcoins/explorer/env/ExplorerEnvTest.scala @@ -0,0 +1,14 @@ +package org.bitcoins.explorer.env + +import org.bitcoins.testkitcore.util.BitcoinSUnitTest + +class ExplorerEnvTest extends BitcoinSUnitTest { + + behavior of "ExplorerEnv" + + it must "have all base uris envs end with a '/'" in { + ExplorerEnv.all.foreach { e => + assert(e.baseUri.last == '/') + } + } +} diff --git a/oracle-explorer-client/src/test/scala/org/bitcoins/explorer/model/SbOracleEventExplorerTest.scala b/oracle-explorer-client/src/test/scala/org/bitcoins/explorer/model/SbOracleEventExplorerTest.scala new file mode 100644 index 0000000000..6f7fcedf87 --- /dev/null +++ b/oracle-explorer-client/src/test/scala/org/bitcoins/explorer/model/SbOracleEventExplorerTest.scala @@ -0,0 +1,29 @@ +package org.bitcoins.explorer.model + +import org.bitcoins.core.protocol.tlv.OracleAnnouncementV0TLV +import org.bitcoins.testkitcore.util.BitcoinSUnitTest + +class SbOracleEventExplorerTest extends BitcoinSUnitTest { + + behavior of "SbOracleEvent" + + it must "encode the event to POST for a form" in { + + val announcementHex = + "fdd824b33cbc4081b947ea9d05e616b010b563bfdbc42a2d20effa6f169f8e4be732b10d5461fa84b5739876a0c8a7bdb717040b8ee5907fe7e60694199ba948ecd505b01d5dcdba2e64cb116cc0c375a0856298f0058b778f46bfe625ac6576204889e4fdd8224f0001efdf735567ae0a00a515e313d20029de5d7525da7b8367bc843d28b672d4db4d605bd280fdd80609000203594553024e4f1b323032312d30332d32342d73756e6e792d696e2d6368696361676f" + val announcement = OracleAnnouncementV0TLV.fromHex(announcementHex) + val oracleName = "Chris_Stewart_5" + val description = "2021-03-24-sunny-in-chicago" + val uriOpt = Some("https://twitter.com/Chris_Stewart_5") + + val event = + CreateAnnouncementExplorer(announcement, oracleName, description, uriOpt) + + val expected = s"oracleAnnouncementV0=${announcementHex}&" + + s"description=$description&" + + s"oracleName=${oracleName}&" + + s"uri=${uriOpt.get}" + + assert(event.toString == expected) + } +} diff --git a/project/Deps.scala b/project/Deps.scala index 82bdd7c710..d6a86c4c43 100644 --- a/project/Deps.scala +++ b/project/Deps.scala @@ -538,4 +538,11 @@ object Deps { Compile.slf4j, Compile.grizzledSlf4j ) + + val oracleExplorerClient = Vector( + Compile.akkaActor, + Compile.akkaHttp, + Compile.akkaStream, + Compile.playJson + ) }