diff --git a/maestro-exe/Maestro/Run/Address.hs b/maestro-exe/Maestro/Run/Address.hs index 54d5fea..7322bc0 100644 --- a/maestro-exe/Maestro/Run/Address.hs +++ b/maestro-exe/Maestro/Run/Address.hs @@ -5,13 +5,13 @@ import Data.List (sort) import Maestro.Client.Env import qualified Maestro.Client.V0 as V0 import qualified Maestro.Client.V1 as V1 -import Maestro.Types.V1.Common (v1UtxoToV0) +import Maestro.Types.V1.Common (v1UtxoWithSlotToV0) runAddressAPI :: MaestroEnv 'V0 -> MaestroEnv 'V1 -> IO () runAddressAPI mEnvV0 mEnvV1 = do let addrs = undefined -- Mention list of addresses. utxos <- V0.allPages $ flip (V0.utxosAtMultiAddresses mEnvV0 Nothing Nothing) addrs let utxosSorted = sort utxos - utxos' <- fmap (fmap v1UtxoToV0) $ V1.allPages $ flip (V1.utxosAtMultiAddresses mEnvV1 Nothing Nothing) addrs + utxos' <- fmap (fmap v1UtxoWithSlotToV0) $ V1.allPages $ flip (V1.utxosAtMultiAddresses mEnvV1 Nothing Nothing) addrs let utxos'Sorted = sort utxos' when (utxosSorted == utxos'Sorted) $ putStrLn "Yes" diff --git a/maestro-sdk.cabal b/maestro-sdk.cabal index 23d4ba6..522432a 100644 --- a/maestro-sdk.cabal +++ b/maestro-sdk.cabal @@ -57,8 +57,12 @@ library Maestro.API.V0.TxManager Maestro.API.V1 - Maestro.API.V1.Address + Maestro.API.V1.Addresses + Maestro.API.V1.Datum Maestro.API.V1.General + Maestro.API.V1.Pools + Maestro.API.V1.Transactions + Maestro.API.V1.TxManager Maestro.Client.Env Maestro.Client.Error @@ -79,7 +83,12 @@ library Maestro.Client.V1 Maestro.Client.V1.Core Maestro.Client.V1.Core.Pagination - Maestro.Client.V1.Address + Maestro.Client.V1.Addresses + Maestro.Client.V1.Datum + Maestro.Client.V1.General + Maestro.Client.V1.Pools + Maestro.Client.V1.Transactions + Maestro.Client.V1.TxManager Maestro.Types.Common Maestro.Types.V0 @@ -91,10 +100,16 @@ library Maestro.Types.V0.Epochs Maestro.Types.V0.General Maestro.Types.V0.Pool + Maestro.Types.V0.Transactions Maestro.Types.V1 + Maestro.Types.V1.Addresses + Maestro.Types.V1.Datum Maestro.Types.V1.Common + Maestro.Types.V1.Common.Pagination Maestro.Types.V1.General + Maestro.Types.V1.Pools + Maestro.Types.V1.Transactions -- other-modules: -- other-extensions: diff --git a/src/Maestro/API/V0/Address.hs b/src/Maestro/API/V0/Address.hs index 2364288..f690007 100644 --- a/src/Maestro/API/V0/Address.hs +++ b/src/Maestro/API/V0/Address.hs @@ -1,6 +1,6 @@ module Maestro.API.V0.Address where -import Data.Text (Text) +import Data.Text (Text) import Maestro.Client.V0.Core.Pagination import Maestro.Types.V0 import Servant.API @@ -12,8 +12,8 @@ data AddressAPI route = AddressAPI _addressesUtxos :: route :- "utxos" - :> QueryParam "resolve_datums" Bool - :> QueryParam "with_cbor" Bool + :> QueryParam "resolve_datums" Bool + :> QueryParam "with_cbor" Bool :> Pagination :> ReqBody '[JSON] [Text] :> Post '[JSON] [Utxo] @@ -22,8 +22,8 @@ data AddressAPI route = AddressAPI :: route :- Capture "address" Text :> "utxos" - :> QueryParam "resolve_datums" Bool - :> QueryParam "with_cbor" Bool + :> QueryParam "resolve_datums" Bool + :> QueryParam "with_cbor" Bool :> Pagination :> Get '[JSON] [Utxo] diff --git a/src/Maestro/API/V1.hs b/src/Maestro/API/V1.hs index d30784f..d1f23d0 100644 --- a/src/Maestro/API/V1.hs +++ b/src/Maestro/API/V1.hs @@ -1,14 +1,22 @@ module Maestro.API.V1 where -import Data.Text (Text) -import Maestro.API.V1.Address +import Data.Text (Text) +import Maestro.API.V1.Addresses +import Maestro.API.V1.Datum import Maestro.API.V1.General +import Maestro.API.V1.Pools +import Maestro.API.V1.Transactions +import Maestro.API.V1.TxManager import Servant.API import Servant.API.Generic data MaestroApiV1 route = MaestroApiV1 - { _general :: route :- ToServantApi GeneralAPI - , _address :: route :- "addresses" :> ToServantApi AddressAPI + { _general :: route :- ToServantApi GeneralAPI + , _addresses :: route :- "addresses" :> ToServantApi AddressesAPI + , _datum :: route :- "datum" :> ToServantApi DatumAPI + , _pools :: route :- "pools" :> ToServantApi PoolsAPI + , _txManager :: route :- "txmanager" :> ToServantApi TxManagerAPI + , _transactions :: route :- ToServantApi TransactionsAPI } deriving Generic newtype MaestroApiV1Auth route = MaestroApiV1Auth diff --git a/src/Maestro/API/V1/Address.hs b/src/Maestro/API/V1/Address.hs deleted file mode 100644 index 0010530..0000000 --- a/src/Maestro/API/V1/Address.hs +++ /dev/null @@ -1,20 +0,0 @@ -module Maestro.API.V1.Address where - -import Data.Text (Text) -import Maestro.Client.V1.Core.Pagination -import Maestro.Types.V1 -import Servant.API -import Servant.API.Generic - -data AddressAPI route = AddressAPI - { - _addressesUtxos - :: route - :- "utxos" - :> QueryParam "resolve_datums" Bool - :> QueryParam "with_cbor" Bool - :> Pagination - :> ReqBody '[JSON] [Text] - :> Post '[JSON] Utxos - - } deriving (Generic) diff --git a/src/Maestro/API/V1/Addresses.hs b/src/Maestro/API/V1/Addresses.hs new file mode 100644 index 0000000..84071f4 --- /dev/null +++ b/src/Maestro/API/V1/Addresses.hs @@ -0,0 +1,32 @@ +module Maestro.API.V1.Addresses where + +import Maestro.Client.V1.Core.Pagination +import Maestro.Types.V1 +import Servant.API +import Servant.API.Generic + +data AddressesAPI route = AddressesAPI + { + _decodeAddress + :: route + :- Capture "address" (TaggedText AddressToDecode) + :> "decode" + :> Get '[JSON] AddressInfo + + , _addressesUtxos + :: route + :- "utxos" + :> QueryParam "resolve_datums" Bool + :> QueryParam "with_cbor" Bool + :> Pagination + :> ReqBody '[JSON] [Bech32StringOf Address] + :> Post '[JSON] PaginatedUtxoWithSlot + + -- , _addressUtxoRefs + -- :: route + -- :- Capture "address" Text + -- :> "utxo_refs" + -- :> Pagination + -- :> Get '[JSON] [UtxoRef] + + } deriving (Generic) diff --git a/src/Maestro/API/V1/Datum.hs b/src/Maestro/API/V1/Datum.hs new file mode 100644 index 0000000..62cb273 --- /dev/null +++ b/src/Maestro/API/V1/Datum.hs @@ -0,0 +1,14 @@ +module Maestro.API.V1.Datum where + +import Maestro.Types.V1 +import Servant.API +import Servant.API.Generic + +newtype DatumAPI route = + DatumAPI + { + _datumByHash + :: route + :- Capture "datum_hash" (HexStringOf DatumHash) + :> Get '[JSON] Datum + } deriving Generic diff --git a/src/Maestro/API/V1/Pools.hs b/src/Maestro/API/V1/Pools.hs new file mode 100644 index 0000000..21b1be4 --- /dev/null +++ b/src/Maestro/API/V1/Pools.hs @@ -0,0 +1,14 @@ +module Maestro.API.V1.Pools where + +import Maestro.Client.V1.Core.Pagination +import Maestro.Types.V1 +import Servant.API +import Servant.API.Generic + +data PoolsAPI route = PoolsAPI + { _listPools :: + route + :- Pagination + :> Get '[JSON] PaginatedPoolListInfo + } + deriving (Generic) diff --git a/src/Maestro/API/V1/Transactions.hs b/src/Maestro/API/V1/Transactions.hs new file mode 100644 index 0000000..72d382c --- /dev/null +++ b/src/Maestro/API/V1/Transactions.hs @@ -0,0 +1,19 @@ +module Maestro.API.V1.Transactions where + +import Maestro.Client.V1.Core.Pagination +import Maestro.Types.V1 +import Servant.API +import Servant.API.Generic + +newtype TransactionsAPI route = TransactionsAPI + { _txOutputs :: + route + :- "transactions" + :> "outputs" + :> QueryParam "resolve_datums" Bool + :> QueryParam "with_cbor" Bool + :> Pagination + :> ReqBody '[JSON] [OutputReference] + :> Post '[JSON] PaginatedUtxo + } + deriving (Generic) diff --git a/src/Maestro/API/V1/TxManager.hs b/src/Maestro/API/V1/TxManager.hs new file mode 100644 index 0000000..d388331 --- /dev/null +++ b/src/Maestro/API/V1/TxManager.hs @@ -0,0 +1,15 @@ +module Maestro.API.V1.TxManager where + +import qualified Data.ByteString as BS +import qualified Data.Text as T +import Maestro.Types.V1 +import Servant.API +import Servant.API.Generic + +newtype TxManagerAPI route = TxManagerAPI + { _monitoredTxSubmit :: + route + :- ReqBody' '[Required] '[CBORStream] BS.ByteString + :> PostAccepted '[JSON] T.Text + } + deriving (Generic) diff --git a/src/Maestro/Client/V1.hs b/src/Maestro/Client/V1.hs index 561d9ee..f86018f 100644 --- a/src/Maestro/Client/V1.hs +++ b/src/Maestro/Client/V1.hs @@ -2,11 +2,11 @@ module Maestro.Client.V1 ( module Maestro.Client.Env , module Maestro.Client.Error , module Maestro.Client.V1.Core - , module Maestro.Client.V1.Address + , module Maestro.Client.V1.Addresses ) where import Maestro.Client.Env import Maestro.Client.Error -import Maestro.Client.V1.Address +import Maestro.Client.V1.Addresses import Maestro.Client.V1.Core diff --git a/src/Maestro/Client/V1/Address.hs b/src/Maestro/Client/V1/Address.hs deleted file mode 100644 index c13f6b5..0000000 --- a/src/Maestro/Client/V1/Address.hs +++ /dev/null @@ -1,28 +0,0 @@ -module Maestro.Client.V1.Address where - -import Data.Text (Text) -import Maestro.API.V1 -import Maestro.API.V1.Address -import Maestro.Client.Env -import Maestro.Client.V1.Core -import Maestro.Types.V1 -import Servant.API.Generic -import Servant.Client - -addressClient :: MaestroEnv 'V1 -> AddressAPI (AsClientT IO) -addressClient = fromServant . _address . apiV1Client - --- | Returns list of utxos for multiple addresses -utxosAtMultiAddresses :: - -- | The Maestro Environment - MaestroEnv 'V1 -> - -- | Query param to include the corresponding datums for datum hashes - Maybe Bool -> - -- | Query Param to include the CBOR encodings of the transaction outputs in the response - Maybe Bool -> - -- | The pagination attributes - Cursor -> - -- | List of Address in bech32 format to fetch utxo from - [Text] -> - IO Utxos -utxosAtMultiAddresses = _addressesUtxos . addressClient diff --git a/src/Maestro/Client/V1/Addresses.hs b/src/Maestro/Client/V1/Addresses.hs new file mode 100644 index 0000000..f6fa1c9 --- /dev/null +++ b/src/Maestro/Client/V1/Addresses.hs @@ -0,0 +1,32 @@ +-- | Module to query for /"addresses"/ category of endpoints defined at [docs.gomaestro.org](https://docs.gomaestro.org/docs/category/addresses). + +module Maestro.Client.V1.Addresses ( + utxosAtMultiAddresses, + ) where + +import Maestro.API.V1 +import Maestro.API.V1.Addresses +import Maestro.Client.Env +import Maestro.Client.V1.Core +import Maestro.Types.Common (Address, Bech32StringOf) +import Maestro.Types.V1 (PaginatedUtxoWithSlot) +import Servant.API.Generic +import Servant.Client + +addressClient :: MaestroEnv 'V1 -> AddressesAPI (AsClientT IO) +addressClient = fromServant . _addresses . apiV1Client + +-- | Returns list of utxos for multiple addresses. +utxosAtMultiAddresses :: + -- | The Maestro Environment. + MaestroEnv 'V1 -> + -- | Query param to include the corresponding datums for datum hashes. + Maybe Bool -> + -- | Query Param to include the CBOR encodings of the transaction outputs in the response. + Maybe Bool -> + -- | The pagination attributes. + Cursor -> + -- | List of Address in bech32 format to fetch utxo from. + [Bech32StringOf Address] -> + IO PaginatedUtxoWithSlot +utxosAtMultiAddresses = _addressesUtxos . addressClient diff --git a/src/Maestro/Client/V1/Core/Pagination.hs b/src/Maestro/Client/V1/Core/Pagination.hs index 1e292c9..1558cb5 100644 --- a/src/Maestro/Client/V1/Core/Pagination.hs +++ b/src/Maestro/Client/V1/Core/Pagination.hs @@ -1,18 +1,18 @@ module Maestro.Client.V1.Core.Pagination where import Data.Default.Class -import Data.Kind (Type) -import Data.Maybe (isNothing) -import Data.Proxy (Proxy (..)) -import Data.Text (Text) -import Servant.API (QueryParam, (:>)) -import Servant.Client.Core (Client, HasClient, clientWithRoute, - hoistClientMonad) +import Data.Maybe (isNothing) +import Data.Proxy (Proxy (..)) +import Maestro.Types.V1.Common.Pagination +import Servant.API (QueryParam, (:>)) +import Servant.Client.Core (Client, HasClient, + clientWithRoute, + hoistClientMonad) -- | Pagination parameters. data Cursor = Cursor - { resultPerPage :: !Int -- ^ Total result to have per page. - , cursor :: !(Maybe Text) -- ^ Cursor. + { resultPerPage :: !Int -- ^ Total result to have per page. + , cursor :: !(Maybe NextCursor) -- ^ Cursor. } -- | Maximum number of result per page. @@ -22,12 +22,6 @@ maxResultsPerPage = 100 instance Default Cursor where def = Cursor maxResultsPerPage Nothing --- | Is the endpoint paged? -class (Monoid (CursorData a)) => HasCursor a where - type CursorData a :: Type - getNextCursor :: a -> Maybe Text - getCursorData :: a -> CursorData a - -- Utility for querying all results from a paged endpoint. allPages :: (Monad m, HasCursor a) => (Cursor -> m a) -> m (CursorData a) allPages act = fetch Nothing @@ -46,7 +40,7 @@ data Pagination type PaginationApi api = QueryParam "count" Int - :> QueryParam "cursor" Text + :> QueryParam "cursor" NextCursor :> api instance HasClient m api => HasClient m (Pagination :> api) where diff --git a/src/Maestro/Client/V1/Datum.hs b/src/Maestro/Client/V1/Datum.hs new file mode 100644 index 0000000..8c369be --- /dev/null +++ b/src/Maestro/Client/V1/Datum.hs @@ -0,0 +1,20 @@ +-- | Module to query for /"datum"/ category of endpoints defined at [docs.gomaestro.org](https://docs.gomaestro.org/docs/category/datum). + +module Maestro.Client.V1.Datum + ( getDatumByHash + ) where + +import Maestro.API.V1 (_datum) +import Maestro.API.V1.Datum +import Maestro.Client.Env +import Maestro.Client.V1.Core +import Maestro.Types.V1 +import Servant.API.Generic +import Servant.Client + +datumClient :: MaestroEnv 'V1 -> DatumAPI (AsClientT IO) +datumClient = fromServant . _datum . apiV1Client + +-- | Get information about the datum from it's hash. +getDatumByHash :: MaestroEnv 'V1 -> HexStringOf DatumHash -> IO Datum +getDatumByHash = _datumByHash . datumClient diff --git a/src/Maestro/Client/V1/General.hs b/src/Maestro/Client/V1/General.hs new file mode 100644 index 0000000..59a7579 --- /dev/null +++ b/src/Maestro/Client/V1/General.hs @@ -0,0 +1,35 @@ +-- | Module to query for /"general"/ category of endpoints defined at [docs.gomaestro.org](https://docs.gomaestro.org/docs/category/general). + +module Maestro.Client.V1.General + ( getChainTip + , getSystemStart + , getEraHistory + , getProtocolParameters + ) where + +import Maestro.API.V1 (_general) +import Maestro.API.V1.General +import Maestro.Client.Env +import Maestro.Client.V1.Core +import Maestro.Types.V1 +import Servant.API.Generic +import Servant.Client + +generalClient :: MaestroEnv 'V1 -> GeneralAPI (AsClientT IO) +generalClient = fromServant . _general . apiV1Client + +-- | Get details about the latest block of the network. +getChainTip :: MaestroEnv 'V1 -> IO ChainTip +getChainTip = _chainTip . generalClient + +-- | Get network start time since genesis. +getSystemStart :: MaestroEnv 'V1 -> IO SystemStart +getSystemStart = _systemStart . generalClient + +-- | Get network era history. +getEraHistory :: MaestroEnv 'V1 -> IO EraSummaries +getEraHistory = _eraHistory . generalClient + +-- | Get protocol parameters for the latest epoch. +getProtocolParameters :: MaestroEnv 'V1 -> IO ProtocolParameters +getProtocolParameters = _protocolParams . generalClient diff --git a/src/Maestro/Client/V1/Pools.hs b/src/Maestro/Client/V1/Pools.hs new file mode 100644 index 0000000..cad7af3 --- /dev/null +++ b/src/Maestro/Client/V1/Pools.hs @@ -0,0 +1,21 @@ +-- | Module to query for /"pools"/ category of endpoints defined at [docs.gomaestro.org](https://docs.gomaestro.org/docs/category/pools). + +module Maestro.Client.V1.Pools + ( listPools, + ) +where + +import Maestro.API.V1 +import Maestro.API.V1.Pools +import Maestro.Client.Env +import Maestro.Client.V1.Core +import Maestro.Types.V1 +import Servant.API.Generic +import Servant.Client + +poolsClient :: MaestroEnv 'V1 -> PoolsAPI (AsClientT IO) +poolsClient = fromServant . _pools . apiV1Client + +-- | Returns a list of currently registered stake pools +listPools :: MaestroEnv 'V1 -> Cursor -> IO PaginatedPoolListInfo +listPools = _listPools . poolsClient diff --git a/src/Maestro/Client/V1/Transactions.hs b/src/Maestro/Client/V1/Transactions.hs new file mode 100644 index 0000000..96f4e75 --- /dev/null +++ b/src/Maestro/Client/V1/Transactions.hs @@ -0,0 +1,31 @@ +-- | Module to query for /"transactions"/ category of endpoints defined at [docs.gomaestro.org](https://docs.gomaestro.org/docs/category/transactions). + +module Maestro.Client.V1.Transactions + ( outputsByReferences, + ) where + +import Maestro.API.V1 (_transactions) +import Maestro.API.V1.Transactions +import Maestro.Client.Env +import Maestro.Client.V1.Core +import Maestro.Types.V1 +import Servant.API.Generic +import Servant.Client + +txClient :: MaestroEnv 'V1 -> TransactionsAPI (AsClientT IO) +txClient = fromServant . _transactions . apiV1Client + +-- | Returns outputs for given output references. +outputsByReferences :: + -- | The Maestro Environment. + MaestroEnv 'V1 -> + -- | Try find and include the corresponding datums for datum hashes. + Maybe Bool -> + -- | Include the CBOR encodings of the transaction outputs in the response. + Maybe Bool -> + -- | The pagination attributes. + Cursor -> + -- | Output references. + [OutputReference] -> + IO PaginatedUtxo +outputsByReferences = _txOutputs . txClient diff --git a/src/Maestro/Client/V1/TxManager.hs b/src/Maestro/Client/V1/TxManager.hs new file mode 100644 index 0000000..49c69a6 --- /dev/null +++ b/src/Maestro/Client/V1/TxManager.hs @@ -0,0 +1,25 @@ +module Maestro.Client.V1.TxManager + ( submitAndMonitorTx + ) +where + +import qualified Data.ByteString as BS +import Data.Text (Text) +import Maestro.API.V1 (_txManager) +import Maestro.API.V1.TxManager +import Maestro.Client.Env +import Maestro.Client.V1.Core +import Servant.API.Generic +import Servant.Client + +txClient :: MaestroEnv 'V1 -> TxManagerAPI (AsClientT IO) +txClient = fromServant . _txManager . apiV1Client + +-- | Submit a signed and serialized transaction to the network. A transaction submited with this endpoint will be monitored by Maestro. +submitAndMonitorTx :: + -- | The Maestro Environment + MaestroEnv 'V1 -> + -- | CBOR encoded Transaction + BS.ByteString -> + IO Text +submitAndMonitorTx = _monitoredTxSubmit . txClient diff --git a/src/Maestro/Types/Common.hs b/src/Maestro/Types/Common.hs index eba5074..163c017 100644 --- a/src/Maestro/Types/Common.hs +++ b/src/Maestro/Types/Common.hs @@ -1,10 +1,13 @@ +-- | Common (shared) types between different versions of Maestro-API. + module Maestro.Types.Common ( Tx, TxOutCbor, + DatumHash, + Address, TxIndex (..), PolicyId (..), - AssetId (..), - CBORStream, + TokenName (..), EpochNo (..), EpochSize (..), AbsoluteSlot (..), @@ -13,16 +16,16 @@ module Maestro.Types.Common BlockHash (..), TxHash (..), Bech32StringOf (..), - HexStringOf, + HexStringOf (..), HashStringOf (..), DatumOptionType (..), DatumOption (..), ScriptType (..), Script (..), - TxCbor (..), - UtxoAddress (..), Order (..), + CBORStream, LowerFirst, + LowerAll, ) where @@ -45,20 +48,26 @@ data Tx -- | Phantom datatype to be used with `HexStringOf` to represent hex encoded CBOR bytes of transaction output. data TxOutCbor +-- | Phantom datatype to be used with `HexStringOf` to represent hex encoded datum hash. +data DatumHash + +-- | Phantom datatype to be used with, say `Bech32StringOf` to represent Bech32 representation of an address. +data Address + -- | Index of UTxO in a transaction outputs. newtype TxIndex = TxIndex Natural deriving stock (Eq, Ord, Show, Generic) deriving newtype (Num, Enum, Real, Integral, FromHttpApiData, ToHttpApiData, FromJSON, ToJSON) --- | Minting policy ID. +-- | Hex encoded minting policy ID (for non-ada native asset). newtype PolicyId = PolicyId Text - deriving stock (Eq, Show, Generic) + deriving stock (Eq, Ord, Show, Generic) deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON, IsString) --- | Concatenation of hex encoded policy ID and hex encoded asset name. -newtype AssetId = AssetId Text +-- | Hex encoded token name (for non-ada native asset). +newtype TokenName = TokenName Text deriving stock (Eq, Ord, Show, Generic) - deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON) + deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON, IsString) -- | An epoch, i.e. the number of the epoch. newtype EpochNo = EpochNo {unEpochNo :: Word64} @@ -94,78 +103,84 @@ newtype BlockHash = BlockHash {unBlockHash :: Text} deriving (FromJSON, ToJSON) -- | Hash of the Transaction. -newtype TxHash = TxHash {unTxHash :: Text} - deriving stock (Show, Eq, Generic) - deriving newtype (IsString) - deriving (FromJSON, ToJSON) +newtype TxHash = TxHash Text + deriving stock (Show, Eq, Ord, Generic) + deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON, IsString) +-- | Type to label the string is question is a @Bech32@ representation of the given type @a@. newtype Bech32StringOf a = Bech32StringOf Text - deriving stock (Eq, Show, Generic) + deriving stock (Eq, Ord, Show, Generic) deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON, IsString) -type HexStringOf a = Text +-- | Type to label the string is question is a hexadecimal representation of the given type @a@. +newtype HexStringOf a = HexStringOf Text + deriving stock (Eq, Ord, Show, Generic) + deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON, IsString) +-- | Type to label the string is question is a hash string of the given type @a@, like hash of the transaction body. newtype HashStringOf a = HashStringOf Text - deriving stock (Eq, Show, Generic) + deriving stock (Eq, Ord, Show, Generic) deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON, IsString) +-- | Datum in output is either inlined or not. data DatumOptionType = Inline | Hash deriving stock (Show, Eq, Ord, Generic) deriving (FromJSON, ToJSON) via CustomJSON '[ConstructorTagModifier '[LowerFirst]] DatumOptionType +-- | Description of datum in an output. If datum is successfully resolved for (when mentioning to resolve for it by giving @resolve_datums@ flag in query parameters) then fields like @_datumOptionBytes@ would have non `Nothing` value even if UTxO just had hash of datum. data DatumOption = DatumOption { _datumOptionBytes :: !(Maybe Text), + -- ^ Hex encoded datum CBOR bytes. _datumOptionHash :: !Text, + -- ^ Hash of the datum. _datumOptionJson :: !(Maybe Aeson.Value), + -- ^ JSON representation of the datum. _datumOptionType :: !DatumOptionType + -- ^ See `DatumOptionType`. } deriving stock (Show, Eq, Ord, Generic) deriving (FromJSON, ToJSON) via CustomJSON '[FieldLabelModifier '[StripPrefix "_datumOption", LowerFirst]] DatumOption +-- | Type of script. data ScriptType = Native | PlutusV1 | PlutusV2 deriving stock (Show, Eq, Ord, Generic) deriving (FromJSON, ToJSON) via CustomJSON '[ConstructorTagModifier '[LowerAll]] ScriptType +-- | Type to represent script in an UTxO. data Script = Script { _scriptBytes :: !(Maybe Text), + -- ^ Script bytes (`Nothing` if `Native` script). _scriptHash :: !Text, + -- ^ Hash of script. _scriptJson :: !(Maybe Aeson.Value), + -- ^ JSON representation of script (`Nothing` if not `Native` script). _scriptType :: !ScriptType + -- ^ See `ScriptType`. } deriving stock (Show, Eq, Ord, Generic) deriving (FromJSON, ToJSON) via CustomJSON '[FieldLabelModifier '[StripPrefix "_script", LowerFirst]] Script -newtype TxCbor = TxCbor {_txCbor :: Text} - deriving stock (Show, Eq, Generic) - deriving - (FromJSON, ToJSON) - via CustomJSON '[FieldLabelModifier '[StripPrefix "_tx", LowerFirst]] TxCbor - -newtype UtxoAddress = UtxoAddress {_utxoAddressAddress :: Text} - deriving stock (Show, Eq, Generic) - deriving - (FromJSON, ToJSON) - via CustomJSON '[FieldLabelModifier '[StripPrefix "_utxoAddress", LowerFirst]] UtxoAddress - +-- Datatype to represent for /"order"/ query parameter in some of the API requests. data Order = Ascending | Descending +-- Don't change @Show@ instance blindly, as `ToHttpApiData` instance is making use of it. +instance Show Order where + show Ascending = "asc" + show Descending = "desc" + instance ToHttpApiData Order where - toQueryParam Ascending = "asc" - toQueryParam Descending = "desc" + toQueryParam order = T.pack $ show order instance Default Order where def = Ascending -instance Show Order where - show Ascending = "asc" - show Descending = "desc" - +-- | Content-Type to represent transaction when submitting for it. data CBORStream instance Accept CBORStream where diff --git a/src/Maestro/Types/V0.hs b/src/Maestro/Types/V0.hs index 7c8a65a..26a45a5 100644 --- a/src/Maestro/Types/V0.hs +++ b/src/Maestro/Types/V0.hs @@ -9,6 +9,7 @@ module Maestro.Types.V0 , module Maestro.Types.V0.Common , module Maestro.Types.V0.General , module Maestro.Types.V0.Pool + , module Maestro.Types.V0.Transactions ) where import Maestro.Types.V0.Accounts @@ -19,3 +20,4 @@ import Maestro.Types.V0.Datum import Maestro.Types.V0.Epochs import Maestro.Types.V0.General import Maestro.Types.V0.Pool +import Maestro.Types.V0.Transactions diff --git a/src/Maestro/Types/V0/Common.hs b/src/Maestro/Types/V0/Common.hs index b8abb96..950b965 100644 --- a/src/Maestro/Types/V0/Common.hs +++ b/src/Maestro/Types/V0/Common.hs @@ -1,5 +1,6 @@ module Maestro.Types.V0.Common - ( Asset (..), + ( AssetId (..), + Asset (..), Utxo (..), module Maestro.Types.Common ) @@ -9,6 +10,12 @@ import Data.Text (Text) import Deriving.Aeson import GHC.Natural (Natural) import Maestro.Types.Common +import Servant.API (FromHttpApiData, ToHttpApiData) + +-- | Concatenation of hex encoded policy ID and hex encoded asset name. +newtype AssetId = AssetId Text + deriving stock (Eq, Ord, Show, Generic) + deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON) -- | Representation of asset in an UTxO. data Asset = Asset @@ -22,7 +29,7 @@ data Asset = Asset -- | Transaction output. data Utxo = Utxo - { _utxoAddress :: !Text, + { _utxoAddress :: !(Bech32StringOf Address), _utxoAssets :: ![Asset], _utxoDatum :: !(Maybe DatumOption), _utxoIndex :: !Natural, diff --git a/src/Maestro/Types/V0/Transactions.hs b/src/Maestro/Types/V0/Transactions.hs new file mode 100644 index 0000000..dd98e18 --- /dev/null +++ b/src/Maestro/Types/V0/Transactions.hs @@ -0,0 +1,22 @@ +module Maestro.Types.V0.Transactions + ( TxCbor (..), + UtxoAddress (..), + ) +where + +import Data.Text (Text) +import Deriving.Aeson +import Maestro.Types.Common (LowerFirst) + +newtype TxCbor = TxCbor { _txCbor :: Text } + deriving stock (Show, Eq, Generic) + deriving + (FromJSON, ToJSON) + via CustomJSON '[FieldLabelModifier '[StripPrefix "_tx", LowerFirst]] TxCbor + +newtype UtxoAddress = UtxoAddress { _utxoAddressAddress :: Text } + deriving stock (Show, Eq, Generic) + deriving + (FromJSON, ToJSON) + via CustomJSON '[FieldLabelModifier '[StripPrefix "_utxoAddress", LowerFirst]] UtxoAddress + diff --git a/src/Maestro/Types/V1.hs b/src/Maestro/Types/V1.hs index ae3cb26..3bc07f6 100644 --- a/src/Maestro/Types/V1.hs +++ b/src/Maestro/Types/V1.hs @@ -1,9 +1,17 @@ --- | Maestro types +-- | Module exporting all available types of this specific Maestro-API version. module Maestro.Types.V1 - ( module Maestro.Types.V1.Common + ( module Maestro.Types.V1.Addresses + , module Maestro.Types.V1.Common + , module Maestro.Types.V1.Datum , module Maestro.Types.V1.General + , module Maestro.Types.V1.Pools + , module Maestro.Types.V1.Transactions ) where +import Maestro.Types.V1.Addresses import Maestro.Types.V1.Common +import Maestro.Types.V1.Datum import Maestro.Types.V1.General +import Maestro.Types.V1.Pools +import Maestro.Types.V1.Transactions diff --git a/src/Maestro/Types/V1/Addresses.hs b/src/Maestro/Types/V1/Addresses.hs new file mode 100644 index 0000000..76c208c --- /dev/null +++ b/src/Maestro/Types/V1/Addresses.hs @@ -0,0 +1,101 @@ +-- | Module to define types for /\"Addresses\"/ category of endpoints defined at [docs.gomaestro.org](https://docs.gomaestro.org/docs/category/addresses). + +module Maestro.Types.V1.Addresses ( + AddressToDecode, + NetworkId (..), + PaymentCredKind (..), + PaymentCredential (..), + StakingCredKind (..), + CertIndex (..), + ChainPointer (..), + StakingCredential (..), + AddressInfo (..), + ) where + +import Deriving.Aeson +import GHC.Natural (Natural) +import Maestro.Types.V1.Common +import Servant.API (FromHttpApiData, ToHttpApiData) + +-- | Address to decode. Given address should be in either Bech32 or Hex or Base58 format. Base58 is for Byron addresses whereas others use Bech32. +type AddressToDecode = "Bech32/Hex/Base58 encoded address" + +-- | Denotes network for the entity in question, such as address. +data NetworkId = Mainnet | Testnet + deriving stock (Show, Eq, Ord, Generic) + deriving (FromJSON, ToJSON) via CustomJSON '[ConstructorTagModifier '[LowerFirst]] NetworkId + +-- | Denotes kind of a payment credential. +data PaymentCredKind = PCKKey | PCKScript + deriving stock (Show, Eq, Ord, Generic) + deriving (FromJSON, ToJSON) via CustomJSON '[ConstructorTagModifier '[StripPrefix "PCK", LowerFirst]] PaymentCredKind + +-- | Payment credential, the payment part of a Cardano address. +data PaymentCredential = PaymentCredential + { _paymentCredentialBech32:: !(Bech32StringOf PaymentCredentialAddress) + -- ^ Bech32-encoding of the credential key hash or script hash. + , _paymentCredentialHex :: !(HexStringOf PaymentCredentialAddress) + -- ^ Hex-encoding of the script or key credential. + , _paymentCredentialKind :: !PaymentCredKind + -- ^ See `PaymentCredKind`. + } + deriving stock (Show, Eq, Ord, Generic) + deriving (FromJSON, ToJSON) + via CustomJSON '[FieldLabelModifier '[StripPrefix "_paymentCredential", CamelToSnake]] PaymentCredential + +-- | Denotes kind of a staking credential. +data StakingCredKind = SCKKey | SCKScript | SCKPointer + deriving stock (Show, Eq, Ord, Generic) + deriving (FromJSON, ToJSON) via CustomJSON '[ConstructorTagModifier '[StripPrefix "SCK", LowerFirst]] StakingCredKind + +-- | To understand it, see it's use in `ChainPointer` datatype. +newtype CertIndex = CertIndex Natural + deriving stock (Eq, Ord, Show, Generic) + deriving newtype (Num, Enum, Real, Integral, FromHttpApiData, ToHttpApiData, FromJSON, ToJSON) + +-- | In an address, a chain pointer refers to a point of the chain containing a stake key registration certificate. A point is identified by 3 coordinates, as listed in the type. +data ChainPointer = ChainPointer + { _chainPointerSlot :: !SlotNo + -- ^ An absolute slot number. + , _chainPointerTxIndex :: !TxIndex + -- ^ A transaction index (within that slot). + , _chainPointerCertIndex :: !CertIndex + -- ^ A (delegation) certificate index (within that transaction). + } + deriving stock (Show, Eq, Ord, Generic) + deriving (FromJSON, ToJSON) + via CustomJSON '[FieldLabelModifier '[StripPrefix "_chainPointer", CamelToSnake]] ChainPointer + +-- | Payment credential, the payment part of a Cardano address. +data StakingCredential = StakingCredential + { _stakingCredentialBech32:: !(Maybe (Bech32StringOf StakingCredentialAddress)) + -- ^ Bech32-encoding of the credential key hash or script hash. + , _stakingCredentialHex :: !(Maybe (HexStringOf StakingCredentialAddress)) + -- ^ Hex-encoding of the script or key credential. + , _stakingCredentialKind :: !StakingCredKind + -- ^ See `StakingCredKind`. + , _stakingCredentialPointer :: !(Maybe ChainPointer) + -- ^ See `ChainPointer`. + , _stakingCredentialRewardAddress :: !(Maybe (Bech32StringOf RewardAddress)) + -- ^ See `RewardAddress`. + } + deriving stock (Show, Eq, Ord, Generic) + deriving (FromJSON, ToJSON) + via CustomJSON '[FieldLabelModifier '[StripPrefix "_stakingCredential", CamelToSnake]] StakingCredential + +-- | Information decoded from a Cardano address. +data AddressInfo = AddressInfo + { _addressInfoHex :: !(HexStringOf Address) + -- ^ Hexadecimal format encoding of the given address. + , _addressInfoBech32 :: !(Maybe (Bech32StringOf Address)) + -- ^ Bech32 representation of the given address. Present for Shelly & stake addresses whereas byron addresses are encoded in Base58. + , _addressInfoNetwork :: !(Maybe NetworkId) + -- ^ See `NetworkId`. + , _addressInfoPaymentCred :: !(Maybe PaymentCredential) + -- ^ See `PaymentCredential`. + , _addressInfoStakingCred :: !(Maybe StakingCredential) + -- ^ See `StakingCredential`. + } + deriving stock (Show, Eq, Ord, Generic) + deriving (FromJSON, ToJSON) + via CustomJSON '[FieldLabelModifier '[StripPrefix "_addressInfo", CamelToSnake]] AddressInfo diff --git a/src/Maestro/Types/V1/Common.hs b/src/Maestro/Types/V1/Common.hs index f4a5a65..c87af4a 100644 --- a/src/Maestro/Types/V1/Common.hs +++ b/src/Maestro/Types/V1/Common.hs @@ -1,21 +1,48 @@ +-- | Common (shared) types used which are not specific to single category of endpoints. + module Maestro.Types.V1.Common - ( LastUpdated (..), + ( PaymentCredentialAddress, + StakingCredentialAddress, + RewardAddress, + TaggedText (..), + LastUpdated (..), Asset (..), v1AssetToV0, - UtxoData (..), - v1UtxoToV0, - Utxos (..), - module Maestro.Types.Common - ) -where - -import Data.Text (Text) -import qualified Data.Text as T (splitAt) + UtxoWithSlot (..), + v1UtxoWithSlotToV0, + PaginatedUtxoWithSlot (..), + module Maestro.Types.Common, + module Maestro.Types.V1.Common.Pagination + ) where + +import Data.Aeson (FromJSON (..), ToJSON (..), + Value (..), withText) +import Data.Coerce (coerce) +import Data.String (IsString) +import Data.Text (Text) +import qualified Data.Text as T (splitAt) import Deriving.Aeson -import GHC.Natural (Natural) -import Maestro.Client.V1.Core.Pagination (HasCursor (..)) +import GHC.TypeLits (Symbol) import Maestro.Types.Common -import qualified Maestro.Types.V0 as V0 (Asset (..), Utxo (..)) +import qualified Maestro.Types.V0 as V0 (Asset (..), + Utxo (..)) +import Maestro.Types.V1.Common.Pagination +import Servant.API (FromHttpApiData (..), + ToHttpApiData (..)) + +-- | Phantom datatype to be used with, say `Bech32StringOf` to represent Bech32 representation of payment credential of an address. +data PaymentCredentialAddress + +-- | Phantom datatype to be used with, say `Bech32StringOf` to represent Bech32 representation of staking credential of an address. +data StakingCredentialAddress + +-- | Phantom datatype to be used with, say `Bech32StringOf` to represent Bech32 representation of stake address (See [CIP-19](https://cips.cardano.org/cips/cip19/) for more details). +data RewardAddress + +-- | Wrapper around `Text` type with mentioned description of it. +newtype TaggedText (description :: Symbol) = TaggedText Text + deriving stock (Eq, Ord, Show, Generic) + deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON, IsString) -- | Details of the most recent block processed by the indexer (aka chain tip); that is, the data returned is correct as of this block in time. data LastUpdated = LastUpdated @@ -27,10 +54,41 @@ data LastUpdated = LastUpdated deriving stock (Eq, Ord, Show, Generic) deriving (FromJSON, ToJSON) via CustomJSON '[FieldLabelModifier '[StripPrefix "_lastUpdated", CamelToSnake]] LastUpdated +-- | Type to denote for native tokens (besides ada). +data NonAdaNativeToken = NonAdaNativeToken !PolicyId !TokenName + deriving stock (Eq, Ord, Show) + +instance ToHttpApiData NonAdaNativeToken where + toUrlPiece (NonAdaNativeToken policyId tokenName) = coerce policyId <> coerce tokenName + +-- | Given asset name is either /lovelace/ or concatenation of hex encoded policy ID and hex encoded asset name for native asset. +data AssetUnit = Lovelace + -- ^ Lovelace. + | UserMintedToken !NonAdaNativeToken + -- ^ For non-ada native-tokens. + deriving stock (Eq, Ord) + +instance Show AssetUnit where + show Lovelace = "lovelace" + show (UserMintedToken nonAdaNativeToken) = show nonAdaNativeToken + +instance FromJSON AssetUnit where + parseJSON = withText "AssetUnit" $ \t -> + if t == "lovelace" then pure Lovelace + else + let (policyId, tokenName) = T.splitAt 56 t + in pure $ UserMintedToken $ NonAdaNativeToken (coerce policyId) (coerce tokenName) + +instance ToJSON AssetUnit where + toJSON Lovelace = String "lovelace" + toJSON (UserMintedToken nonAdaNativeToken) = String $ toUrlPiece nonAdaNativeToken + -- | Representation of asset in an UTxO. data Asset = Asset { _assetAmount :: !Integer - , _assetUnit :: !Text + -- ^ Amount of the asset. + , _assetUnit :: !AssetUnit + -- ^ See `AssetUnit`. } deriving stock (Show, Eq, Ord, Generic) deriving @@ -41,54 +99,62 @@ data Asset = Asset v1AssetToV0 :: Asset -> V0.Asset v1AssetToV0 Asset {..} = V0.Asset { V0._assetQuantity = _assetAmount - , V0._assetUnit = - if _assetUnit == "lovelace" then _assetUnit - else - let (policyId, tokenName) = T.splitAt 56 _assetUnit - in policyId <> "#" <> tokenName + , V0._assetUnit = case _assetUnit of + Lovelace -> "lovelace" + UserMintedToken (NonAdaNativeToken policyId tokenName) -> coerce policyId <> "#" <> coerce tokenName } -- | Transaction output. -data UtxoData = UtxoData - { _utxoDataAddress :: !Text, - _utxoDataAssets :: ![Asset], - _utxoDataDatum :: !(Maybe DatumOption), - _utxoDataIndex :: !Natural, - _utxoDataReferenceScript :: !(Maybe Script), - _utxoDataTxHash :: !Text, - _utxoDataSlot :: !SlotNo, - _utxoDataTxoutCbor :: !(Maybe (HexStringOf TxOutCbor)) - +data UtxoWithSlot = UtxoWithSlot + { _utxoWithSlotAddress :: !(Bech32StringOf Address), + -- ^ UTxO's address. + _utxoWithSlotAssets :: ![Asset], + -- ^ UTxO's assets. + _utxoWithSlotDatum :: !(Maybe DatumOption), + -- ^ UTxO's datum. + _utxoWithSlotIndex :: !TxIndex, + -- ^ UTxO's transaction index. + _utxoWithSlotReferenceScript :: !(Maybe Script), + -- ^ UTxO's script. + _utxoWithSlotTxHash :: !TxHash, + -- ^ UTxO's transaction hash. + _utxoWithSlotSlot :: !SlotNo, + -- ^ Absolute slot of block which produced the UTxO. + _utxoWithSlotTxoutCbor :: !(Maybe (HexStringOf TxOutCbor)) + -- ^ Hex encoded transaction output CBOR bytes. } deriving stock (Show, Eq, Ord, Generic) deriving (FromJSON, ToJSON) - via CustomJSON '[FieldLabelModifier '[StripPrefix "_utxoData", CamelToSnake]] UtxoData - --- | Convert @V1@ API version `UtxoData` type into corresponding @V0@ type. -v1UtxoToV0 :: UtxoData -> V0.Utxo -v1UtxoToV0 UtxoData {..} = V0.Utxo { - V0._utxoAddress = _utxoDataAddress - , V0._utxoAssets = map v1AssetToV0 _utxoDataAssets - , V0._utxoDatum = _utxoDataDatum - , V0._utxoIndex = _utxoDataIndex - , V0._utxoReferenceScript = _utxoDataReferenceScript - , V0._utxoTxHash = _utxoDataTxHash - , V0._utxoTxoutCbor = _utxoDataTxoutCbor + via CustomJSON '[FieldLabelModifier '[StripPrefix "_utxoWithSlot", CamelToSnake]] UtxoWithSlot + +-- | Convert @V1@ API version UTxO (with slot) type into corresponding @V0@ type. +v1UtxoWithSlotToV0 :: UtxoWithSlot -> V0.Utxo +v1UtxoWithSlotToV0 UtxoWithSlot {..} = V0.Utxo { + V0._utxoAddress = _utxoWithSlotAddress + , V0._utxoAssets = map v1AssetToV0 _utxoWithSlotAssets + , V0._utxoDatum = _utxoWithSlotDatum + , V0._utxoIndex = coerce _utxoWithSlotIndex + , V0._utxoReferenceScript = _utxoWithSlotReferenceScript + , V0._utxoTxHash = coerce _utxoWithSlotTxHash + , V0._utxoTxoutCbor = _utxoWithSlotTxoutCbor } --- | Transaction Outputs -data Utxos = Utxos - { _utxosData :: ![UtxoData], - _utxosLastUpdated :: !LastUpdated, - _utxosNextCursor :: !(Maybe Text) +-- | A paginated response of transaction outputs. +data PaginatedUtxoWithSlot = PaginatedUtxoWithSlot + { _paginatedUtxoWithSlotData :: ![UtxoWithSlot], + -- ^ List of UTxOs. + _paginatedUtxoWithSlotLastUpdated :: !LastUpdated, + -- ^ See `LastUpdated`. + _paginatedUtxoWithSlotNextCursor :: !(Maybe NextCursor) + -- ^ See `NextCursor` } deriving stock (Show, Eq, Generic) deriving (FromJSON, ToJSON) - via CustomJSON '[FieldLabelModifier '[StripPrefix "_utxos", CamelToSnake]] Utxos + via CustomJSON '[FieldLabelModifier '[StripPrefix "_paginatedUtxoWithSlot", CamelToSnake]] PaginatedUtxoWithSlot -instance HasCursor Utxos where - type CursorData Utxos = [UtxoData] - getNextCursor utxos = _utxosNextCursor utxos - getCursorData utxos = _utxosData utxos +instance HasCursor PaginatedUtxoWithSlot where + type CursorData PaginatedUtxoWithSlot = [UtxoWithSlot] + getNextCursor utxos = _paginatedUtxoWithSlotNextCursor utxos + getCursorData utxos = _paginatedUtxoWithSlotData utxos diff --git a/src/Maestro/Types/V1/Common/Pagination.hs b/src/Maestro/Types/V1/Common/Pagination.hs new file mode 100644 index 0000000..b3bbf1a --- /dev/null +++ b/src/Maestro/Types/V1/Common/Pagination.hs @@ -0,0 +1,27 @@ +-- | Module to define types demanded by cursor based pagination to be used by other types defined in @Maestro.Types.V1@. + +module Maestro.Types.V1.Common.Pagination ( + NextCursor (..) + , HasCursor (..) + ) where + +import Data.Aeson (FromJSON, ToJSON) +import Data.Kind (Type) +import Data.String (IsString) +import Data.Text (Text) +import GHC.Generics (Generic) +import Servant.API (FromHttpApiData, ToHttpApiData) + +-- | Type to denote for cursor to be returned in a paginated endpoint. +newtype NextCursor = NextCursor Text + deriving stock (Eq, Ord, Show, Generic) + deriving newtype (FromHttpApiData, ToHttpApiData, FromJSON, ToJSON, IsString) + +-- | Is the endpoint paged? +class (Monoid (CursorData a)) => HasCursor a where + -- | What is the type of the main data in question? + type CursorData a :: Type + -- | Get the next cursor from the value of the given type @a@. + getNextCursor :: a -> Maybe NextCursor + -- | Get the main data from the value of the given type @a@. + getCursorData :: a -> CursorData a diff --git a/src/Maestro/Types/V1/Datum.hs b/src/Maestro/Types/V1/Datum.hs new file mode 100644 index 0000000..913a497 --- /dev/null +++ b/src/Maestro/Types/V1/Datum.hs @@ -0,0 +1,20 @@ +-- | Module to define types for /\"Datum\"/ endpoints defined at [docs.gomaestro.org](https://docs.gomaestro.org/docs/category/datum). + +module Maestro.Types.V1.Datum + ( Datum (..) + ) where + +import Data.Aeson (Value) +import Data.Text (Text) +import Deriving.Aeson +import Maestro.Types.V1.Common (LowerFirst) + +-- | Details of datum when queried by it's hash. +data Datum = Datum + { _datumBytes :: !Text + -- ^ Hex encoded datum CBOR bytes. + , _datumJson :: !Value + -- ^ JSON representation of the datum. + } + deriving stock (Eq, Show, Generic) + deriving (FromJSON, ToJSON) via CustomJSON '[FieldLabelModifier '[StripPrefix "_datum", LowerFirst]] Datum diff --git a/src/Maestro/Types/V1/General.hs b/src/Maestro/Types/V1/General.hs index 4099dd4..04ca4df 100644 --- a/src/Maestro/Types/V1/General.hs +++ b/src/Maestro/Types/V1/General.hs @@ -1,4 +1,4 @@ --- | Module to define types for /\"General\"/ endpoints defined at [reference.gomaestro.org](https://reference.gomaestro.org/). +-- | Module to define types for /\"General\"/ endpoints defined at [docs.gomaestro.org](https://docs.gomaestro.org/docs/category/general). module Maestro.Types.V1.General ( -- * Types for @/system-start@ endpoint @@ -46,7 +46,9 @@ import Numeric.Natural (Natural) -- | Network start time since genesis. data SystemStart = SystemStart { _systemStartData :: !LocalTime + -- ^ Network start time since genesis. , _systemStartLastUpdated :: !LastUpdated + -- ^ See `LastUpdated`. } deriving stock (Eq, Ord, Show, Generic) deriving (FromJSON, ToJSON) via CustomJSON '[FieldLabelModifier '[StripPrefix "_systemStart", CamelToSnake]] SystemStart @@ -58,7 +60,9 @@ data SystemStart = SystemStart -- | Network era summaries. data EraSummaries = EraSummaries { _eraSummariesData :: ![EraSummaryData] + -- ^ Era summaries, see `EraSummaryData`. , _eraSummariesLastUpdated :: !LastUpdated + -- ^ See `LastUpdated`. } deriving stock (Eq, Show, Generic) deriving (FromJSON, ToJSON) via CustomJSON '[FieldLabelModifier '[StripPrefix "_eraSummaries", LowerFirst]] EraSummaries @@ -179,7 +183,9 @@ instance FromJSON MaestroRational where -- See `ProtocolParametersData`. data ProtocolParameters = ProtocolParameters { _protocolParametersData :: !ProtocolParametersData + -- ^ See `ProtocolParametersData`. , _protocolParametersLastUpdated :: !LastUpdated + -- ^ See `LastUpdated`. } deriving stock (Eq, Show, Generic) deriving (FromJSON, ToJSON) via CustomJSON '[FieldLabelModifier '[StripPrefix "_protocolParameters", CamelToSnake]] ProtocolParameters @@ -254,7 +260,9 @@ data ChainTipData = ChainTipData -- | See `ChainTipData`. data ChainTip = ChainTip { _chainTipData :: !ChainTipData + -- ^ See `ChainTipData`. , _chainTipLastUpdated :: !LastUpdated + -- ^ See `LastUpdated`. } deriving stock (Eq, Show, Generic) deriving (FromJSON, ToJSON) via CustomJSON '[FieldLabelModifier '[StripPrefix "_chainTip", CamelToSnake]] ChainTip diff --git a/src/Maestro/Types/V1/Pools.hs b/src/Maestro/Types/V1/Pools.hs new file mode 100644 index 0000000..e6a94df --- /dev/null +++ b/src/Maestro/Types/V1/Pools.hs @@ -0,0 +1,44 @@ +-- | Module to define types for /\"Pools\"/ category of endpoints defined at [docs.gomaestro.org](https://docs.gomaestro.org/docs/category/pools). + +module Maestro.Types.V1.Pools + ( PoolId, + PoolListInfo (..), + PaginatedPoolListInfo (..), + ) +where + +import Deriving.Aeson +import Maestro.Types.V1.Common + +-- | Phantom datatype to be used with, say `Bech32StringOf` to represent Bech32 representation of a pool id. +data PoolId + +-- | Information about a registered stake pool. +data PoolListInfo = PoolListInfo + { _poolListInfoPoolIdBech32 :: !(Bech32StringOf PoolId), + -- ^ Bech32 encoded Pool ID. + _poolListInfoTicker :: !(Maybe (TaggedText "pool-ticker")) + -- ^ Pool ticker symbol. + } + deriving stock (Show, Eq, Ord, Generic) + deriving + (FromJSON, ToJSON) + via CustomJSON '[FieldLabelModifier '[StripPrefix "_poolListInfo", CamelToSnake]] PoolListInfo + +-- | Paginated list of registered stake pools. +data PaginatedPoolListInfo = PaginatedPoolListInfo + { _paginatedPoolListInfoData :: ![PoolListInfo] + -- ^ See `PoolListInfo`. + , _paginatedPoolListInfoLastUpdated :: !LastUpdated + -- ^ See `LastUpdated`. + , _paginatedPoolListInfoNextCursor :: !(Maybe NextCursor) + } + deriving stock (Show, Eq, Ord, Generic) + deriving + (FromJSON, ToJSON) + via CustomJSON '[FieldLabelModifier '[StripPrefix "_paginatedPoolListInfo", CamelToSnake]] PaginatedPoolListInfo + +instance HasCursor PaginatedPoolListInfo where + type CursorData PaginatedPoolListInfo = [PoolListInfo] + getNextCursor pools = _paginatedPoolListInfoNextCursor pools + getCursorData pools = _paginatedPoolListInfoData pools diff --git a/src/Maestro/Types/V1/Transactions.hs b/src/Maestro/Types/V1/Transactions.hs new file mode 100644 index 0000000..330ba90 --- /dev/null +++ b/src/Maestro/Types/V1/Transactions.hs @@ -0,0 +1,80 @@ +-- | Module to define types for /\"Transactions\"/ category endpoints defined at [docs.gomaestro.org](https://docs.gomaestro.org/docs/category/transactions). + +module Maestro.Types.V1.Transactions + ( OutputReference (..) + , Utxo (..) + , v1UtxoToV0 + , PaginatedUtxo (..) + ) where + +import Data.Aeson (ToJSON (..), Value (..)) +import Data.Coerce (coerce) +import qualified Data.Text as T (pack) +import Deriving.Aeson +import Maestro.Types.Common +import qualified Maestro.Types.V0 as V0 (Utxo (..)) +import Maestro.Types.V1.Common +import Servant.API (ToHttpApiData (..)) + +-- | An UTxO output reference. +data OutputReference = OutputReference !TxHash !TxIndex + deriving stock (Show, Eq, Ord) + +instance ToHttpApiData OutputReference where + toQueryParam (OutputReference txHash txIndex) = coerce txHash <> T.pack (show txIndex) + +instance ToJSON OutputReference where + toJSON outputReference = String $ toQueryParam outputReference + +-- | Transaction output. +data Utxo = Utxo + { _utxoAddress :: !(Bech32StringOf Address), + -- ^ UTxO's address. + _utxoAssets :: ![Asset], + -- ^ UTxO's assets. + _utxoDatum :: !(Maybe DatumOption), + -- ^ UTxO's datum. + _utxoIndex :: !TxIndex, + -- ^ UTxO's transaction index. + _utxoReferenceScript :: !(Maybe Script), + -- ^ UTxO's script. + _utxoTxHash :: !TxHash, + -- ^ UTxO's transaction hash. + _utxoTxoutCbor :: !(Maybe (HexStringOf TxOutCbor)) + -- ^ Hex encoded transaction output CBOR bytes. + } + deriving stock (Show, Eq, Ord, Generic) + deriving + (FromJSON, ToJSON) + via CustomJSON '[FieldLabelModifier '[StripPrefix "_utxo", CamelToSnake]] Utxo + +-- | Convert @V1@ API version UTxO type into corresponding @V0@ type. +v1UtxoToV0 :: Utxo -> V0.Utxo +v1UtxoToV0 Utxo {..} = V0.Utxo { + V0._utxoAddress = _utxoAddress + , V0._utxoAssets = map v1AssetToV0 _utxoAssets + , V0._utxoDatum = _utxoDatum + , V0._utxoIndex = coerce _utxoIndex + , V0._utxoReferenceScript = _utxoReferenceScript + , V0._utxoTxHash = coerce _utxoTxHash + , V0._utxoTxoutCbor = _utxoTxoutCbor + } + +-- | A paginated response of transaction outputs. +data PaginatedUtxo = PaginatedUtxo + { _paginatedUtxoData :: ![Utxo], + -- ^ List of UTxOs. + _paginatedUtxoLastUpdated :: !LastUpdated, + -- ^ See `LastUpdated`. + _paginatedUtxoNextCursor :: !(Maybe NextCursor) + -- ^ See `NextCursor` + } + deriving stock (Show, Eq, Generic) + deriving + (FromJSON, ToJSON) + via CustomJSON '[FieldLabelModifier '[StripPrefix "_paginatedUtxo", CamelToSnake]] PaginatedUtxo + +instance HasCursor PaginatedUtxo where + type CursorData PaginatedUtxo = [Utxo] + getNextCursor utxos = _paginatedUtxoNextCursor utxos + getCursorData utxos = _paginatedUtxoData utxos