module Cardano.Wasm.Api.GRPC where

import Cardano.Wasm.Api.Tx qualified as Wasm
import Cardano.Wasm.ExceptionHandling (rightOrError, toMonadFail)

import Data.ByteString.Base16 qualified as Base16
import Data.ByteString.Base64 qualified as Base64
import Data.ByteString.Char8 qualified as BS

-- | Internal data for the GrpcConnection virtual object. Currently, it is just a wrapper around the grpcClient,
-- which is some object that allows us to interact with the Cardano Node via gRPC or GRPC-web.
newtype GrpcObject grpcClient
  = GrpcObject grpcClient

-- | Create a new unsigned transaction object for making a Conway era transaction.
newGrpcConnectionImpl :: (String -> IO grpcClient) -> String -> IO (GrpcObject grpcClient)
newGrpcConnectionImpl :: forall grpcClient.
(String -> IO grpcClient) -> String -> IO (GrpcObject grpcClient)
newGrpcConnectionImpl String -> IO grpcClient
createClientFunc String
host = grpcClient -> GrpcObject grpcClient
forall grpcClient. grpcClient -> GrpcObject grpcClient
GrpcObject (grpcClient -> GrpcObject grpcClient)
-> IO grpcClient -> IO (GrpcObject grpcClient)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO grpcClient
createClientFunc String
host

-- | Get the era from the Cardano Node using gRPC or GRPC-web.
getEraImpl :: (grpcClient -> IO Int) -> GrpcObject grpcClient -> IO Int
getEraImpl :: forall grpcClient.
(grpcClient -> IO Int) -> GrpcObject grpcClient -> IO Int
getEraImpl grpcClient -> IO Int
getEraFunc (GrpcObject grpcClient
client) = grpcClient -> IO Int
getEraFunc grpcClient
client

-- | Get the protocol parameters from the Cardano Node using gRPC or GRPC-web.
getProtocolParamsImpl
  :: (grpcClient -> IO Wasm.ProtocolParamsJSON)
  -> GrpcObject grpcClient
  -> IO Wasm.ProtocolParamsJSON
getProtocolParamsImpl :: forall grpcClient.
(grpcClient -> IO ProtocolParamsJSON)
-> GrpcObject grpcClient -> IO ProtocolParamsJSON
getProtocolParamsImpl grpcClient -> IO ProtocolParamsJSON
getProtocolParamsFunc (GrpcObject grpcClient
client) = grpcClient -> IO ProtocolParamsJSON
getProtocolParamsFunc grpcClient
client

-- | Get all UTXOs from the node using a gRPC or GRPC-web client.
getAllUtxosImpl
  :: (grpcClient -> IO utxos)
  -> GrpcObject grpcClient
  -> IO utxos
getAllUtxosImpl :: forall grpcClient utxos.
(grpcClient -> IO utxos) -> GrpcObject grpcClient -> IO utxos
getAllUtxosImpl grpcClient -> IO utxos
getUtxosFunc (GrpcObject grpcClient
client) = grpcClient -> IO utxos
getUtxosFunc grpcClient
client

-- | Get UTXOs for a given address using a gRPC or GRPC-web client.
getUtxosForAddressImpl
  :: (grpcClient -> String -> IO utxos)
  -> GrpcObject grpcClient
  -> String
  -> IO utxos
getUtxosForAddressImpl :: forall grpcClient utxos.
(grpcClient -> String -> IO utxos)
-> GrpcObject grpcClient -> String -> IO utxos
getUtxosForAddressImpl grpcClient -> String -> IO utxos
getUtxosForAddressFunc (GrpcObject grpcClient
client) = grpcClient -> String -> IO utxos
getUtxosForAddressFunc grpcClient
client

-- | Submit a transaction to the Cardano Node using gRPC or GRPC-web.
submitTxImpl
  :: (grpcClient -> String -> IO (Either String String))
  -> GrpcObject grpcClient
  -> String
  -> IO String
submitTxImpl :: forall grpcClient.
(grpcClient -> String -> IO (Either String String))
-> GrpcObject grpcClient -> String -> IO String
submitTxImpl grpcClient -> String -> IO (Either String String)
submitTxFunc (GrpcObject grpcClient
client) String
tx =
  Either SomeException String -> IO String
forall e (m :: * -> *) a.
(Exception e, MonadFail m) =>
Either e a -> m a
toMonadFail (Either SomeException String -> IO String)
-> (Either String String -> Either SomeException String)
-> Either String String
-> IO String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either String String -> Either SomeException String
forall (m :: * -> *) e a.
(HasCallStack, MonadThrow m, Show e) =>
Either e a -> m a
rightOrError (Either String String -> Either SomeException String)
-> (Either String String -> Either String String)
-> Either String String
-> Either SomeException String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Either String String
base64ToBase16 (String -> Either String String)
-> Either String String -> Either String String
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) (Either String String -> IO String)
-> IO (Either String String) -> IO String
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< grpcClient -> String -> IO (Either String String)
submitTxFunc grpcClient
client String
tx
 where
  -- We reencode as Base16 because it is a more common format for txIds
  base64ToBase16 :: String -> Either String String
  base64ToBase16 :: String -> Either String String
base64ToBase16 String
encoded = do
    decoded <- ByteString -> Either String ByteString
Base64.decode (ByteString -> Either String ByteString)
-> ByteString -> Either String ByteString
forall a b. (a -> b) -> a -> b
$ String -> ByteString
BS.pack String
encoded
    return $ BS.unpack $ Base16.encode decoded