Skip to content

Commit

Permalink
TSDK-754 Start session pegout (#4)
Browse files Browse the repository at this point in the history
* TSDK-754 Simplify pegin session

* TSDK-754 Fix integration test

* TSDK-754 First basic implementation

* TSDK-754 Fix tests

* TSDK-754 Complete tests

* TSDK-754 Remove TODO
  • Loading branch information
mundacho committed Mar 8, 2024
1 parent 05818d7 commit b35e5dd
Show file tree
Hide file tree
Showing 17 changed files with 714 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
package co.topl.bridge

import munit.CatsEffectSuite
import fs2.io.process
import cats.effect.IO
import org.http4s.ember.client._
import co.topl.shared.BridgeContants
import co.topl.shared.ConfirmDepositRequest
import co.topl.shared.ConfirmDepositResponse
import co.topl.shared.ConfirmRedemptionRequest
import co.topl.shared.ConfirmRedemptionResponse
import co.topl.shared.StartPeginSessionRequest
import co.topl.shared.StartPeginSessionResponse
import co.topl.shared.SyncWalletRequest
import fs2.io.process
import munit.CatsEffectSuite
import org.checkerframework.checker.units.qual.g
import org.http4s.EntityDecoder
import org.http4s.Method
import co.topl.shared.StartSessionRequest
import org.http4s.Request
import org.http4s.Uri
import org.http4s.EntityDecoder
import co.topl.shared.StartSessionResponse
import org.http4s.ember.client._
import org.http4s.headers.`Content-Type`
import org.checkerframework.checker.units.qual.g
import co.topl.shared.ConfirmRedemptionRequest
import co.topl.shared.ConfirmRedemptionResponse
import co.topl.shared.SyncWalletRequest
import co.topl.shared.ConfirmDepositResponse
import co.topl.shared.ConfirmDepositRequest

import scala.concurrent.duration._

class BridgeIntegrationSpec extends CatsEffectSuite {

val DOCKER_CMD = "docker"


override val munitTimeout = Duration(180, "s")

val createWallet = Seq(
Expand Down Expand Up @@ -142,13 +143,13 @@ class BridgeIntegrationSpec extends CatsEffectSuite {
import org.http4s.circe._
import org.http4s.dsl.io._
implicit val startSessionRequestDecoder
: EntityEncoder[IO, StartSessionRequest] =
jsonEncoderOf[IO, StartSessionRequest]
: EntityEncoder[IO, StartPeginSessionRequest] =
jsonEncoderOf[IO, StartPeginSessionRequest]
implicit val syncWalletRequestDecoder
: EntityEncoder[IO, SyncWalletRequest] =
jsonEncoderOf[IO, SyncWalletRequest]
implicit val startSessionResponse: EntityDecoder[IO, StartSessionResponse] =
jsonOf[IO, StartSessionResponse]
implicit val startSessionResponse: EntityDecoder[IO, StartPeginSessionResponse] =
jsonOf[IO, StartPeginSessionResponse]
implicit val confirmRedemptionRequestDecoder
: EntityEncoder[IO, ConfirmRedemptionRequest] =
jsonEncoderOf[IO, ConfirmRedemptionRequest]
Expand Down Expand Up @@ -190,17 +191,19 @@ class BridgeIntegrationSpec extends CatsEffectSuite {
.default[IO]
.build
.use({ client =>
client.expect[StartSessionResponse](
client.expect[StartPeginSessionResponse](
Request[IO](
method = Method.POST,
Uri
.fromString("http://127.0.0.1:3000/start-session")
.fromString(
"http://127.0.0.1:3000/" + BridgeContants.START_PEGIN_SESSION_PATH
)
.toOption
.get
).withContentType(
`Content-Type`.apply(MediaType.application.json)
).withEntity(
StartSessionRequest(
StartPeginSessionRequest(
pkey =
"0295bb5a3b80eeccb1e38ab2cbac2545e9af6c7012cdc8d53bd276754c54fc2e4a",
sha256 =
Expand Down Expand Up @@ -318,7 +321,9 @@ class BridgeIntegrationSpec extends CatsEffectSuite {
_ <- IO.println("startSessionResponse: " + confirmRedemptionResponse)
_ <- IO.sleep(10.seconds)
_ <- getCurrentUtxos.use(_.exitValue).iterateUntil(_ == 0)
_ <- assertIOBoolean(getCurrentUtxos.use(getText).map(_.contains("Asset")))
_ <- assertIOBoolean(
getCurrentUtxos.use(getText).map(_.contains("Asset"))
)
} yield (),
()
)
Expand Down
2 changes: 1 addition & 1 deletion project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ object Dependencies {

lazy val toplOrg = "co.topl"

lazy val bramblVersion = "2.0.0-beta1"
lazy val bramblVersion = "2.0.0-beta3"

val bramblSdk = toplOrg %% "brambl-sdk" % bramblVersion

Expand Down
7 changes: 7 additions & 0 deletions shared/src/main/scala/co/topl/shared/BridgeContants.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package co.topl.shared

object BridgeContants {
val START_PEGIN_SESSION_PATH = "start-session-pegin"

val START_PEGOUT_SESSION_PATH = "start-session-pegout"
}
23 changes: 21 additions & 2 deletions shared/src/main/scala/co/topl/shared/InputOutput.scala
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
package co.topl.shared

case class StartSessionRequest(
/** This class is used to create a new session for a peg-in.
*
* @param pkey
* The public key of the user.
* @param sha256
* The hash of the secret that is used to redeem the peg-in.
*/
case class StartPeginSessionRequest(
pkey: String,
sha256: String
)

case class StartPegoutSessionRequest(
userBaseKey: String,
currentHeight: Int,
sha256: String
)

case class SyncWalletRequest(
secret: String
)

case class StartSessionResponse(
case class StartPeginSessionResponse(
sessionID: String,
script: String,
escrowAddress: String,
descriptor: String
)

case class StartPegoutSessionResponse(
sessionID: String,
escrowAddress: String
)

case class ConfirmRedemptionRequest(
sessionID: String,
inputTxId: String,
Expand Down Expand Up @@ -48,3 +66,4 @@ case class InvalidKey(error: String) extends BridgeError
case class InvalidHash(error: String) extends BridgeError
case class InvalidBase58(error: String) extends BridgeError
case class InvalidInput(error: String) extends BridgeError
case class WalletSetupError(error: String) extends BridgeError
72 changes: 51 additions & 21 deletions topl-btc-bridge/src/main/scala/co/topl/bridge/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,46 @@ import cats.effect.IO
import cats.effect.IOApp
import cats.effect.kernel.Resource
import co.topl.brambl.builders.TransactionBuilderApi
import co.topl.brambl.codecs.AddressCodecs
import co.topl.brambl.constants.NetworkConstants
import co.topl.brambl.dataApi.GenusQueryAlgebra
import co.topl.brambl.dataApi.RpcChannelResource
import co.topl.brambl.dataApi.WalletStateAlgebra
import co.topl.brambl.models.Indices
import co.topl.brambl.models.LockAddress
import co.topl.brambl.models.LockId
import co.topl.brambl.servicekit.FellowshipStorageApi
import co.topl.brambl.servicekit.TemplateStorageApi
import co.topl.brambl.servicekit.WalletKeyApi
import co.topl.brambl.servicekit.WalletStateApi
import co.topl.brambl.servicekit.WalletStateResource
import co.topl.brambl.utils.Encoding
import co.topl.brambl.wallet.WalletApi
import co.topl.bridge.BridgeParamsDescriptor
import co.topl.bridge.ServerConfig
import co.topl.bridge.ToplBTCBridgeParamConfig
import co.topl.bridge.controllers.ConfirmDepositController
import co.topl.bridge.controllers.ConfirmRedemptionController
import co.topl.bridge.controllers.StartSessionController
import co.topl.bridge.controllers.ConfirmDepositController
import co.topl.bridge.managers.BTCWalletAlgebra
import co.topl.bridge.managers.BTCWalletImpl
import co.topl.bridge.managers.SessionManagerAlgebra
import co.topl.bridge.managers.SessionManagerImpl
import co.topl.bridge.managers.SessionManagerAlgebra
import co.topl.bridge.managers.ToplWalletAlgebra
import co.topl.bridge.managers.ToplWalletImpl
import co.topl.bridge.managers.TransactionAlgebra
import co.topl.bridge.managers.WalletManagementUtils
import co.topl.genus.services.Txo
import co.topl.genus.services.TxoState
import co.topl.shared.BitcoinNetworkIdentifiers
import co.topl.shared.BridgeContants
import co.topl.shared.BridgeError
import co.topl.shared.ConfirmDepositRequest
import co.topl.shared.ConfirmRedemptionRequest
import co.topl.shared.SessionNotFoundError
import co.topl.shared.StartSessionRequest
import co.topl.shared.StartPeginSessionRequest
import co.topl.shared.SyncWalletRequest
import co.topl.shared.ToplNetworkIdentifiers
import co.topl.shared.utils.KeyGenerationUtils
import io.circe.generic.auto._
import io.circe.syntax._
Expand All @@ -44,20 +57,11 @@ import org.http4s.ember.server.EmberServerBuilder
import org.http4s.server.Router
import org.http4s.server.staticcontent.resourceServiceBuilder
import quivr.models.KeyPair
import quivr.models.VerificationKey
import scopt.OParser

import java.util.concurrent.ConcurrentHashMap
import co.topl.shared.ToplNetworkIdentifiers
import co.topl.brambl.dataApi.WalletStateAlgebra
import co.topl.brambl.codecs.AddressCodecs
import co.topl.genus.services.TxoState
import co.topl.genus.services.Txo
import co.topl.brambl.models.Indices
import co.topl.brambl.models.LockAddress
import co.topl.brambl.utils.Encoding
import co.topl.brambl.models.LockId
import quivr.models.VerificationKey
import co.topl.shared.SyncWalletRequest
import co.topl.shared.StartPegoutSessionRequest

object Main
extends IOApp
Expand Down Expand Up @@ -101,15 +105,14 @@ object Main
e.printStackTrace()
BadRequest("Error syncing wallet")
}

case req @ POST -> Root / "start-session" =>
case req @ POST -> Root / BridgeContants.START_PEGIN_SESSION_PATH =>
import StartSessionController._
implicit val startSessionRequestDecoder
: EntityDecoder[IO, StartSessionRequest] =
jsonOf[IO, StartSessionRequest]
: EntityDecoder[IO, StartPeginSessionRequest] =
jsonOf[IO, StartPeginSessionRequest]
for {
x <- req.as[StartSessionRequest]
res <- startSession(
x <- req.as[StartPeginSessionRequest]
res <- startPeginSession(
x,
pegInWalletManager,
sessionManager,
Expand All @@ -121,6 +124,29 @@ object Main
case Right(value) => Ok(value.asJson)
}
} yield resp
case req @ POST -> Root / BridgeContants.START_PEGOUT_SESSION_PATH =>
import StartSessionController._
implicit val startSessionRequestDecoder
: EntityDecoder[IO, StartPegoutSessionRequest] =
jsonOf[IO, StartPegoutSessionRequest]
(for {
x <- req.as[StartPegoutSessionRequest]
res <- startPegoutSession(
x,
toplNetwork,
toplKeypair,
toplWalletAlgebra,
sessionManager,
1000
)
resp <- res match {
case Left(e: BridgeError) => BadRequest(e.asJson)
case Right(value) => Ok(value.asJson)
}
} yield resp).handleErrorWith { case e =>
e.printStackTrace()
BadRequest("Error starting pegout session")
}
case req @ POST -> Root / "confirm-deposit" =>
implicit val confirmDepositRequestDecoder
: EntityDecoder[IO, ConfirmDepositRequest] =
Expand Down Expand Up @@ -246,7 +272,9 @@ object Main
), // lockPredicate
lockAddress.toBase58(), // lockAddress
Some("ExtendedEd25519"),
Some(Encoding.encodeToBase58(vksDerived.head.toByteArray)), // TODO: we assume here only one party, fix this later
Some(
Encoding.encodeToBase58(vksDerived.head.toByteArray)
), // TODO: we assume here only one party, fix this later
indices
)
} yield txos
Expand Down Expand Up @@ -311,6 +339,8 @@ object Main
toplWalletImpl = ToplWalletImpl.make[IO](
IO.asyncForIO,
walletApi,
FellowshipStorageApi.make(walletResource(params.toplWalletDb)),
TemplateStorageApi.make(walletResource(params.toplWalletDb)),
walletStateAlgebra,
transactionBuilderApi,
genusQueryAlgebra
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import scodec.bits.ByteVector
import co.topl.shared.SessionNotFoundError
import cats.effect.kernel.Sync
import co.topl.shared.BridgeError
import co.topl.bridge.managers.PeginSessionInfo

object ConfirmRedemptionController {

Expand All @@ -28,13 +29,24 @@ object ConfirmRedemptionController {
): F[Either[BridgeError, ConfirmRedemptionResponse]] = {
import cats.implicits._
(for {
sessionInfo <- sessionManager
genericSessionInfo <- sessionManager
.getSession(req.sessionID)
.handleError(_ =>
throw SessionNotFoundError(
s"Session with id ${req.sessionID} not found"
)
)
sessionInfo = genericSessionInfo match {
case PeginSessionInfo(currentWalletIdx, scriptAsm) =>
PeginSessionInfo(
currentWalletIdx,
scriptAsm
)
case _ =>
throw new RuntimeException(
"Session info is not a pegin session info"
)
}
nextPubKey <- walletManager.getCurrentPubKey()
tx = BitcoinUtils.createRedeemingTx(
req.inputTxId,
Expand Down

0 comments on commit b35e5dd

Please sign in to comment.