blockfrost-api-0.10.0.0: src/Blockfrost/Types/Cardano/Utils.hs
{-# LANGUAGE RecordWildCards #-}
-- | Cardano Utils responses
module Blockfrost.Types.Cardano.Utils
( DerivedAddress (..)
, TxEval (..)
, TxEvalValidator (..)
, TxEvalBudget (..)
, evalSample
, TxEvalInput (..)
) where
import Data.Aeson
( FromJSON (..)
, FromJSONKey (..)
, ToJSON (..)
, ToJSONKey (..)
, Value (Array)
, object
, withObject
, withText
, (.:)
, (.:?)
, (.=)
)
import Data.Aeson.Types (FromJSONKeyFunction(..), Parser)
import Blockfrost.Types.Shared.CBOR (CBORString(..))
import Blockfrost.Types.Shared.ValidationPurpose (ValidationPurpose(..))
import Data.Text (Text)
import Data.Map (Map)
import Deriving.Aeson
import Servant.Docs (ToSample (..), singleSample)
import qualified Data.Aeson.Types
import qualified Data.Char
import qualified Data.Text
import qualified Data.Map.Strict
import qualified Text.Read
-- | Derived Shelley address
data DerivedAddress = DerivedAddress
{ _derivedAddressXpub :: Text -- ^ Hexadecimal xpub
, _derivedAddressRole :: Integer -- ^ Account role
, _derivedAddressIndex :: Integer -- ^ Address index
, _derivedAddressAddress :: Text -- ^ Derived address
}
deriving stock (Show, Eq, Generic)
deriving (FromJSON, ToJSON)
via CustomJSON '[FieldLabelModifier '[StripPrefix "_derivedAddress", CamelToSnake]] DerivedAddress
instance ToSample DerivedAddress where
toSamples = pure $ singleSample
DerivedAddress
{ _derivedAddressXpub = "d507c8f866691bd96e131334c355188b1a1d0b2fa0ab11545075aab332d77d9eb19657ad13ee581b56b0f8d744d66ca356b93d42fe176b3de007d53e9c4c4e7a"
, _derivedAddressRole = 0
, _derivedAddressIndex = 0
, _derivedAddressAddress = "addr1q90sqnljxky88s0jsnps48jd872p7znzwym0jpzqnax6qs5nfrlkaatu28n0qzmqh7f2cpksxhpc9jefx3wrl0a2wu8q5amen7"
}
-- * TxEval
data TxEvalValidator = TxEvalValidator
{ _txEvalValidatorPurpose :: ValidationPurpose
, _txEvalValidatorIndex :: Int
}
deriving stock (Eq, Ord, Show, Generic)
instance ToJSON TxEvalValidator where
toJSON = toJSON . mkOgmiosValidator
instance ToJSONKey TxEvalValidator where
toJSONKey = Data.Aeson.Types.toJSONKeyText mkOgmiosValidator
mkOgmiosValidator
:: TxEvalValidator
-> Text
mkOgmiosValidator TxEvalValidator{..} =
( toOgmiosPurpose _txEvalValidatorPurpose
<> ":"
<> Data.Text.pack (show _txEvalValidatorIndex)
)
instance FromJSON TxEvalValidator where
parseJSON =
withText
"TxEvalValidator"
parseOgmiosValidator
instance FromJSONKey TxEvalValidator where
fromJSONKey = FromJSONKeyTextParser parseOgmiosValidator
parseOgmiosValidator
:: Text
-> Parser TxEvalValidator
parseOgmiosValidator =
(\case
[purpose, index] ->
case fromOgmiosPurpose purpose of
Right p ->
case Text.Read.readMaybe (Data.Text.unpack index) of
Nothing -> fail $ "Expecting numeric index, got " <> (Data.Text.unpack index)
Just idx -> pure $ TxEvalValidator p idx
Left e ->
fail e
x -> fail $ "Expecting [purpose, index], got " <> show x
. Data.Text.splitOn ":"
)
toOgmiosPurpose
:: ValidationPurpose
-> Text
toOgmiosPurpose Spend = "spend"
toOgmiosPurpose Mint = "mint"
toOgmiosPurpose Cert = "publish"
toOgmiosPurpose Reward = "withdraw"
fromOgmiosPurpose
:: Text
-> Either String ValidationPurpose
fromOgmiosPurpose "spend" = Right Spend
fromOgmiosPurpose "mint" = Right Mint
fromOgmiosPurpose "publish" = Right Cert
fromOgmiosPurpose "withdraw" = Right Reward
fromOgmiosPurpose x =
Left
$ "Don't know how to handle Ogmios validation purpose: "
<> Data.Text.unpack x
validatorSample :: TxEvalValidator
validatorSample =
TxEvalValidator
{ _txEvalValidatorPurpose = Spend
, _txEvalValidatorIndex = 0
}
instance ToSample TxEvalValidator where
toSamples = pure $ singleSample validatorSample
data TxEvalBudget = TxEvalBudget
{ _txEvalBudgetMemory :: Integer -- ^ Memory budget
, _txEvalBudgetSteps :: Integer -- ^ CPU budget
}
deriving stock (Show, Eq, Generic)
deriving (FromJSON, ToJSON)
via CustomJSON '[FieldLabelModifier '[StripPrefix "_txEvalBudget", CamelToSnake]] TxEvalBudget
budgetSample :: TxEvalBudget
budgetSample =
TxEvalBudget
{ _txEvalBudgetMemory = 1765011
, _txEvalBudgetSteps = 503871230
}
instance ToSample TxEvalBudget where
toSamples = pure $ singleSample budgetSample
data TxEvalFailure = TxEvalFailure Value
deriving stock (Show, Eq, Generic)
deriving (FromJSON, ToJSON)
-- | Transaction evaluation result wrapper
newtype TxEval = TxEval
{ _txEvalResult ::
Either
TxEvalFailure
(Map
TxEvalValidator
TxEvalBudget)
}
deriving stock (Show, Eq, Generic)
instance ToJSON TxEval where
toJSON TxEval{..} =
object
[ "type" .= ("jsonwsp/response" :: Text)
, "version" .= ("1.0" :: Text)
, "servicename" .= ("ogmios" :: Text)
, "methodname" .= ("EvaluateTx" :: Text)
, "result" .= toJSON _txEvalResult
]
instance FromJSON TxEval where
parseJSON = withObject "txEval" $ \o -> do
r <- o .: "result"
mEvalResult <- r .:? "EvaluationResult"
case mEvalResult of
Nothing -> TxEval . Left . TxEvalFailure <$> r .: "EvaluationFailure"
Just evalRes -> TxEval . Right <$> parseJSON evalRes
evalSample :: TxEval
evalSample =
TxEval
$ Right
(Data.Map.Strict.fromList
[(validatorSample, budgetSample)]
)
instance ToSample TxEval where
toSamples = pure $ singleSample evalSample
data LowerLeading
instance StringModifier LowerLeading where
getStringModifier "" = ""
getStringModifier (c:xs) = Data.Char.toLower c : xs
-- | Transaction evaluation input for UTXO variant
data TxEvalInput = TxEvalInput
{ _txEvalInputCbor :: CBORString -- ^ CBOR encoded transaction
, _txEvalInputAdditionalUtxoSet :: Value -- ^ Additional UTXO set as JSON @Value@
}
deriving stock (Show, Eq, Generic)
deriving (FromJSON, ToJSON)
via CustomJSON '[FieldLabelModifier '[StripPrefix "_txEvalInput", LowerLeading]] TxEvalInput
instance ToSample TxEvalInput where
toSamples = pure $ singleSample
TxEvalInput
{ _txEvalInputCbor = CBORString "83a40081825820daa9"
, _txEvalInputAdditionalUtxoSet = Array mempty
}