blockfrost-api 0.8.1.0 → 0.9.0.0
raw patch · 23 files changed
+928/−41 lines, 23 filesdep ~servantPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: servant
API changes (from Hackage documentation)
- Blockfrost.Lens: class HasOnchainMetadata s a | s -> a
- Blockfrost.Lens: instance Blockfrost.Lens.HasImage Blockfrost.Types.Cardano.Assets.AssetOnChainMetadata Data.Text.Internal.Text
- Blockfrost.Lens: instance Blockfrost.Lens.HasName Blockfrost.Types.Cardano.Assets.AssetOnChainMetadata Data.Text.Internal.Text
- Blockfrost.Lens: instance Blockfrost.Lens.HasOnchainMetadata Blockfrost.Types.Cardano.Assets.AssetDetails (GHC.Maybe.Maybe Blockfrost.Types.Cardano.Assets.AssetOnChainMetadata)
- Blockfrost.Lens: onchainMetadata :: HasOnchainMetadata s a => Lens' s a
- Blockfrost.Types.Cardano.Assets: [_assetDetailsOnchainMetadata] :: AssetDetails -> Maybe AssetOnChainMetadata
+ Blockfrost.Auth: Sanchonet :: Env
+ Blockfrost.Env: Sanchonet :: Env
+ Blockfrost.Lens: class HasFiles s a | s -> a
+ Blockfrost.Lens: class HasMediaType s a | s -> a
+ Blockfrost.Lens: class HasOnchainMetadataExtra s a | s -> a
+ Blockfrost.Lens: class HasOnchainMetadataValue s a | s -> a
+ Blockfrost.Lens: class HasOnchainStandardMetadata s a | s -> a
+ Blockfrost.Lens: files :: HasFiles s a => Lens' s a
+ Blockfrost.Lens: instance Blockfrost.Lens.HasDescription Blockfrost.Types.Cardano.Assets.AssetOnChainMetadata (GHC.Maybe.Maybe Data.Text.Internal.Text)
+ Blockfrost.Lens: instance Blockfrost.Lens.HasFiles Blockfrost.Types.Cardano.Assets.AssetOnChainMetadata (GHC.Maybe.Maybe [Blockfrost.Types.Cardano.Assets.MetadataMediaFile])
+ Blockfrost.Lens: instance Blockfrost.Lens.HasImage Blockfrost.Types.Cardano.Assets.AssetOnChainMetadata (GHC.Maybe.Maybe Data.Text.Internal.Text)
+ Blockfrost.Lens: instance Blockfrost.Lens.HasMediaType Blockfrost.Types.Cardano.Assets.AssetOnChainMetadata (GHC.Maybe.Maybe Data.Text.Internal.Text)
+ Blockfrost.Lens: instance Blockfrost.Lens.HasName Blockfrost.Types.Cardano.Assets.AssetOnChainMetadata (GHC.Maybe.Maybe Data.Text.Internal.Text)
+ Blockfrost.Lens: instance Blockfrost.Lens.HasOnchainMetadataExtra Blockfrost.Types.Cardano.Assets.AssetDetails (GHC.Maybe.Maybe Data.Text.Internal.Text)
+ Blockfrost.Lens: instance Blockfrost.Lens.HasOnchainMetadataValue Blockfrost.Types.Cardano.Assets.AssetDetails (GHC.Maybe.Maybe Data.Aeson.Types.Internal.Value)
+ Blockfrost.Lens: instance Blockfrost.Lens.HasOnchainStandardMetadata Blockfrost.Types.Cardano.Assets.AssetDetails (GHC.Maybe.Maybe Blockfrost.Types.Cardano.Assets.AssetOnChainMetadata)
+ Blockfrost.Lens: mediaType :: HasMediaType s a => Lens' s a
+ Blockfrost.Lens: onchainMetadataExtra :: HasOnchainMetadataExtra s a => Lens' s a
+ Blockfrost.Lens: onchainMetadataValue :: HasOnchainMetadataValue s a => Lens' s a
+ Blockfrost.Lens: onchainStandardMetadata :: HasOnchainStandardMetadata s a => Lens' s a
+ Blockfrost.Types.Cardano.Accounts: AddressAssociatedTotal :: Address -> [Amount] -> [Amount] -> Integer -> AddressAssociatedTotal
+ Blockfrost.Types.Cardano.Accounts: [_addressAssociatedTotalReceivedSum] :: AddressAssociatedTotal -> [Amount]
+ Blockfrost.Types.Cardano.Accounts: [_addressAssociatedTotalSentSum] :: AddressAssociatedTotal -> [Amount]
+ Blockfrost.Types.Cardano.Accounts: [_addressAssociatedTotalStakeAddress] :: AddressAssociatedTotal -> Address
+ Blockfrost.Types.Cardano.Accounts: [_addressAssociatedTotalTxCount] :: AddressAssociatedTotal -> Integer
+ Blockfrost.Types.Cardano.Accounts: data AddressAssociatedTotal
+ Blockfrost.Types.Cardano.Accounts: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Cardano.Accounts.AddressAssociatedTotal
+ Blockfrost.Types.Cardano.Accounts: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Cardano.Accounts.AddressAssociatedTotal
+ Blockfrost.Types.Cardano.Accounts: instance GHC.Classes.Eq Blockfrost.Types.Cardano.Accounts.AddressAssociatedTotal
+ Blockfrost.Types.Cardano.Accounts: instance GHC.Generics.Generic Blockfrost.Types.Cardano.Accounts.AddressAssociatedTotal
+ Blockfrost.Types.Cardano.Accounts: instance GHC.Show.Show Blockfrost.Types.Cardano.Accounts.AddressAssociatedTotal
+ Blockfrost.Types.Cardano.Accounts: instance Servant.Docs.Internal.ToSample Blockfrost.Types.Cardano.Accounts.AddressAssociatedTotal
+ Blockfrost.Types.Cardano.Addresses: AddressInfoExtended :: Address -> [AmountExtended] -> Maybe Address -> AddressType -> Bool -> AddressInfoExtended
+ Blockfrost.Types.Cardano.Addresses: [_addressInfoExtendedAddress] :: AddressInfoExtended -> Address
+ Blockfrost.Types.Cardano.Addresses: [_addressInfoExtendedAmount] :: AddressInfoExtended -> [AmountExtended]
+ Blockfrost.Types.Cardano.Addresses: [_addressInfoExtendedScript] :: AddressInfoExtended -> Bool
+ Blockfrost.Types.Cardano.Addresses: [_addressInfoExtendedStakeAddress] :: AddressInfoExtended -> Maybe Address
+ Blockfrost.Types.Cardano.Addresses: [_addressInfoExtendedType] :: AddressInfoExtended -> AddressType
+ Blockfrost.Types.Cardano.Addresses: data AddressInfoExtended
+ Blockfrost.Types.Cardano.Addresses: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Cardano.Addresses.AddressInfoExtended
+ Blockfrost.Types.Cardano.Addresses: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Cardano.Addresses.AddressInfoExtended
+ Blockfrost.Types.Cardano.Addresses: instance GHC.Classes.Eq Blockfrost.Types.Cardano.Addresses.AddressInfoExtended
+ Blockfrost.Types.Cardano.Addresses: instance GHC.Generics.Generic Blockfrost.Types.Cardano.Addresses.AddressInfoExtended
+ Blockfrost.Types.Cardano.Addresses: instance GHC.Show.Show Blockfrost.Types.Cardano.Addresses.AddressInfoExtended
+ Blockfrost.Types.Cardano.Addresses: instance Servant.Docs.Internal.ToSample Blockfrost.Types.Cardano.Addresses.AddressInfoExtended
+ Blockfrost.Types.Cardano.Assets: MetadataMediaFile :: Maybe Text -> Maybe Text -> Maybe Text -> MetadataMediaFile
+ Blockfrost.Types.Cardano.Assets: [_assetDetailsOnchainMetadataExtra] :: AssetDetails -> Maybe Text
+ Blockfrost.Types.Cardano.Assets: [_assetDetailsOnchainMetadataValue] :: AssetDetails -> Maybe Value
+ Blockfrost.Types.Cardano.Assets: [_assetDetailsOnchainStandardMetadata] :: AssetDetails -> Maybe AssetOnChainMetadata
+ Blockfrost.Types.Cardano.Assets: [_assetOnChainMetadataDescription] :: AssetOnChainMetadata -> Maybe Text
+ Blockfrost.Types.Cardano.Assets: [_assetOnChainMetadataFiles] :: AssetOnChainMetadata -> Maybe [MetadataMediaFile]
+ Blockfrost.Types.Cardano.Assets: [_assetOnChainMetadataMediaType] :: AssetOnChainMetadata -> Maybe Text
+ Blockfrost.Types.Cardano.Assets: [_metadataMediaFileMediaType] :: MetadataMediaFile -> Maybe Text
+ Blockfrost.Types.Cardano.Assets: [_metadataMediaFileName] :: MetadataMediaFile -> Maybe Text
+ Blockfrost.Types.Cardano.Assets: [_metadataMediaFileSrc] :: MetadataMediaFile -> Maybe Text
+ Blockfrost.Types.Cardano.Assets: data MetadataMediaFile
+ Blockfrost.Types.Cardano.Assets: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Cardano.Assets.MetadataMediaFile
+ Blockfrost.Types.Cardano.Assets: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Cardano.Assets.MetadataMediaFile
+ Blockfrost.Types.Cardano.Assets: instance Deriving.Aeson.StringModifier Blockfrost.Types.Cardano.Assets.LowerHead
+ Blockfrost.Types.Cardano.Assets: instance GHC.Classes.Eq Blockfrost.Types.Cardano.Assets.MetadataMediaFile
+ Blockfrost.Types.Cardano.Assets: instance GHC.Generics.Generic Blockfrost.Types.Cardano.Assets.MetadataMediaFile
+ Blockfrost.Types.Cardano.Assets: instance GHC.Show.Show Blockfrost.Types.Cardano.Assets.MetadataMediaFile
+ Blockfrost.Types.Cardano.Assets: instance Servant.Docs.Internal.ToSample Blockfrost.Types.Cardano.Assets.MetadataMediaFile
+ Blockfrost.Types.Cardano.Assets: parseStandardMetadata :: Maybe Value -> Maybe AssetOnChainMetadata
+ Blockfrost.Types.Cardano.Assets: parseStandardMetadataInDetails :: AssetDetails -> AssetDetails
+ Blockfrost.Types.Cardano.Pools: Pool :: PoolId -> Text -> Lovelaces -> Lovelaces -> Pool
+ Blockfrost.Types.Cardano.Pools: [_poolActiveStake] :: Pool -> Lovelaces
+ Blockfrost.Types.Cardano.Pools: [_poolHex] :: Pool -> Text
+ Blockfrost.Types.Cardano.Pools: [_poolLiveStake] :: Pool -> Lovelaces
+ Blockfrost.Types.Cardano.Pools: [_poolPoolId] :: Pool -> PoolId
+ Blockfrost.Types.Cardano.Pools: data Pool
+ Blockfrost.Types.Cardano.Pools: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Cardano.Pools.Pool
+ Blockfrost.Types.Cardano.Pools: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Cardano.Pools.Pool
+ Blockfrost.Types.Cardano.Pools: instance GHC.Classes.Eq Blockfrost.Types.Cardano.Pools.Pool
+ Blockfrost.Types.Cardano.Pools: instance GHC.Generics.Generic Blockfrost.Types.Cardano.Pools.Pool
+ Blockfrost.Types.Cardano.Pools: instance GHC.Show.Show Blockfrost.Types.Cardano.Pools.Pool
+ Blockfrost.Types.Cardano.Pools: instance Servant.Docs.Internal.ToSample Blockfrost.Types.Cardano.Pools.Pool
+ Blockfrost.Types.Cardano.Utils: DerivedAddress :: Text -> Integer -> Integer -> Text -> DerivedAddress
+ Blockfrost.Types.Cardano.Utils: TxEval :: [TxEvalResult] -> TxEval
+ Blockfrost.Types.Cardano.Utils: TxEvalBudget :: Integer -> Integer -> TxEvalBudget
+ Blockfrost.Types.Cardano.Utils: TxEvalInput :: CBORString -> Value -> TxEvalInput
+ Blockfrost.Types.Cardano.Utils: TxEvalResult :: Text -> TxEvalBudget -> TxEvalResult
+ Blockfrost.Types.Cardano.Utils: [_derivedAddressAddress] :: DerivedAddress -> Text
+ Blockfrost.Types.Cardano.Utils: [_derivedAddressIndex] :: DerivedAddress -> Integer
+ Blockfrost.Types.Cardano.Utils: [_derivedAddressRole] :: DerivedAddress -> Integer
+ Blockfrost.Types.Cardano.Utils: [_derivedAddressXpub] :: DerivedAddress -> Text
+ Blockfrost.Types.Cardano.Utils: [_txEvalBudgetCPU] :: TxEvalBudget -> Integer
+ Blockfrost.Types.Cardano.Utils: [_txEvalBudgetMemory] :: TxEvalBudget -> Integer
+ Blockfrost.Types.Cardano.Utils: [_txEvalInputAdditionalUtxoSet] :: TxEvalInput -> Value
+ Blockfrost.Types.Cardano.Utils: [_txEvalInputCbor] :: TxEvalInput -> CBORString
+ Blockfrost.Types.Cardano.Utils: [_txEvalResultBudget] :: TxEvalResult -> TxEvalBudget
+ Blockfrost.Types.Cardano.Utils: [_txEvalResultValidator] :: TxEvalResult -> Text
+ Blockfrost.Types.Cardano.Utils: [_txEvalResult] :: TxEval -> [TxEvalResult]
+ Blockfrost.Types.Cardano.Utils: data DerivedAddress
+ Blockfrost.Types.Cardano.Utils: data TxEvalBudget
+ Blockfrost.Types.Cardano.Utils: data TxEvalInput
+ Blockfrost.Types.Cardano.Utils: data TxEvalResult
+ Blockfrost.Types.Cardano.Utils: evalSample :: TxEval
+ Blockfrost.Types.Cardano.Utils: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Cardano.Utils.DerivedAddress
+ Blockfrost.Types.Cardano.Utils: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Cardano.Utils.TxEval
+ Blockfrost.Types.Cardano.Utils: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Cardano.Utils.TxEvalBudget
+ Blockfrost.Types.Cardano.Utils: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Cardano.Utils.TxEvalInput
+ Blockfrost.Types.Cardano.Utils: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Cardano.Utils.TxEvalResult
+ Blockfrost.Types.Cardano.Utils: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Cardano.Utils.DerivedAddress
+ Blockfrost.Types.Cardano.Utils: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Cardano.Utils.TxEval
+ Blockfrost.Types.Cardano.Utils: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Cardano.Utils.TxEvalBudget
+ Blockfrost.Types.Cardano.Utils: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Cardano.Utils.TxEvalInput
+ Blockfrost.Types.Cardano.Utils: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Cardano.Utils.TxEvalResult
+ Blockfrost.Types.Cardano.Utils: instance Deriving.Aeson.StringModifier Blockfrost.Types.Cardano.Utils.LowerLeading
+ Blockfrost.Types.Cardano.Utils: instance GHC.Classes.Eq Blockfrost.Types.Cardano.Utils.DerivedAddress
+ Blockfrost.Types.Cardano.Utils: instance GHC.Classes.Eq Blockfrost.Types.Cardano.Utils.TxEval
+ Blockfrost.Types.Cardano.Utils: instance GHC.Classes.Eq Blockfrost.Types.Cardano.Utils.TxEvalBudget
+ Blockfrost.Types.Cardano.Utils: instance GHC.Classes.Eq Blockfrost.Types.Cardano.Utils.TxEvalInput
+ Blockfrost.Types.Cardano.Utils: instance GHC.Classes.Eq Blockfrost.Types.Cardano.Utils.TxEvalResult
+ Blockfrost.Types.Cardano.Utils: instance GHC.Generics.Generic Blockfrost.Types.Cardano.Utils.DerivedAddress
+ Blockfrost.Types.Cardano.Utils: instance GHC.Generics.Generic Blockfrost.Types.Cardano.Utils.TxEval
+ Blockfrost.Types.Cardano.Utils: instance GHC.Generics.Generic Blockfrost.Types.Cardano.Utils.TxEvalBudget
+ Blockfrost.Types.Cardano.Utils: instance GHC.Generics.Generic Blockfrost.Types.Cardano.Utils.TxEvalInput
+ Blockfrost.Types.Cardano.Utils: instance GHC.Generics.Generic Blockfrost.Types.Cardano.Utils.TxEvalResult
+ Blockfrost.Types.Cardano.Utils: instance GHC.Show.Show Blockfrost.Types.Cardano.Utils.DerivedAddress
+ Blockfrost.Types.Cardano.Utils: instance GHC.Show.Show Blockfrost.Types.Cardano.Utils.TxEval
+ Blockfrost.Types.Cardano.Utils: instance GHC.Show.Show Blockfrost.Types.Cardano.Utils.TxEvalBudget
+ Blockfrost.Types.Cardano.Utils: instance GHC.Show.Show Blockfrost.Types.Cardano.Utils.TxEvalInput
+ Blockfrost.Types.Cardano.Utils: instance GHC.Show.Show Blockfrost.Types.Cardano.Utils.TxEvalResult
+ Blockfrost.Types.Cardano.Utils: instance Servant.Docs.Internal.ToSample Blockfrost.Types.Cardano.Utils.DerivedAddress
+ Blockfrost.Types.Cardano.Utils: instance Servant.Docs.Internal.ToSample Blockfrost.Types.Cardano.Utils.TxEval
+ Blockfrost.Types.Cardano.Utils: instance Servant.Docs.Internal.ToSample Blockfrost.Types.Cardano.Utils.TxEvalBudget
+ Blockfrost.Types.Cardano.Utils: instance Servant.Docs.Internal.ToSample Blockfrost.Types.Cardano.Utils.TxEvalInput
+ Blockfrost.Types.Cardano.Utils: instance Servant.Docs.Internal.ToSample Blockfrost.Types.Cardano.Utils.TxEvalResult
+ Blockfrost.Types.Cardano.Utils: newtype TxEval
+ Blockfrost.Types.Cardano.Utils: resultSample :: TxEvalResult
+ Blockfrost.Types.Shared.Amount: AdaAmountExtended :: Lovelaces -> AmountExtended
+ Blockfrost.Types.Shared.Amount: AssetAmountExtended :: Maybe Int -> Bool -> SomeDiscrete -> AmountExtended
+ Blockfrost.Types.Shared.Amount: [assetAmountExtendedDecimals] :: AmountExtended -> Maybe Int
+ Blockfrost.Types.Shared.Amount: [assetAmountExtendedHasNftOnchainMetadata] :: AmountExtended -> Bool
+ Blockfrost.Types.Shared.Amount: [assetAmountExtendedValue] :: AmountExtended -> SomeDiscrete
+ Blockfrost.Types.Shared.Amount: data AmountExtended
+ Blockfrost.Types.Shared.Amount: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Shared.Amount.AmountExtended
+ Blockfrost.Types.Shared.Amount: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Shared.Amount.AmountExtended
+ Blockfrost.Types.Shared.Amount: instance GHC.Classes.Eq Blockfrost.Types.Shared.Amount.AmountExtended
+ Blockfrost.Types.Shared.Amount: instance GHC.Classes.Ord Blockfrost.Types.Shared.Amount.AmountExtended
+ Blockfrost.Types.Shared.Amount: instance GHC.Generics.Generic Blockfrost.Types.Shared.Amount.AmountExtended
+ Blockfrost.Types.Shared.Amount: instance GHC.Show.Show Blockfrost.Types.Shared.Amount.AmountExtended
+ Blockfrost.Types.Shared.Amount: instance Servant.Docs.Internal.ToSample Blockfrost.Types.Shared.Amount.AmountExtended
+ Blockfrost.Types.Shared.CBOR: instance Data.Aeson.Types.FromJSON.FromJSON Blockfrost.Types.Shared.CBOR.CBORString
+ Blockfrost.Types.Shared.CBOR: instance Data.Aeson.Types.ToJSON.ToJSON Blockfrost.Types.Shared.CBOR.CBORString
- Blockfrost.Types.Cardano.Assets: AssetDetails :: Text -> PolicyId -> Maybe Text -> Text -> Quantity -> TxHash -> Integer -> Maybe AssetOnChainMetadata -> Maybe AssetMetadata -> AssetDetails
+ Blockfrost.Types.Cardano.Assets: AssetDetails :: Text -> PolicyId -> Maybe Text -> Text -> Quantity -> TxHash -> Integer -> Maybe Value -> Maybe AssetOnChainMetadata -> Maybe AssetMetadata -> Maybe Text -> AssetDetails
- Blockfrost.Types.Cardano.Assets: AssetOnChainMetadata :: Text -> Text -> AssetOnChainMetadata
+ Blockfrost.Types.Cardano.Assets: AssetOnChainMetadata :: Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe [MetadataMediaFile] -> AssetOnChainMetadata
- Blockfrost.Types.Cardano.Assets: [_assetOnChainMetadataImage] :: AssetOnChainMetadata -> Text
+ Blockfrost.Types.Cardano.Assets: [_assetOnChainMetadataImage] :: AssetOnChainMetadata -> Maybe Text
- Blockfrost.Types.Cardano.Assets: [_assetOnChainMetadataName] :: AssetOnChainMetadata -> Text
+ Blockfrost.Types.Cardano.Assets: [_assetOnChainMetadataName] :: AssetOnChainMetadata -> Maybe Text
Files
- CHANGELOG.md +16/−0
- blockfrost-api.cabal +7/−3
- src/Blockfrost/API.hs +5/−0
- src/Blockfrost/API/Cardano.hs +2/−0
- src/Blockfrost/API/Cardano/Accounts.hs +11/−0
- src/Blockfrost/API/Cardano/Addresses.hs +7/−0
- src/Blockfrost/API/Cardano/Pools.hs +8/−0
- src/Blockfrost/API/Cardano/Utils.hs +50/−0
- src/Blockfrost/Env.hs +2/−1
- src/Blockfrost/Types/Cardano.hs +2/−0
- src/Blockfrost/Types/Cardano/Accounts.hs +35/−0
- src/Blockfrost/Types/Cardano/Addresses.hs +33/−0
- src/Blockfrost/Types/Cardano/Assets.hs +110/−26
- src/Blockfrost/Types/Cardano/Pools.hs +35/−1
- src/Blockfrost/Types/Cardano/Utils.hs +136/−0
- src/Blockfrost/Types/Shared/Amount.hs +60/−1
- src/Blockfrost/Types/Shared/CBOR.hs +20/−0
- src/Blockfrost/Util/LensRules.hs +1/−1
- test/Cardano/Accounts.hs +54/−0
- test/Cardano/Addresses.hs +48/−0
- test/Cardano/Assets.hs +57/−8
- test/Cardano/Pools.hs +50/−0
- test/Cardano/Utils.hs +179/−0
CHANGELOG.md view
@@ -1,3 +1,19 @@+# Version [0.9.0.0](https://github.com/blockfrost/blockfrost-haskell/compare/api-0.8.1.0...api-0.9.0.0) (2023-12-18)++* Allow servant `0.20` [#41](https://github.com/blockfrost/blockfrost-haskell/pull/41)+* Additions [#43](https://github.com/blockfrost/blockfrost-haskell/pull/43)+ * `Env` enum extended with `Sanchonet` for `cardano-sanchonet` network+ * `/accounts/:stake_address/addresses/total` endpoint and `AddressAssociatedTotal` type+ * `/addresses/:address/extended` endpoint and `AddressInfoExtended` type (uses `AmountExtended` type)+ * `/pools/extended` endpoint and `Pool` type+ * `/utils` API+ * `/utils/addresses/xpub/:xpub/:role/:index` endpoint and `DerivedAddress` type+ * `/utils/txs/evaluate` endpoint+ * `/utils/txs/evaluate/utxos` endpoint+ * `TxEval`, `TxEvalResult`, `TxEvalBudget`, `TxEvalInput` types for the two above+* Better metadata handling [#40](https://github.com/blockfrost/blockfrost-haskell/pull/40)+ * Adds `onchainMetadataExtra` and `onchainMetadataValue` fields for `AssetDetails`+ # Version [0.8.1.0](https://github.com/blockfrost/blockfrost-haskell/compare/api-0.8.0.0...api-0.8.1.0) (2023-09-18) * Added `address` field to `AddressUtxo` [#38](https://github.com/blockfrost/blockfrost-haskell/pull/38)
blockfrost-api.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: blockfrost-api-version: 0.8.1.0+version: 0.9.0.0 synopsis: API definitions for blockfrost.io description: Core types and Servant API description homepage: https://github.com/blockfrost/blockfrost-haskell@@ -13,9 +13,10 @@ build-type: Simple extra-source-files:- CHANGELOG.md LICENSE README.md+extra-doc-files:+ CHANGELOG.md flag BuildFast Default: True@@ -72,6 +73,7 @@ , Blockfrost.API.Cardano.Pools , Blockfrost.API.Cardano.Scripts , Blockfrost.API.Cardano.Transactions+ , Blockfrost.API.Cardano.Utils , Blockfrost.API.IPFS , Blockfrost.API.NutLink , Blockfrost.Auth@@ -92,6 +94,7 @@ , Blockfrost.Types.Cardano.Pools , Blockfrost.Types.Cardano.Scripts , Blockfrost.Types.Cardano.Transactions+ , Blockfrost.Types.Cardano.Utils , Blockfrost.Types.IPFS , Blockfrost.Types.NutLink , Blockfrost.Types.Shared@@ -130,7 +133,7 @@ , deriving-aeson , lens >= 5.0 && < 5.3 , template-haskell- , servant >= 0.18 && < 0.20+ , servant >= 0.18 && < 0.21 , servant-docs , servant-multipart-api , safe-money >= 0.9 && < 0.10@@ -153,6 +156,7 @@ , Cardano.Pools , Cardano.Scripts , Cardano.Transactions+ , Cardano.Utils , IPFS , NutLink build-depends: base >= 4.7 && < 5
src/Blockfrost/API.hs view
@@ -132,6 +132,11 @@ :> "submit" :> ReqBody '[CBOR] CBORString :> Post '[JSON] TxHash+ , _utils+ :: route+ :- "utils"+ :> Tag "Cardano » Utilities"+ :> ToServantApi UtilsAPI } deriving (Generic) type ServantBlockfrostAPI = ToServantApi BlockfrostAPI
src/Blockfrost/API/Cardano.hs view
@@ -14,6 +14,7 @@ , module Blockfrost.API.Cardano.Pools , module Blockfrost.API.Cardano.Scripts , module Blockfrost.API.Cardano.Transactions+ , module Blockfrost.API.Cardano.Utils ) where import Blockfrost.API.Cardano.Accounts@@ -27,3 +28,4 @@ import Blockfrost.API.Cardano.Pools import Blockfrost.API.Cardano.Scripts import Blockfrost.API.Cardano.Transactions+import Blockfrost.API.Cardano.Utils
src/Blockfrost/API/Cardano/Accounts.hs view
@@ -95,4 +95,15 @@ :> Pagination :> Sorting :> Get '[JSON] [Amount]+ , _accountAssociatedTotal+ :: route+ :- Summary "Detailed information about account associated addresses"+ :> Description "Obtain summed details about all addresses associated with a given account. \+ \Be careful, as an account could be part of a mangled address and does not \+ \necessarily mean the addresses are owned by user as the account."+ :> Capture "stake_address" Address+ :> "addresses"+ :> "total"+ :> Get '[JSON] AddressAssociatedTotal+ } deriving (Generic)
src/Blockfrost/API/Cardano/Addresses.hs view
@@ -22,6 +22,13 @@ :> Description "Obtain information about a specific address." :> Capture "address" Address :> Get '[JSON] AddressInfo+ , _addressInfoExtended+ :: route+ :- Summary "Specific address - extended"+ :> Description "Obtain extended information about a specific address."+ :> Capture "address" Address+ :> "extended"+ :> Get '[JSON] AddressInfoExtended , _addressDetails :: route :- Summary "Address details"
src/Blockfrost/API/Cardano/Pools.hs view
@@ -23,6 +23,14 @@ :> Pagination :> Sorting :> Get '[JSON] [PoolId]+ , _listPoolsExtended+ :: route+ :- Summary "List of stake pools with additional information"+ :> Description "List of registered stake pools with additional information."+ :> "extended"+ :> Pagination+ :> Sorting+ :> Get '[JSON] [Pool] , _listRetiredPools :: route :- Summary "List of retired stake pools"
+ src/Blockfrost/API/Cardano/Utils.hs view
@@ -0,0 +1,50 @@+-- | Cardano utility endpoints++{-# OPTIONS_HADDOCK hide #-}++module Blockfrost.API.Cardano.Utils+ where++import Data.Text+import Servant.API+import Servant.API.Generic++import Blockfrost.Types.Cardano.Utils+import Blockfrost.Types.Shared.CBOR++data UtilsAPI route =+ UtilsAPI+ {+ _deriveAddr+ :: route+ :- Summary "Derive an address"+ :> Description "Derive Shelley address from an xpub."+ :> "addresses"+ :> "xpub"+ :> Capture "xpub" Text+ :> Capture "role" Integer+ :> Capture "Index" Integer+ :> Get '[JSON] DerivedAddress++ , _txEvaluate+ :: route+ :- Summary "Submit a transaction for execution units evaluation"+ :> Description "Submit an already serialized transaction to evaluate \+ \how much execution units it requires."+ :> "txs"+ :> "evaluate"+ :> ReqBody '[CBOR] CBORString+ :> Post '[JSON] TxEval++ , _txEvaluateUTXOs+ :: route+ :- Summary "Submit a transaction for execution units evaluation (additional UTXO set)"+ :> Description "Submit a JSON payload with transaction CBOR and additional UTXO set \+ \to evaluate how much execution units it requires."+ :> "txs"+ :> "evaluate"+ :> "utxos"+ :> ReqBody '[JSON] TxEvalInput+ :> Post '[JSON] TxEval++ } deriving (Generic)
src/Blockfrost/Env.hs view
@@ -20,6 +20,7 @@ | Testnet | Preprod | Preview+ | Sanchonet | Localhost deriving (Eq, Read, Show, Ord, Generic) @@ -30,4 +31,4 @@ Nothing -> Left $ "Unknown environment: `" <> tEnv <> "`"- <> " expecting one of `ipfs`, `mainnet`, `testnet`, `localhost`"+ <> " expecting one of `ipfs`, `mainnet`, `testnet`, `preprod`, `preview`, `sanchonet`, `localhost`"
src/Blockfrost/Types/Cardano.hs view
@@ -12,6 +12,7 @@ , module Blockfrost.Types.Cardano.Pools , module Blockfrost.Types.Cardano.Scripts , module Blockfrost.Types.Cardano.Transactions+ , module Blockfrost.Types.Cardano.Utils ) where import Blockfrost.Types.Cardano.Accounts@@ -25,3 +26,4 @@ import Blockfrost.Types.Cardano.Pools import Blockfrost.Types.Cardano.Scripts import Blockfrost.Types.Cardano.Transactions+import Blockfrost.Types.Cardano.Utils
src/Blockfrost/Types/Cardano/Accounts.hs view
@@ -11,10 +11,12 @@ , AccountWithdrawal (..) , AccountMir (..) , AddressAssociated (..)+ , AddressAssociatedTotal (..) ) where import Blockfrost.Types.Shared import Deriving.Aeson+import qualified Money import Servant.Docs (ToSample (..), samples, singleSample) -- | Information about an account, identified by its stake address@@ -230,3 +232,36 @@ [ AddressAssociated "addr1qx2kd28nq8ac5prwg32hhvudlwggpgfp8utlyqxu6wqgz62f79qsdmm5dsknt9ecr5w468r9ey0fxwkdrwh08ly3tu9sy0f4qd" , AddressAssociated "addr1q8j55h253zcvl326sk5qdt2n8z7eghzspe0ekxgncr796s2f79qsdmm5dsknt9ecr5w468r9ey0fxwkdrwh08ly3tu9sjmd35m" ]++-- | Detailed information about account associated addresses+data AddressAssociatedTotal = AddressAssociatedTotal {+ _addressAssociatedTotalStakeAddress :: Address -- ^ Bech32 encoded address+ , _addressAssociatedTotalReceivedSum :: [Amount]+ , _addressAssociatedTotalSentSum :: [Amount]+ , _addressAssociatedTotalTxCount :: Integer -- ^ Count of all transactions for all addresses associated with the account+ } deriving stock (Show, Eq, Generic)+ deriving (FromJSON, ToJSON)+ via CustomJSON '[FieldLabelModifier '[StripPrefix "_addressAssociatedTotal", CamelToSnake]] AddressAssociatedTotal++instance ToSample AddressAssociatedTotal where+ toSamples = pure $ singleSample+ AddressAssociatedTotal+ { _addressAssociatedTotalStakeAddress = "stake1u9l5q5jwgelgagzyt6nuaasefgmn8pd25c8e9qpeprq0tdcp0e3uk"+ , _addressAssociatedTotalReceivedSum =+ [ AdaAmount 42000000+ , AssetAmount+ $ Money.mkSomeDiscrete+ "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e"+ unitScale+ 12+ ]+ , _addressAssociatedTotalSentSum =+ [ AdaAmount 123+ , AssetAmount+ $ Money.mkSomeDiscrete+ "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e"+ unitScale+ 1+ ]+ , _addressAssociatedTotalTxCount = 2+ }
src/Blockfrost/Types/Cardano/Addresses.hs view
@@ -2,6 +2,7 @@ module Blockfrost.Types.Cardano.Addresses ( AddressInfo (..)+ , AddressInfoExtended (..) , AddressType (..) , AddressDetails (..) , AddressUtxo (..)@@ -41,6 +42,38 @@ , _addressInfoStakeAddress = pure "stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7" , _addressInfoType = Shelley , _addressInfoScript = False+ }++-- | Information about Cardano address+data AddressInfoExtended = AddressInfoExtended+ { _addressInfoExtendedAddress :: Address -- ^ Bech32 encoded addresses+ , _addressInfoExtendedAmount :: [AmountExtended] -- ^ Lovelaces or tokens stored on this address+ , _addressInfoExtendedStakeAddress :: Maybe Address -- ^ Stake address that controls the key+ , _addressInfoExtendedType :: AddressType -- ^ Address era+ , _addressInfoExtendedScript :: Bool -- ^ True if this is a script address+ } deriving stock (Show, Eq, Generic)+ deriving (FromJSON, ToJSON)+ via CustomJSON '[FieldLabelModifier '[StripPrefix "_addressInfoExtended", CamelToSnake]] AddressInfoExtended++instance ToSample AddressInfoExtended where+ toSamples = pure $ singleSample+ AddressInfoExtended+ { _addressInfoExtendedAddress = "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz"+ , _addressInfoExtendedAmount =+ [ AdaAmountExtended 42000000+ , AssetAmountExtended+ { assetAmountExtendedDecimals = Nothing+ , assetAmountExtendedHasNftOnchainMetadata = True+ , assetAmountExtendedValue =+ Money.toSomeDiscrete+ (12 :: Money.Discrete'+ "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e"+ '(1,1))+ }+ ]+ , _addressInfoExtendedStakeAddress = pure "stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7"+ , _addressInfoExtendedType = Shelley+ , _addressInfoExtendedScript = False } -- | Type (era) of an address
src/Blockfrost/Types/Cardano/Assets.hs view
@@ -4,6 +4,9 @@ ( AssetInfo (..) , AssetDetails (..) , AssetOnChainMetadata (..)+ , MetadataMediaFile (..)+ , parseStandardMetadata+ , parseStandardMetadataInDetails , AssetMetadata (..) , AssetHistory (..) , AssetAction (..)@@ -12,9 +15,15 @@ ) where import Blockfrost.Types.Shared+import Data.Aeson (Value (..), FromJSON(parseJSON))+import Data.Aeson.Types (parseMaybe)+import Data.Aeson.KeyMap (fromList)+import Data.Char (toLower) import Data.Text (Text)+import qualified Data.Vector as V (singleton) import Deriving.Aeson import Servant.Docs (ToSample (..), samples, singleSample)+import Prelude hiding (String) -- | Asset information, result of listing assets data AssetInfo = AssetInfo@@ -41,23 +50,57 @@ } ] +-- CIP25 uses camelCase, so we need this to derive appropriate instances+data LowerHead++instance StringModifier LowerHead where+ getStringModifier (f:rest) = toLower f : rest+ getStringModifier [] = error "Empty field name"++-- | Additional media files (accordingly to CIP25 and CIP68)+data MetadataMediaFile = MetadataMediaFile+ { _metadataMediaFileName :: Maybe Text -- ^ file name+ , _metadataMediaFileMediaType :: Maybe Text -- ^ file MIME content-type+ , _metadataMediaFileSrc :: Maybe Text -- ^ URI of the media file+ }+ deriving stock (Show, Eq, Generic)+ deriving (FromJSON, ToJSON)+ via CustomJSON '[FieldLabelModifier '[StripPrefix "_metadataMediaFile", LowerHead]] MetadataMediaFile++instance ToSample MetadataMediaFile where+ toSamples = pure $ singleSample sampleAssetOnChainMetadataFile++sampleAssetOnChainMetadataFile :: MetadataMediaFile+sampleAssetOnChainMetadataFile =+ MetadataMediaFile+ { _metadataMediaFileName = Just "Detailed image"+ , _metadataMediaFileMediaType = Just "image/png"+ , _metadataMediaFileSrc = Just "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226"+ }+ -- | On-chain metadata stored in the minting transaction under label 721, -- community discussion around the standard ongoing at https://github.com/cardano-foundation/CIPs/pull/85 data AssetOnChainMetadata = AssetOnChainMetadata- { _assetOnChainMetadataName :: Text -- ^ Name of the asset- , _assetOnChainMetadataImage :: Text -- ^ URI of the associated asset- -- TODO: in schema has `additionalProperties: true`- -- so it can carry more arbitrary properties, keep as Value?+ { _assetOnChainMetadataName :: Maybe Text -- ^ Name of the asset+ , _assetOnChainMetadataDescription :: Maybe Text -- ^ Description of the asset+ , _assetOnChainMetadataImage :: Maybe Text -- ^ URI of the image, usually IPFS-based+ , _assetOnChainMetadataMediaType :: Maybe Text -- ^ image MIME content-type+ , _assetOnChainMetadataFiles :: Maybe [MetadataMediaFile] -- ^ Additional media files } deriving stock (Show, Eq, Generic) deriving (FromJSON, ToJSON)- via CustomJSON '[FieldLabelModifier '[StripPrefix "_assetOnChainMetadata", CamelToSnake]] AssetOnChainMetadata+ via CustomJSON '[FieldLabelModifier '[StripPrefix "_assetOnChainMetadata", LowerHead]] AssetOnChainMetadata instance ToSample AssetOnChainMetadata where- toSamples = pure $ singleSample- AssetOnChainMetadata- { _assetOnChainMetadataName = "My NFT token"- , _assetOnChainMetadataImage = "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226"+ toSamples = pure $ singleSample $ sampleAssetOnChainMetadata++sampleAssetOnChainMetadata :: AssetOnChainMetadata+sampleAssetOnChainMetadata = AssetOnChainMetadata+ { _assetOnChainMetadataName = Just "My NFT token"+ , _assetOnChainMetadataDescription = Just "A cool token for joy and fun."+ , _assetOnChainMetadataImage = Just "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226"+ , _assetOnChainMetadataMediaType = Just "image/png"+ , _assetOnChainMetadataFiles = Just [ sampleAssetOnChainMetadataFile ] } -- | Asset metadata obtained from Cardano token registry@@ -87,22 +130,43 @@ -- | Details of an asset data AssetDetails = AssetDetails- { _assetDetailsAsset :: Text -- ^ Hex-encoded asset full name- , _assetDetailsPolicyId :: PolicyId -- ^ Policy ID of the asset- , _assetDetailsAssetName :: Maybe Text -- ^ Hex-encoded asset name of the asset- , _assetDetailsFingerprint :: Text -- ^ CIP14 based user-facing fingerprint- , _assetDetailsQuantity :: Quantity -- ^ Current asset quantity- , _assetDetailsInitialMintTxHash :: TxHash -- ^ ID of the initial minting transaction- , _assetDetailsMintOrBurnCount :: Integer -- ^ Count of mint and burn transactions- , _assetDetailsOnchainMetadata :: Maybe AssetOnChainMetadata- -- ^ On-chain metadata stored in the minting transaction under label 721,- -- community discussion around the standard ongoing at https://github.com/cardano-foundation/CIPs/pull/85- , _assetDetailsMetadata :: Maybe AssetMetadata+ { _assetDetailsAsset :: Text -- ^ Hex-encoded asset full name+ , _assetDetailsPolicyId :: PolicyId -- ^ Policy ID of the asset+ , _assetDetailsAssetName :: Maybe Text -- ^ Hex-encoded asset name of the asset+ , _assetDetailsFingerprint :: Text -- ^ CIP14 based user-facing fingerprint+ , _assetDetailsQuantity :: Quantity -- ^ Current asset quantity+ , _assetDetailsInitialMintTxHash :: TxHash -- ^ ID of the initial minting transaction+ , _assetDetailsMintOrBurnCount :: Integer -- ^ Count of mint and burn transactions+ , _assetDetailsOnchainMetadataValue :: Maybe Value+ -- ^ On-chain metadata stored in the minting transaction under label 721 for CIP25+ -- standard or in the first element in the specific constructor in a reference token's+ -- datum for CIP68 standard. In both cases this part is represenatable as JSON+ -- and might be arbitrary, so we keep it as @Value@+ , _assetDetailsOnchainStandardMetadata :: Maybe AssetOnChainMetadata+ -- ^ Some bits of on-chain metadata are considered being "standard" (like name, image and so on).+ -- If they are found in the metadata JSON bundle, this field will contain them.+ , _assetDetailsMetadata :: Maybe AssetMetadata+ , _assetDetailsOnchainMetadataExtra :: Maybe Text+ -- ^ CIP68 extra metadata plutus data (CBOR-encoded) } deriving stock (Show, Eq, Generic) deriving (FromJSON, ToJSON)- via CustomJSON '[FieldLabelModifier '[StripPrefix "_assetDetails", CamelToSnake]] AssetDetails+ via CustomJSON '[ FieldLabelModifier+ '[ StripPrefix "_assetDetails"+ , CamelToSnake+ , Rename "onchain_metadata_value" "onchain_metadata"+ ]+ ] AssetDetails +parseStandardMetadata :: Maybe Value -> Maybe AssetOnChainMetadata+parseStandardMetadata mbValue = mbValue >>= parseMaybe parseJSON++parseStandardMetadataInDetails :: AssetDetails -> AssetDetails+parseStandardMetadataInDetails+ details@AssetDetails{_assetDetailsOnchainMetadataValue = mbValue} =+ details { _assetDetailsOnchainStandardMetadata = parseStandardMetadata mbValue}++ instance ToSample AssetDetails where toSamples = pure $ singleSample AssetDetails@@ -113,11 +177,30 @@ , _assetDetailsQuantity = 12000 , _assetDetailsInitialMintTxHash = "6804edf9712d2b619edb6ac86861fe93a730693183a262b165fcc1ba1bc99cad" , _assetDetailsMintOrBurnCount = 1- , _assetDetailsOnchainMetadata = pure $- AssetOnChainMetadata- { _assetOnChainMetadataName = "My NFT token"- , _assetOnChainMetadataImage = "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226"- }+ , _assetDetailsOnchainMetadataValue = Just $+ (+ Object+ (fromList+ [ ("id",Number 630.0)+ , ("image",String "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226")+ , ("mediaType",String "image/png")+ , ("name",String "My NFT token")+ , ("files", Array+ ( V.singleton+ (Object+ (fromList+ [ ("name", String "Detailed image")+ , ("mediaType", String "image/png")+ , ("src", String "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226")+ ]+ )+ )+ )+ )+ ]+ )+ )+ , _assetDetailsOnchainStandardMetadata = pure sampleAssetOnChainMetadata , _assetDetailsMetadata = pure $ AssetMetadata { _assetMetadataName = "nutcoin"@@ -127,6 +210,7 @@ , _assetMetadataLogo = pure "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" , _assetMetadataDecimals = pure 6 }+ , _assetDetailsOnchainMetadataExtra = Just "9f01582430303030303030302d303030302d303030302d303030302d3030303030303030303132334d47616d65585f4578616d706c65020203454c6576656c413145506f7765724231304553706565644131ff" } -- | Action of the asset.
src/Blockfrost/Types/Cardano/Pools.hs view
@@ -1,7 +1,8 @@ -- | Cardano Pools reponses module Blockfrost.Types.Cardano.Pools- ( PoolEpoch (..)+ ( Pool (..)+ , PoolEpoch (..) , PoolInfo (..) , PoolHistory (..) , PoolMetadata (..)@@ -18,6 +19,39 @@ import Servant.Docs (ToSample (..), samples, singleSample) import Blockfrost.Types.Shared++-- | Extended pool info+data Pool = Pool+ { _poolPoolId :: PoolId -- ^ Bech32 encoded pool ID+ , _poolHex :: Text -- ^ Hexadecimal pool ID.+ , _poolActiveStake :: Lovelaces -- ^ Active delegated amount+ , _poolLiveStake :: Lovelaces -- ^ Currently delegated amount+ }+ deriving stock (Show, Eq, Generic)+ deriving (FromJSON, ToJSON)+ via CustomJSON '[FieldLabelModifier '[StripPrefix "_pool", CamelToSnake]] Pool++instance ToSample Pool where+ toSamples = pure $ samples+ [ Pool+ { _poolPoolId = "pool19u64770wqp6s95gkajc8udheske5e6ljmpq33awxk326zjaza0q"+ , _poolHex = "2f355f79ee007502d116ecb07e36f985b34cebf2d84118f5c6b455a1"+ , _poolActiveStake = 1541200000+ , _poolLiveStake = 1541400000+ }+ , Pool+ { _poolPoolId = "pool1dvla4zq98hpvacv20snndupjrqhuc79zl6gjap565nku6et5zdx"+ , _poolHex = "6b3fda88053dc2cee18a7c2736f032182fcc78a2fe912e869aa4edcd"+ , _poolActiveStake = 22200000+ , _poolLiveStake = 48955550+ }+ , Pool+ { _poolPoolId = "pool1wvccajt4eugjtf3k0ja3exjqdj7t8egsujwhcw4tzj4rzsxzw5w"+ , _poolHex = "73318ec975cf1125a6367cbb1c9a406cbcb3e510e49d7c3aab14aa31"+ , _poolActiveStake = 9989541215+ , _poolLiveStake = 168445464878+ }+ ] -- | Retirement epoch for pool data PoolEpoch = PoolEpoch
+ src/Blockfrost/Types/Cardano/Utils.hs view
@@ -0,0 +1,136 @@+{-# LANGUAGE RecordWildCards #-}+-- | Cardano Utils responses++module Blockfrost.Types.Cardano.Utils+ ( DerivedAddress (..)+ , TxEval (..)+ , TxEvalBudget (..)+ , TxEvalResult (..)+ , evalSample+ , resultSample+ , TxEvalInput (..)+ ) where++import Data.Aeson+ ( FromJSON (..)+ , ToJSON (..)+ , Value (Array)+ , object+ , withObject+ , (.:)+ , (.:?)+ , (.=)+ )++import Blockfrost.Types.Shared.CBOR (CBORString(..))+import Data.Text (Text)+import Deriving.Aeson+import Servant.Docs (ToSample (..), singleSample)+import qualified Data.Char++-- | 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"+ }++data TxEvalBudget = TxEvalBudget+ { _txEvalBudgetMemory :: Integer -- ^ Memory budget+ , _txEvalBudgetCPU :: Integer -- ^ CPU budget+ }+ deriving stock (Show, Eq, Generic)+ deriving (FromJSON, ToJSON)+ via CustomJSON '[FieldLabelModifier '[StripPrefix "_txEvalBudget", CamelToSnake]] TxEvalBudget++instance ToSample TxEvalBudget where+ toSamples = pure $ singleSample+ TxEvalBudget+ { _txEvalBudgetMemory = 1700+ , _txEvalBudgetCPU = 476468+ }++-- | Transaction evaluation result+data TxEvalResult = TxEvalResult+ { _txEvalResultValidator :: Text -- ^ Redeemer pointer+ , _txEvalResultBudget :: TxEvalBudget -- ^ Budget+ }+ deriving stock (Show, Eq, Generic)+ deriving (FromJSON, ToJSON)+ via CustomJSON '[FieldLabelModifier '[StripPrefix "_txEvalResult", CamelToSnake]] TxEvalResult++resultSample :: TxEvalResult+resultSample =+ TxEvalResult+ { _txEvalResultValidator = "spend:0"+ , _txEvalResultBudget =+ TxEvalBudget+ { _txEvalBudgetMemory = 1700+ , _txEvalBudgetCPU = 476468+ }+ }++instance ToSample TxEvalResult where+ toSamples = pure $ singleSample resultSample++-- | Transaction evaluation result wrapper+newtype TxEval = TxEval { _txEvalResult :: [TxEvalResult] }+ deriving stock (Show, Eq, Generic)++instance ToJSON TxEval where+ toJSON TxEval{..} =+ object+ [ "jsonrpc" .= ("2.0" :: Text)+ , "method" .= ("evaluateTransaction" :: Text)+ , "result" .= toJSON _txEvalResult+ ]++instance FromJSON TxEval where+ parseJSON = withObject "txEval" $ \o -> do+ (mErr :: Maybe Value) <- o .:? "error"+ case mErr of+ Just err -> fail $ show err+ Nothing -> pure ()++ r <- o .: "result"+ TxEval <$> parseJSON r++evalSample :: TxEval+evalSample = TxEval (pure resultSample)++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+ }
@@ -1,6 +1,7 @@ -- | Amount sum type {-# LANGUAGE NumericUnderscores #-}+{-# LANGUAGE RecordWildCards #-} module Blockfrost.Types.Shared.Amount where@@ -31,7 +32,9 @@ -- | SomeDiscrete values always use scale of 1 unitScale :: Money.Scale-unitScale = let (Just s) = Money.scaleFromRational 1 in s+unitScale = case Money.scaleFromRational 1 of+ Just s -> s+ Nothing -> error "Money.scaleFromRational impossible" instance ToJSON Money.SomeDiscrete where toJSON sd =@@ -77,3 +80,59 @@ "6804edf9712d2b619edb6ac86861fe93a730693183a262b165fcc1ba1bc99cad" '(1,1)) ]++-- | Like @Amount@, extended with @decimals` and `has_nft_onchain_metadata`+data AmountExtended =+ AdaAmountExtended Lovelaces+ | AssetAmountExtended+ { assetAmountExtendedDecimals :: Maybe Int+ , assetAmountExtendedHasNftOnchainMetadata :: Bool+ , assetAmountExtendedValue :: Money.SomeDiscrete+ }+ deriving (Eq, Show, Ord, Generic)++instance ToJSON AmountExtended where+ toJSON (AdaAmountExtended lovelaces) =+ object [ "unit" .= ("lovelace" :: String)+ , "quantity" .= toJSON lovelaces+ , "decimals" .= (6 :: Int)+ , "has_nft_onchain_metadata" .= False+ ]+ toJSON (AssetAmountExtended {..}) =+ object [ "unit" .= Money.someDiscreteCurrency assetAmountExtendedValue+ , "quantity" .= show (Money.someDiscreteAmount assetAmountExtendedValue)+ , "decimals" .= assetAmountExtendedDecimals+ , "has_nft_onchain_metadata" .= assetAmountExtendedHasNftOnchainMetadata+ ]++instance FromJSON AmountExtended where+ parseJSON x@(Object o) = do+ (u :: String) <- o .: "unit"+ v <- o .: "quantity"+ assetAmountExtendedDecimals+ <- o .: "decimals"+ assetAmountExtendedHasNftOnchainMetadata+ <- o .: "has_nft_onchain_metadata"+ case u of+ "lovelace" -> AdaAmountExtended <$> parseJSON v+ _ -> do+ assetAmountExtendedValue <- parseJSON x+ pure AssetAmountExtended{..}++ parseJSON other = fail $ "Amount expecting object, got" ++ show other++instance ToSample AmountExtended where+ toSamples = pure $ samples+ [ AdaAmountExtended 42000000+ , AssetAmountExtended+ { assetAmountExtendedDecimals = Nothing+ , assetAmountExtendedHasNftOnchainMetadata = True+ , assetAmountExtendedValue =+ Money.toSomeDiscrete+ (12 :: Money.Discrete'+ "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e"+ '(1,1))+ }+ ]++
@@ -3,16 +3,36 @@ module Blockfrost.Types.Shared.CBOR where +import Data.Aeson (FromJSON (..), ToJSON (..), withText) import Data.ByteString.Lazy (ByteString) import Servant.API (Accept (..), MimeRender (..), MimeUnrender (..)) import Servant.Docs (ToSample (..), singleSample) +import qualified Data.ByteString.Char8+import qualified Data.ByteString.Lazy+import qualified Data.Text+ data CBOR -- | Wrapper for CBOR encoded `ByteString`s -- used for submitting a transaction newtype CBORString = CBORString ByteString deriving stock (Eq, Show)++instance ToJSON CBORString where+ toJSON (CBORString bs) =+ toJSON+ . Data.Text.pack+ $ Data.ByteString.Char8.unpack+ $ Data.ByteString.Lazy.toStrict bs++instance FromJSON CBORString where+ parseJSON = withText "CBORString" $ \t ->+ pure+ $ CBORString+ <$> Data.ByteString.Lazy.fromStrict+ . Data.ByteString.Char8.pack+ $ Data.Text.unpack t instance Accept CBOR where contentType = pure "application/cbor"
src/Blockfrost/Util/LensRules.hs view
@@ -17,7 +17,7 @@ modNamer namer dname fnames fname = map fixDefName (namer (fixTypeName dname) fnames fname) - fixDefName (MethodName cname mname)=MethodName cname (fixName mname)+ fixDefName (MethodName cname mname) = MethodName cname (fixName mname) fixDefName (TopName name) = TopName (fixName name) fixTypeName = mkName . fixTypeName' . nameBase
test/Cardano/Accounts.hs view
@@ -57,6 +57,11 @@ `shouldBe` Right accountAssociatedAddressesExpected + it "parses account associated addresses total sample" $ do+ eitherDecode accountAssociatedAddressesTotalSample+ `shouldBe`+ Right accountAssociatedAddressesTotalExpected+ accountSample = [r| { "stake_address": "stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7",@@ -300,3 +305,52 @@ [ AddressAssociated "addr1qx2kd28nq8ac5prwg32hhvudlwggpgfp8utlyqxu6wqgz62f79qsdmm5dsknt9ecr5w468r9ey0fxwkdrwh08ly3tu9sy0f4qd" , AddressAssociated "addr1q8j55h253zcvl326sk5qdt2n8z7eghzspe0ekxgncr796s2f79qsdmm5dsknt9ecr5w468r9ey0fxwkdrwh08ly3tu9sjmd35m" ]++accountAssociatedAddressesTotalSample = [r|+{+ "stake_address": "stake1u9l5q5jwgelgagzyt6nuaasefgmn8pd25c8e9qpeprq0tdcp0e3uk",+ "received_sum": [+ {+ "unit": "lovelace",+ "quantity": "42000000"+ },+ {+ "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",+ "quantity": "12"+ }+ ],+ "sent_sum": [+ {+ "unit": "lovelace",+ "quantity": "42000000"+ },+ {+ "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",+ "quantity": "12"+ }+ ],+ "tx_count": 12+}+|]++accountAssociatedAddressesTotalExpected =+ AddressAssociatedTotal+ { _addressAssociatedTotalStakeAddress = "stake1u9l5q5jwgelgagzyt6nuaasefgmn8pd25c8e9qpeprq0tdcp0e3uk"+ , _addressAssociatedTotalReceivedSum =+ [ AdaAmount 42000000+ , AssetAmount+ $ Money.mkSomeDiscrete+ "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e"+ unitScale+ 12+ ]+ , _addressAssociatedTotalSentSum =+ [ AdaAmount 42000000+ , AssetAmount+ $ Money.mkSomeDiscrete+ "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e"+ unitScale+ 12+ ]+ , _addressAssociatedTotalTxCount = 12+ }
test/Cardano/Addresses.hs view
@@ -22,6 +22,11 @@ `shouldBe` Right addressInfoExpected + it "parses address info extended sample" $ do+ eitherDecode addressInfoExtendedSample+ `shouldBe`+ Right addressInfoExtendedExpected+ it "parses address info sample" $ do eitherDecode addressInfoSample `shouldBe`@@ -76,6 +81,49 @@ , _addressInfoType = Shelley , _addressInfoScript = False }++addressInfoExtendedSample = [r|+{+ "address": "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz",+ "amount": [+ {+ "unit": "lovelace",+ "quantity": "42000000",+ "decimals": 6,+ "has_nft_onchain_metadata": false+ },+ {+ "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",+ "quantity": "12",+ "decimals": null,+ "has_nft_onchain_metadata": true+ }+ ],+ "stake_address": "stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7",+ "type": "shelley",+ "script": false+}+|]++addressInfoExtendedExpected =+ AddressInfoExtended+ { _addressInfoExtendedAddress = "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz"+ , _addressInfoExtendedAmount =+ [ AdaAmountExtended 42000000+ , AssetAmountExtended+ { assetAmountExtendedDecimals = Nothing+ , assetAmountExtendedHasNftOnchainMetadata = True+ , assetAmountExtendedValue =+ Money.mkSomeDiscrete+ "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e"+ unitScale+ 12+ }+ ]+ , _addressInfoExtendedStakeAddress = pure "stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7"+ , _addressInfoExtendedType = Shelley+ , _addressInfoExtendedScript = False+ } addressDetailsSample = [r| {
test/Cardano/Assets.hs view
@@ -6,7 +6,9 @@ module Cardano.Assets where -import Data.Aeson (decode, eitherDecode, encode)+import Data.Aeson (Value (..), decode, eitherDecode, encode)+import Data.Aeson.KeyMap (fromList)+import qualified Data.Vector as V (singleton) import Data.Text (Text) import qualified Money import Test.Hspec@@ -23,7 +25,7 @@ Right assetInfoExpected it "parses assets details sample" $ do- eitherDecode assetDetailsSample+ (parseStandardMetadataInDetails <$> eitherDecode assetDetailsSample) `shouldBe` Right assetDetailsExpected @@ -85,8 +87,19 @@ "initial_mint_tx_hash": "6804edf9712d2b619edb6ac86861fe93a730693183a262b165fcc1ba1bc99cad", "mint_or_burn_count": 1, "onchain_metadata": {+ "id": 630.0, "name": "My NFT token",- "image": "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226"+ "description": "A cool token for joy and fun.",+ "image": "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226",+ "mediaType": "image/png",+ "files" :+ [+ {+ "mediaType": "image/png",+ "name": "Detailed image",+ "src": "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226"+ }+ ] }, "metadata": { "name": "nutcoin",@@ -95,7 +108,8 @@ "url": "https://www.stakenuts.com/", "logo": "iVBORw0KGgoAAAANSUhEUgAAADAAAAAoCAYAAAC4h3lxAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAAB3RJTUUH5QITCDUPjqwFHwAAB9xJREFUWMPVWXtsU9cZ/8499/r6dZ3E9rUdO7ZDEgglFWO8KaOsJW0pCLRKrN1AqqYVkqoqrYo0ja7bpElru1WairStFKY9WzaE1E1tx+jokKqwtqFNyhKahEJJyJNgJ37E9r1+3HvO/sFR4vhx7SBtfH/F3/l93/f7ne/4PBxEKYU72dj/ZfH772v1TU+HtqbTaX8wOO01GPQpRVH7JEm+vGHDuq6z7/8jUSoHKtaBKkEUFUXdajDy1hUrmrs6zn/wWS7m7pZVjMUirKGUTnzc+e9xLcTrPPVfZzDz06Sc2lyQGEIyAPzT7Xa+dvE/3e+XLaCxoflHsVj8MAAYs74aa/WHoenwvpkZKeFy2Z5NJlOPUkqXZccFwSSrKjlyffjLH+TL6XTUGTGL/6hklD3ldIrj2M5MRmkLBMcvaRLQ1Nj88sxM/HCBfMP+eu/OYGDqe6l0WmpoqJ/88upgrU7HrQNA/cFg6MlkKiLlBtVUO40cx54BgHvLIT/HJLvdeqh/4NKxogKWN7fsCoUi7xTLxLJ4vLq6ak//wKVOrdXtttrTDMPsqJA8AAAwDErdu3VL3alTf5ma9eWCpoKhn5dKpCiqJxicPucQPVu0FHaInn35yHMcKwPAa4SQ3QCwFgDWUko3qSr5vqqSgTypuEg4Mo/zvA74/Y0rZSnZU8akSHV17k2fXfy0txjI5224kEym1s/1EUI7LBbztweHrkzkizn49LP6U6feepFSeggAQK/n04SQZ8bGrxdeQjZrbRvGzLH5hcibRqOhPplMfS1fIY5jz4xPDBdcGggho2h3z9sOLRazdG3wqp9SMgUlzGZ17SSEPsRx7J8CwfGu3PF57WhqqjfN/VxVJUxKUrIdITAXKpDJKFscosdfaFy0u+/K9aXTmXe0kAcAmA5Nng5Hbj6Tj/wCAYFAcN7uEY3GXGazMSHLqVVFapgBoMPna9yqhRAAgCTJMa3YUjZPgNFkSlWYx5eUkx+0tKx83V3rF+cVYJjruWCe133DIXqMmrNrFSDabRcWkywYmG5XFOW6aHcfb9324CoAgMmbo9MIoXkneCajiAihV/c/8eSiBSw4BxyiZxQA6m7H7FBKT2CMn2MY5jFFUX6ZO+5w2j8aHZ7YH40FByrJD5DnHGAY5uTtIA8AgBDaR4F2Yxb3WizCgmtA4ObUPSazodduqz3Suu0hf0U1cjvgdNSJ1dWWveFwdDUAtAiC2Uopdcdi8c9Zlh3GmDGl05mtAKAvo47EcdwThJCjqqpWFxALlNITomg73tff21GRAJez7iVK4WGGYfoJIQduBsbm7UrLm1ueCoUiv65kpiilw1ZbzcFoZOYoIcRTAn6eYZgXJm+Oni+Vd3YJbdyweSch9HlK6SpVVfcyDDq7Yf3m2XPBIXraKyV/a4b9UkLawbLsZgB4rwR8CyGkw13r+5fX27BckwBAEJ47oKpk8+DgUIdod7fV1vqOAMDrlZLPmqKoB+rrvXIgOP6w0WjYy3Ls5RL4bUk52bVm9fqnCk7M3CXU2ND8+MxM7BcIIftiyRYyntcdHh0bmr0wfmXl6p2SJB2KRmP3l4j7zejYUFtRAQAAgslm1Bv4nyGEDpYiIwjmjw0G/RjP866JiclNqqqWfKLq9fyZkdHBBXcnl9O71GDgD8bj0ncRQqZ8sRgzL9yYHH2pqICsOUTPLgA4CXNeZFmzWIS/YhYfjUZmvqPjuceSckrz25pS2h2cmlhbaBwhzr6kfsnL8Xhif55YYFl23Y3Jkdl7EVMoUSA4/q6qqNsBIPd11e52u45FwtG3CSH7yiEPAGC1Vt9dXGBmanDoygFLlbAjtzZCCMyC6VeaOpA1l9N7l1kwtauKaozHE28YTQaQpeR7+TqjxXheR0fHhhgt2CX1S3clEtKC16HL5djYe+niBU0CcmYA2W21/Qih5ZqDcoxlMZ24MaJJAABA87IVJ8Lh6N65Pr1B/+LIyLUfAhRZQvnM6ah7ZDHkAQB0vK6/HHxNTc2ruT5Zkldn/y5LACFk+2LIAwAwCGl6yGSt88KHXbmrBCHkqEgAz+vWLFZALJb4qNwYhFDhCSknkSwnQ4sVgDFeWg7+gQe2r1tAmkGTFQlACHWVg89nhJA9ot3dphV/eeCLp/Pw6K5IQP0S39uLFXCLwDG7zf1cKZxD9LSlUunHc/12u/2t2Vzl/rzu8zb8PZlM7bwdQgDgPK/nX2nddt+53//ht3LW2dS0fF0iLj2vquojuQFmwXRucPBKa8UCmpe1iOFwpAsAfLdJBFBKwVIlXJ2JxqKCxbwyHkvoCkAlv9/71U+7Oq+UJWDZ0hViJBL1cRynbNq0sSeeiPl6ei4NqIqq6TSmlB7X6bjuTEY5pgWfzwxGPZhMpt39/b3vzvWXFGCzulZjjM/DrauDwcAr8bjcgzGjZUuVBMH8k2uDX7wCAFDr8n2LEPI7SqmhTP6SzVbz6MDlz0/nDpT8EmOM22HOvUeWU2wp8iyLgRL6hk7Hrc2SBwC4MTlykmXZRozxn00mbVcphNA5jJmV+chr6oDd5l6jN/A/TqfSuwEAGITGMIsvGo3GTwTB3Dc2NjGSxdZYq4VIOOoNBANnKE0XPXE3brjHOTQ08k2MmVZOxzVJCbkFIQSCYEphzPaFQuGzTpfjb319PZ8UFXin/5OvrHPg/9HueAH/BSUqOuNZm4fyAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIxLTAyLTE5VDA4OjUyOjI1KzAwOjAwCmFGlgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMS0wMi0xOVQwODo1MjoyMyswMDowMBjsyxAAAAAASUVORK5CYII=", "decimals": 6- }+ },+ "onchain_metadata_extra": "9f01582430303030303030302d303030302d303030302d303030302d3030303030303030303132334d47616d65585f4578616d706c65020203454c6576656c413145506f7765724231304553706565644131ff" } |] @@ -108,11 +122,45 @@ , _assetDetailsQuantity = 12000 , _assetDetailsInitialMintTxHash = "6804edf9712d2b619edb6ac86861fe93a730693183a262b165fcc1ba1bc99cad" , _assetDetailsMintOrBurnCount = 1- , _assetDetailsOnchainMetadata = pure $+ , _assetDetailsOnchainMetadataValue = Just $+ (+ Object+ (fromList+ [ ("id",Number 630.0)+ , ("image",String "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226")+ , ("mediaType",String "image/png")+ , ("name",String "My NFT token")+ , ("description",String "A cool token for joy and fun.")+ , ("files", Array+ ( V.singleton+ (Object+ (fromList+ [ ("name", String "Detailed image")+ , ("mediaType", String "image/png")+ , ("src", String "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226")+ ]+ )+ )+ )+ )+ ]+ )+ )+ , _assetDetailsOnchainStandardMetadata = pure $ AssetOnChainMetadata- { _assetOnChainMetadataName = "My NFT token"- , _assetOnChainMetadataImage = "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226"- }+ { _assetOnChainMetadataName = Just "My NFT token"+ , _assetOnChainMetadataDescription = Just "A cool token for joy and fun."+ , _assetOnChainMetadataImage = Just "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226"+ , _assetOnChainMetadataMediaType = Just "image/png"+ , _assetOnChainMetadataFiles = Just+ [+ MetadataMediaFile+ { _metadataMediaFileName = Just "Detailed image"+ , _metadataMediaFileMediaType = Just "image/png"+ , _metadataMediaFileSrc = Just "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226"+ }+ ]+ } , _assetDetailsMetadata = pure $ AssetMetadata { _assetMetadataName = "nutcoin"@@ -122,6 +170,7 @@ , _assetMetadataLogo = pure "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" , _assetMetadataDecimals = pure 6 }+ , _assetDetailsOnchainMetadataExtra = Just "9f01582430303030303030302d303030302d303030302d303030302d3030303030303030303132334d47616d65585f4578616d706c65020203454c6576656c413145506f7765724231304553706565644131ff" } assetHistorySample = [r|
test/Cardano/Pools.hs view
@@ -17,6 +17,11 @@ spec_pools :: Spec spec_pools = do+ it "parses pools sample" $ do+ eitherDecode poolsSample+ `shouldBe`+ Right poolsExpected+ it "parses pool epoch sample" $ do eitherDecode poolEpochSample `shouldBe`@@ -56,6 +61,51 @@ eitherDecode poolUpdatesSample `shouldBe` Right poolUpdatesExpected++poolsSample = [r|+[+ {+ "pool_id": "pool19u64770wqp6s95gkajc8udheske5e6ljmpq33awxk326zjaza0q",+ "hex": "2f355f79ee007502d116ecb07e36f985b34cebf2d84118f5c6b455a1",+ "active_stake": "1541200000",+ "live_stake": "1541400000"+ },+ {+ "pool_id": "pool1dvla4zq98hpvacv20snndupjrqhuc79zl6gjap565nku6et5zdx",+ "hex": "6b3fda88053dc2cee18a7c2736f032182fcc78a2fe912e869aa4edcd",+ "active_stake": "22200000",+ "live_stake": "48955550"+ },+ {+ "pool_id": "pool1wvccajt4eugjtf3k0ja3exjqdj7t8egsujwhcw4tzj4rzsxzw5w",+ "hex": "73318ec975cf1125a6367cbb1c9a406cbcb3e510e49d7c3aab14aa31",+ "active_stake": "9989541215",+ "live_stake": "168445464878"+ }+]+|]++poolsExpected =+ [ Pool+ { _poolPoolId = "pool19u64770wqp6s95gkajc8udheske5e6ljmpq33awxk326zjaza0q"+ , _poolHex = "2f355f79ee007502d116ecb07e36f985b34cebf2d84118f5c6b455a1"+ , _poolActiveStake = 1541200000+ , _poolLiveStake = 1541400000+ }+ , Pool+ { _poolPoolId = "pool1dvla4zq98hpvacv20snndupjrqhuc79zl6gjap565nku6et5zdx"+ , _poolHex = "6b3fda88053dc2cee18a7c2736f032182fcc78a2fe912e869aa4edcd"+ , _poolActiveStake = 22200000+ , _poolLiveStake = 48955550+ }+ , Pool+ { _poolPoolId = "pool1wvccajt4eugjtf3k0ja3exjqdj7t8egsujwhcw4tzj4rzsxzw5w"+ , _poolHex = "73318ec975cf1125a6367cbb1c9a406cbcb3e510e49d7c3aab14aa31"+ , _poolActiveStake = 9989541215+ , _poolLiveStake = 168445464878+ }+ ]+ poolEpochSample = [r| [
+ test/Cardano/Utils.hs view
@@ -0,0 +1,179 @@+{-# LANGUAGE NumericUnderscores #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++module Cardano.Utils+ where++import Data.Aeson (decode, eitherDecode, encode, object, (.=), Value (Array))+import qualified Data.Either+import Data.Text (Text)+import qualified Money+import Test.Hspec+import Test.Tasty.Hspec+import Text.RawString.QQ++import Blockfrost.Types++spec_scripts :: Spec+spec_scripts = do+ it "parses derived address sample" $ do+ eitherDecode derivedAddressSample+ `shouldBe`+ Right derivedAddressExpected++ it "parses tx eval sample" $ do+ eitherDecode txEvalSample+ `shouldBe`+ Right txEvalExpected++ it "fails to parse tx eval error" $ do+ eitherDecode txEvalErrorSample+ `shouldSatisfy`+ (Data.Either.isLeft :: Either String TxEval -> Bool)++ it "parses tx eval input sample" $ do+ eitherDecode txEvalInputSample+ `shouldBe`+ Right txEvalInputExpected++derivedAddressSample = [r|+{+ "xpub": "d507c8f866691bd96e131334c355188b1a1d0b2fa0ab11545075aab332d77d9eb19657ad13ee581b56b0f8d744d66ca356b93d42fe176b3de007d53e9c4c4e7a",+ "role": 0,+ "index": 0,+ "address": "addr1q90sqnljxky88s0jsnps48jd872p7znzwym0jpzqnax6qs5nfrlkaatu28n0qzmqh7f2cpksxhpc9jefx3wrl0a2wu8q5amen7"+}+|]++derivedAddressExpected =+ DerivedAddress+ { _derivedAddressXpub = "d507c8f866691bd96e131334c355188b1a1d0b2fa0ab11545075aab332d77d9eb19657ad13ee581b56b0f8d744d66ca356b93d42fe176b3de007d53e9c4c4e7a"+ , _derivedAddressRole = 0+ , _derivedAddressIndex = 0+ , _derivedAddressAddress = "addr1q90sqnljxky88s0jsnps48jd872p7znzwym0jpzqnax6qs5nfrlkaatu28n0qzmqh7f2cpksxhpc9jefx3wrl0a2wu8q5amen7"+ }++txEvalSample = [r|+{+ "jsonrpc": "2.0",+ "method": "evaluateTransaction",+ "result": [{+ "validator": "spend:0",+ "budget": {+ "memory": 1700,+ "cpu": 476468+ }+ }]+}+|]++txEvalExpected = evalSample++-- Stolen from+-- https://github.com/CardanoSolutions/ogmios/blob/master/server/test/vectors/EvaluateTransactionResponse/000.json+-- Mozilla Public License 2.0+txEvalErrorSample = [r|+{+ "jsonrpc": "2.0",+ "method": "evaluateTransaction",+ "error": {+ "code": 3010,+ "message": "Some scripts of the transactions terminated with error(s).",+ "data": [+ {+ "validator": "spend:4",+ "error": {+ "code": 3011,+ "message": "An associated script witness is missing. Indeed, any script used in a transaction (when spending, minting, withdrawing or publishing certificates) must be provided in full with the transaction. Scripts must therefore be added either to the witness set or provided as a reference inputs should you use Plutus V2+ and a format from Babbage and beyond.",+ "data": {+ "missingScripts": [+ "certificate:3"+ ]+ }+ }+ },+ {+ "validator": "mint:0",+ "error": {+ "code": 3011,+ "message": "An associated script witness is missing. Indeed, any script used in a transaction (when spending, minting, withdrawing or publishing certificates) must be provided in full with the transaction. Scripts must therefore be added either to the witness set or provided as a reference inputs should you use Plutus V2+ and a format from Babbage and beyond.",+ "data": {+ "missingScripts": [+ "certificate:11"+ ]+ }+ }+ },+ {+ "validator": "mint:3",+ "error": {+ "code": 3011,+ "message": "An associated script witness is missing. Indeed, any script used in a transaction (when spending, minting, withdrawing or publishing certificates) must be provided in full with the transaction. Scripts must therefore be added either to the witness set or provided as a reference inputs should you use Plutus V2+ and a format from Babbage and beyond.",+ "data": {+ "missingScripts": [+ "withdrawal:7"+ ]+ }+ }+ },+ {+ "validator": "mint:7",+ "error": {+ "code": 3011,+ "message": "An associated script witness is missing. Indeed, any script used in a transaction (when spending, minting, withdrawing or publishing certificates) must be provided in full with the transaction. Scripts must therefore be added either to the witness set or provided as a reference inputs should you use Plutus V2+ and a format from Babbage and beyond.",+ "data": {+ "missingScripts": [+ "mint:4"+ ]+ }+ }+ },+ {+ "validator": "mint:11",+ "error": {+ "code": 3117,+ "message": "The transaction contains unknown UTxO references as inputs. This can happen if the inputs you're trying to spend have already been spent, or if you've simply referred to non-existing UTxO altogether. The field 'data.unknownOutputReferences' indicates all unknown inputs.",+ "data": {+ "unknownOutputReferences": [+ {+ "transaction": {+ "id": "a10897006ca78f6ce87fc6e2b139d92a896de01d62fe01f4fd0eccc6a10075c1"+ },+ "index": 14+ }+ ]+ }+ }+ },+ {+ "validator": "certificate:2",+ "error": {+ "code": 3011,+ "message": "An associated script witness is missing. Indeed, any script used in a transaction (when spending, minting, withdrawing or publishing certificates) must be provided in full with the transaction. Scripts must therefore be added either to the witness set or provided as a reference inputs should you use Plutus V2+ and a format from Babbage and beyond.",+ "data": {+ "missingScripts": [+ "withdrawal:2"+ ]+ }+ }+ }+ ]+ },+ "id": null+}+|]++txEvalInputSample = [r|+{+ "cbor": "sample",+ "additionalUtxoSet": []+}+|]++txEvalInputExpected =+ TxEvalInput+ { _txEvalInputCbor = CBORString "sample"+ , _txEvalInputAdditionalUtxoSet = Array mempty+ }