{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
module Singular.Provider.Koios.Client
(
Transport (..)
, RawRequest (..)
, Retry (..)
, Answer (..)
, NoAnswer (..)
, Exchange (..)
, rawRequest
, Koios (..)
, ClientConfig (..)
, defaultClientConfig
, ClientFailure (..)
, FailureReason (..)
, PageRefusal (..)
, UnknownFact (..)
, tip
, addressUtxos
, assetUtxos
, assetTxs
, Page
, pageRows
, nextPage
, assetTxsPage
, txInfo
, txCbor
, epochParams
, cliProtocolParams
, SubmitOutcome (..)
, submitTx
, txStatus
, accountRegistered
, referenceScriptUtxos
, utxoInfo
, assetInfo
) where
import Data.Aeson (Value)
import Data.Bifunctor (first)
import Data.ByteString (ByteString)
import Data.Foldable (toList)
import Data.List (find)
import Data.List.NonEmpty (NonEmpty)
import Data.Maybe (fromMaybe, listToMaybe)
import Data.Text (Text)
import Data.Text qualified as T
import Data.Text.Encoding qualified as TE
import Cardano.Ledger.Address (AccountAddress, Addr)
import Cardano.Ledger.Api.Tx.Out (TxOut)
import Cardano.Ledger.BaseTypes (EpochNo)
import Cardano.Ledger.Binary (serialize')
import Cardano.Ledger.Conway (ConwayEra)
import Cardano.Ledger.Core (PParams, eraProtVerHigh)
import Cardano.Ledger.Hashes (ScriptHash)
import Cardano.Ledger.Mary.Value (AssetName, PolicyID)
import Cardano.Ledger.TxIn (TxId, TxIn)
import Singular.Provider.Koios.Wire
( AccountStatus (..)
, AssetInfo
, AssetTx
, Body (..)
, Call (..)
, DecodeFailure
, Method
, Request (..)
, Tip
, TxCbor (..)
, TxInfo (..)
, TxStatus (..)
, UtxoInfo
, accountInfoRequest
, addressUtxosRequest
, assetInfoRequest
, assetTxsRequest
, assetUtxosRequest
, cliProtocolParamsRequest
, decodeAccountStatuses
, decodeAssetInfos
, decodeAssetTxs
, decodeCliProtocolParams
, decodeEpochParams
, decodeReferenceScriptUtxos
, decodeSubmitted
, decodeTip
, decodeTxCbors
, decodeTxInfos
, decodeTxStatuses
, decodeUtxoInfos
, decodeUtxos
, epochParamsRequest
, parseBody
, referenceScriptUtxosRequest
, renderRewardAccount
, submitTxRequest
, tipRequest
, txCborRequest
, txInfoRequest
, txStatusRequest
, utxoInfoRequest
)
import Singular.Registry.Signing (SignedTx, signedTx)
data Retry
=
RetryTransient
|
RetryUnanswered
deriving stock (Retry -> Retry -> Bool
(Retry -> Retry -> Bool) -> (Retry -> Retry -> Bool) -> Eq Retry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Retry -> Retry -> Bool
== :: Retry -> Retry -> Bool
$c/= :: Retry -> Retry -> Bool
/= :: Retry -> Retry -> Bool
Eq, Int -> Retry -> ShowS
[Retry] -> ShowS
Retry -> String
(Int -> Retry -> ShowS)
-> (Retry -> String) -> ([Retry] -> ShowS) -> Show Retry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Retry -> ShowS
showsPrec :: Int -> Retry -> ShowS
$cshow :: Retry -> String
show :: Retry -> String
$cshowList :: [Retry] -> ShowS
showList :: [Retry] -> ShowS
Show)
data RawRequest = RawRequest
{ RawRequest -> Call
rawCall :: Call
, RawRequest -> Method
rawMethod :: Method
, RawRequest -> Text
rawPath :: Text
, RawRequest -> [(Text, Text)]
rawQuery :: [(Text, Text)]
, :: [(Text, Text)]
, RawRequest -> Body
rawBody :: Body
, RawRequest -> Retry
rawRetry :: Retry
}
deriving stock (RawRequest -> RawRequest -> Bool
(RawRequest -> RawRequest -> Bool)
-> (RawRequest -> RawRequest -> Bool) -> Eq RawRequest
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RawRequest -> RawRequest -> Bool
== :: RawRequest -> RawRequest -> Bool
$c/= :: RawRequest -> RawRequest -> Bool
/= :: RawRequest -> RawRequest -> Bool
Eq, Int -> RawRequest -> ShowS
[RawRequest] -> ShowS
RawRequest -> String
(Int -> RawRequest -> ShowS)
-> (RawRequest -> String)
-> ([RawRequest] -> ShowS)
-> Show RawRequest
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RawRequest -> ShowS
showsPrec :: Int -> RawRequest -> ShowS
$cshow :: RawRequest -> String
show :: RawRequest -> String
$cshowList :: [RawRequest] -> ShowS
showList :: [RawRequest] -> ShowS
Show)
rawRequest :: Request a -> RawRequest
rawRequest :: forall (a :: Access). Request a -> RawRequest
rawRequest Request a
r =
RawRequest
{ rawCall :: Call
rawCall = Request a -> Call
forall (a :: Access). Request a -> Call
requestCall Request a
r
, rawMethod :: Method
rawMethod = Request a -> Method
forall (a :: Access). Request a -> Method
requestMethod Request a
r
, rawPath :: Text
rawPath = Request a -> Text
forall (a :: Access). Request a -> Text
requestPath Request a
r
, rawQuery :: [(Text, Text)]
rawQuery = Request a -> [(Text, Text)]
forall (a :: Access). Request a -> [(Text, Text)]
requestQuery Request a
r
, rawHeaders :: [(Text, Text)]
rawHeaders = (Text
"accept", Text
"application/json") (Text, Text) -> [(Text, Text)] -> [(Text, Text)]
forall a. a -> [a] -> [a]
: [(Text, Text)]
contentType
, rawBody :: Body
rawBody = Request a -> Body
forall (a :: Access). Request a -> Body
requestBody Request a
r
, rawRetry :: Retry
rawRetry =
if Request a -> Call
forall (a :: Access). Request a -> Call
requestCall Request a
r Call -> Call -> Bool
forall a. Eq a => a -> a -> Bool
== Call
CallSubmitTx
then Retry
RetryUnanswered
else Retry
RetryTransient
}
where
contentType :: [(Text, Text)]
contentType = case Request a -> Body
forall (a :: Access). Request a -> Body
requestBody Request a
r of
Body
NoBody -> []
JsonBody Value
_ -> [(Text
"content-type", Text
"application/json")]
CborBody ByteString
_ -> [(Text
"content-type", Text
"application/cbor")]
data Answer = Answer
{ Answer -> Int
answerStatus :: Int
, :: [(Text, Text)]
, Answer -> ByteString
answerBody :: ByteString
}
deriving stock (Answer -> Answer -> Bool
(Answer -> Answer -> Bool)
-> (Answer -> Answer -> Bool) -> Eq Answer
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Answer -> Answer -> Bool
== :: Answer -> Answer -> Bool
$c/= :: Answer -> Answer -> Bool
/= :: Answer -> Answer -> Bool
Eq, Int -> Answer -> ShowS
[Answer] -> ShowS
Answer -> String
(Int -> Answer -> ShowS)
-> (Answer -> String) -> ([Answer] -> ShowS) -> Show Answer
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Answer -> ShowS
showsPrec :: Int -> Answer -> ShowS
$cshow :: Answer -> String
show :: Answer -> String
$cshowList :: [Answer] -> ShowS
showList :: [Answer] -> ShowS
Show)
data NoAnswer
=
NoConnection Text
|
NoAnswerInTime
|
BodyCutOff Text
|
NoRecording Text
deriving stock (NoAnswer -> NoAnswer -> Bool
(NoAnswer -> NoAnswer -> Bool)
-> (NoAnswer -> NoAnswer -> Bool) -> Eq NoAnswer
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: NoAnswer -> NoAnswer -> Bool
== :: NoAnswer -> NoAnswer -> Bool
$c/= :: NoAnswer -> NoAnswer -> Bool
/= :: NoAnswer -> NoAnswer -> Bool
Eq, Int -> NoAnswer -> ShowS
[NoAnswer] -> ShowS
NoAnswer -> String
(Int -> NoAnswer -> ShowS)
-> (NoAnswer -> String) -> ([NoAnswer] -> ShowS) -> Show NoAnswer
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> NoAnswer -> ShowS
showsPrec :: Int -> NoAnswer -> ShowS
$cshow :: NoAnswer -> String
show :: NoAnswer -> String
$cshowList :: [NoAnswer] -> ShowS
showList :: [NoAnswer] -> ShowS
Show)
data Exchange = Exchange
{ Exchange -> Int
exchangeAttempts :: Int
, Exchange -> Either NoAnswer Answer
exchangeResult :: Either NoAnswer Answer
}
deriving stock (Exchange -> Exchange -> Bool
(Exchange -> Exchange -> Bool)
-> (Exchange -> Exchange -> Bool) -> Eq Exchange
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Exchange -> Exchange -> Bool
== :: Exchange -> Exchange -> Bool
$c/= :: Exchange -> Exchange -> Bool
/= :: Exchange -> Exchange -> Bool
Eq, Int -> Exchange -> ShowS
[Exchange] -> ShowS
Exchange -> String
(Int -> Exchange -> ShowS)
-> (Exchange -> String) -> ([Exchange] -> ShowS) -> Show Exchange
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Exchange -> ShowS
showsPrec :: Int -> Exchange -> ShowS
$cshow :: Exchange -> String
show :: Exchange -> String
$cshowList :: [Exchange] -> ShowS
showList :: [Exchange] -> ShowS
Show)
newtype Transport m = Transport
{ forall (m :: * -> *). Transport m -> RawRequest -> m Exchange
exchange :: RawRequest -> m Exchange
}
data ClientConfig = ClientConfig
{ ClientConfig -> Int
pageSize :: Int
, ClientConfig -> Int
pageCeiling :: Int
}
deriving stock (ClientConfig -> ClientConfig -> Bool
(ClientConfig -> ClientConfig -> Bool)
-> (ClientConfig -> ClientConfig -> Bool) -> Eq ClientConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ClientConfig -> ClientConfig -> Bool
== :: ClientConfig -> ClientConfig -> Bool
$c/= :: ClientConfig -> ClientConfig -> Bool
/= :: ClientConfig -> ClientConfig -> Bool
Eq, Int -> ClientConfig -> ShowS
[ClientConfig] -> ShowS
ClientConfig -> String
(Int -> ClientConfig -> ShowS)
-> (ClientConfig -> String)
-> ([ClientConfig] -> ShowS)
-> Show ClientConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ClientConfig -> ShowS
showsPrec :: Int -> ClientConfig -> ShowS
$cshow :: ClientConfig -> String
show :: ClientConfig -> String
$cshowList :: [ClientConfig] -> ShowS
showList :: [ClientConfig] -> ShowS
Show)
defaultClientConfig :: ClientConfig
defaultClientConfig :: ClientConfig
defaultClientConfig = ClientConfig{pageSize :: Int
pageSize = Int
1000, pageCeiling :: Int
pageCeiling = Int
100}
data Koios m = Koios
{ forall (m :: * -> *). Koios m -> ClientConfig
koiosConfig :: ClientConfig
, forall (m :: * -> *). Koios m -> Transport m
koiosTransport :: Transport m
}
data ClientFailure = ClientFailure
{ ClientFailure -> Call
failureCall :: Call
, ClientFailure -> Int
failureAttempts :: Int
, ClientFailure -> FailureReason
failureReason :: FailureReason
}
deriving stock (ClientFailure -> ClientFailure -> Bool
(ClientFailure -> ClientFailure -> Bool)
-> (ClientFailure -> ClientFailure -> Bool) -> Eq ClientFailure
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ClientFailure -> ClientFailure -> Bool
== :: ClientFailure -> ClientFailure -> Bool
$c/= :: ClientFailure -> ClientFailure -> Bool
/= :: ClientFailure -> ClientFailure -> Bool
Eq, Int -> ClientFailure -> ShowS
[ClientFailure] -> ShowS
ClientFailure -> String
(Int -> ClientFailure -> ShowS)
-> (ClientFailure -> String)
-> ([ClientFailure] -> ShowS)
-> Show ClientFailure
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ClientFailure -> ShowS
showsPrec :: Int -> ClientFailure -> ShowS
$cshow :: ClientFailure -> String
show :: ClientFailure -> String
$cshowList :: [ClientFailure] -> ShowS
showList :: [ClientFailure] -> ShowS
Show)
data FailureReason
=
Unreachable Text
|
TimedOut
|
RateLimited (Maybe Int)
|
ServerFailing Int Text
|
RefusedByServer Int Text
|
IncompletePage PageRefusal
|
UnknownFact UnknownFact
|
Undecodable DecodeFailure
|
TokenFileUnreadable FilePath Text
|
TokenFileInvalid FilePath Text
|
NotRecorded Text
deriving stock (FailureReason -> FailureReason -> Bool
(FailureReason -> FailureReason -> Bool)
-> (FailureReason -> FailureReason -> Bool) -> Eq FailureReason
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FailureReason -> FailureReason -> Bool
== :: FailureReason -> FailureReason -> Bool
$c/= :: FailureReason -> FailureReason -> Bool
/= :: FailureReason -> FailureReason -> Bool
Eq, Int -> FailureReason -> ShowS
[FailureReason] -> ShowS
FailureReason -> String
(Int -> FailureReason -> ShowS)
-> (FailureReason -> String)
-> ([FailureReason] -> ShowS)
-> Show FailureReason
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FailureReason -> ShowS
showsPrec :: Int -> FailureReason -> ShowS
$cshow :: FailureReason -> String
show :: FailureReason -> String
$cshowList :: [FailureReason] -> ShowS
showList :: [FailureReason] -> ShowS
Show)
data
=
PageCutOff Int Text
|
PageOverLimit Int Int Int
|
TotalChanged Int Integer Integer
|
TotalMissing Int (Maybe Text)
|
RangeMismatch Int Text
|
RowsMissing Integer Integer
|
PageCeilingReached Int
deriving stock (PageRefusal -> PageRefusal -> Bool
(PageRefusal -> PageRefusal -> Bool)
-> (PageRefusal -> PageRefusal -> Bool) -> Eq PageRefusal
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PageRefusal -> PageRefusal -> Bool
== :: PageRefusal -> PageRefusal -> Bool
$c/= :: PageRefusal -> PageRefusal -> Bool
/= :: PageRefusal -> PageRefusal -> Bool
Eq, Int -> PageRefusal -> ShowS
[PageRefusal] -> ShowS
PageRefusal -> String
(Int -> PageRefusal -> ShowS)
-> (PageRefusal -> String)
-> ([PageRefusal] -> ShowS)
-> Show PageRefusal
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PageRefusal -> ShowS
showsPrec :: Int -> PageRefusal -> ShowS
$cshow :: PageRefusal -> String
show :: PageRefusal -> String
$cshowList :: [PageRefusal] -> ShowS
showList :: [PageRefusal] -> ShowS
Show)
data UnknownFact
= UnknownTip
| UnknownEpoch EpochNo
| UnknownTransaction TxId
|
UnknownRegistration Text (Maybe Text)
deriving stock (UnknownFact -> UnknownFact -> Bool
(UnknownFact -> UnknownFact -> Bool)
-> (UnknownFact -> UnknownFact -> Bool) -> Eq UnknownFact
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: UnknownFact -> UnknownFact -> Bool
== :: UnknownFact -> UnknownFact -> Bool
$c/= :: UnknownFact -> UnknownFact -> Bool
/= :: UnknownFact -> UnknownFact -> Bool
Eq, Int -> UnknownFact -> ShowS
[UnknownFact] -> ShowS
UnknownFact -> String
(Int -> UnknownFact -> ShowS)
-> (UnknownFact -> String)
-> ([UnknownFact] -> ShowS)
-> Show UnknownFact
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> UnknownFact -> ShowS
showsPrec :: Int -> UnknownFact -> ShowS
$cshow :: UnknownFact -> String
show :: UnknownFact -> String
$cshowList :: [UnknownFact] -> ShowS
showList :: [UnknownFact] -> ShowS
Show)
type Fails = Int -> FailureReason -> ClientFailure
failing :: Call -> Fails
failing :: Call -> Fails
failing = Call -> Fails
ClientFailure
answerOf :: Fails -> Int -> Exchange -> Either ClientFailure Answer
answerOf :: Fails -> Int -> Exchange -> Either ClientFailure Answer
answerOf Fails
failure Int
offset Exchange
ex = case Exchange -> Either NoAnswer Answer
exchangeResult Exchange
ex of
Left NoAnswer
none -> ClientFailure -> Either ClientFailure Answer
forall a b. a -> Either a b
Left (Fails
failure Int
attempts (NoAnswer -> FailureReason
noAnswer NoAnswer
none))
Right Answer
a
| Int
status Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
200 Bool -> Bool -> Bool
&& Int
status Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
300 -> Answer -> Either ClientFailure Answer
forall a b. b -> Either a b
Right Answer
a
| Bool
otherwise -> ClientFailure -> Either ClientFailure Answer
forall a b. a -> Either a b
Left (Fails
failure Int
attempts (Answer -> FailureReason
refusal Answer
a))
where
status :: Int
status = Answer -> Int
answerStatus Answer
a
where
attempts :: Int
attempts = Exchange -> Int
exchangeAttempts Exchange
ex
noAnswer :: NoAnswer -> FailureReason
noAnswer = \case
NoConnection Text
t -> Text -> FailureReason
Unreachable Text
t
NoAnswer
NoAnswerInTime -> FailureReason
TimedOut
BodyCutOff Text
t -> PageRefusal -> FailureReason
IncompletePage (Int -> Text -> PageRefusal
PageCutOff Int
offset Text
t)
NoRecording Text
t -> Text -> FailureReason
NotRecorded Text
t
refusal :: Answer -> FailureReason
refusal :: Answer -> FailureReason
refusal Answer
a
| Int
status Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
429 = Maybe Int -> FailureReason
RateLimited (Text -> Answer -> Maybe Text
header Text
"retry-after" Answer
a Maybe Text -> (Text -> Maybe Int) -> Maybe Int
forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Text -> Maybe Int
readInt)
| Int
status Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
500 = Int -> Text -> FailureReason
ServerFailing Int
status (Answer -> Text
bodyText Answer
a)
| Bool
otherwise = Int -> Text -> FailureReason
RefusedByServer Int
status (Answer -> Text
bodyText Answer
a)
where
status :: Int
status = Answer -> Int
answerStatus Answer
a
header :: Text -> Answer -> Maybe Text
Text
name = Text -> [(Text, Text)] -> Maybe Text
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Text
name ([(Text, Text)] -> Maybe Text)
-> (Answer -> [(Text, Text)]) -> Answer -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Answer -> [(Text, Text)]
answerHeaders
bodyText :: Answer -> Text
bodyText :: Answer -> Text
bodyText = ByteString -> Text
TE.decodeUtf8Lenient (ByteString -> Text) -> (Answer -> ByteString) -> Answer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Answer -> ByteString
answerBody
readInt :: Text -> Maybe Int
readInt :: Text -> Maybe Int
readInt Text
t = case ReadS Int
forall a. Read a => ReadS a
reads (Text -> String
T.unpack (Text -> Text
T.strip Text
t)) of
[(Int
n, String
"")] -> Int -> Maybe Int
forall a. a -> Maybe a
Just Int
n
[(Int, String)]
_ -> Maybe Int
forall a. Maybe a
Nothing
single
:: (Monad m)
=> Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single :: forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single Koios m
k Request a
req Value -> Either DecodeFailure b
decode = do
ex <- Transport m -> RawRequest -> m Exchange
forall (m :: * -> *). Transport m -> RawRequest -> m Exchange
exchange (Koios m -> Transport m
forall (m :: * -> *). Koios m -> Transport m
koiosTransport Koios m
k) (Request a -> RawRequest
forall (a :: Access). Request a -> RawRequest
rawRequest Request a
req)
let failure = Call -> Fails
failing (Request a -> Call
forall (a :: Access). Request a -> Call
requestCall Request a
req)
attempts = Exchange -> Int
exchangeAttempts Exchange
ex
undecodable = Fails
failure Int
attempts (FailureReason -> ClientFailure)
-> (DecodeFailure -> FailureReason)
-> DecodeFailure
-> ClientFailure
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DecodeFailure -> FailureReason
Undecodable
pure $ do
a <- answerOf failure 0 ex
v <- first undecodable (parseBody (answerBody a))
(,) attempts <$> first undecodable (decode v)
data Page m a = Page
{ :: [a]
, forall (m :: * -> *) a.
Page m a -> Maybe (m (Either ClientFailure (Page m a)))
nextPage :: Maybe (m (Either ClientFailure (Page m a)))
}
paged
:: (Monad m)
=> Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure [b])
paged :: forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure [b])
paged Koios m
k Request a
req Value -> Either DecodeFailure [b]
decode = Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure (Page m b))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure (Page m b))
firstPage Koios m
k Request a
req Value -> Either DecodeFailure [b]
decode m (Either ClientFailure (Page m b))
-> (Either ClientFailure (Page m b)
-> m (Either ClientFailure [b]))
-> m (Either ClientFailure [b])
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [[b]]
-> Either ClientFailure (Page m b) -> m (Either ClientFailure [b])
forall {f :: * -> *} {a}.
Monad f =>
[[a]]
-> Either ClientFailure (Page f a) -> f (Either ClientFailure [a])
collect []
where
collect :: [[a]]
-> Either ClientFailure (Page f a) -> f (Either ClientFailure [a])
collect [[a]]
chunks = \case
Left ClientFailure
failure -> Either ClientFailure [a] -> f (Either ClientFailure [a])
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ClientFailure -> Either ClientFailure [a]
forall a b. a -> Either a b
Left ClientFailure
failure)
Right Page f a
page ->
let chunks' :: [[a]]
chunks' = Page f a -> [a]
forall (m :: * -> *) a. Page m a -> [a]
pageRows Page f a
page [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: [[a]]
chunks
in case Page f a -> Maybe (f (Either ClientFailure (Page f a)))
forall (m :: * -> *) a.
Page m a -> Maybe (m (Either ClientFailure (Page m a)))
nextPage Page f a
page of
Maybe (f (Either ClientFailure (Page f a)))
Nothing -> Either ClientFailure [a] -> f (Either ClientFailure [a])
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([a] -> Either ClientFailure [a]
forall a b. b -> Either a b
Right ([[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[a]] -> [[a]]
forall a. [a] -> [a]
reverse [[a]]
chunks')))
Just f (Either ClientFailure (Page f a))
more -> f (Either ClientFailure (Page f a))
more f (Either ClientFailure (Page f a))
-> (Either ClientFailure (Page f a)
-> f (Either ClientFailure [a]))
-> f (Either ClientFailure [a])
forall a b. f a -> (a -> f b) -> f b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [[a]]
-> Either ClientFailure (Page f a) -> f (Either ClientFailure [a])
collect [[a]]
chunks'
firstPage
:: (Monad m)
=> Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure (Page m b))
firstPage :: forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure (Page m b))
firstPage Koios m
k Request a
req Value -> Either DecodeFailure [b]
decode = Int -> Int -> Maybe Integer -> m (Either ClientFailure (Page m b))
go Int
0 Int
0 Maybe Integer
forall a. Maybe a
Nothing
where
ClientConfig{pageSize :: ClientConfig -> Int
pageSize = Int
size, pageCeiling :: ClientConfig -> Int
pageCeiling = Int
ceiling'} = Koios m -> ClientConfig
forall (m :: * -> *). Koios m -> ClientConfig
koiosConfig Koios m
k
failure :: Fails
failure = Call -> Fails
failing (Request a -> Call
forall (a :: Access). Request a -> Call
requestCall Request a
req)
order :: [(Text, Text)]
order = [(Text, Text)]
-> (Text -> [(Text, Text)]) -> Maybe Text -> [(Text, Text)]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (\Text
o -> [(Text
"order", Text
o)]) (Request a -> Maybe Text
forall (a :: Access). Request a -> Maybe Text
requestOrder Request a
req)
pageRequest :: a -> RawRequest
pageRequest a
offset =
let raw :: RawRequest
raw = Request a -> RawRequest
forall (a :: Access). Request a -> RawRequest
rawRequest Request a
req
in RawRequest
raw
{ rawQuery =
rawQuery raw
<> order
<> [ ("offset", T.pack (show offset))
, ("limit", T.pack (show size))
]
, rawHeaders = ("prefer", "count=exact") : rawHeaders raw
}
go :: Int -> Int -> Maybe Integer -> m (Either ClientFailure (Page m b))
go Int
pages Int
offset Maybe Integer
total
| Int
pages Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
ceiling' =
Either ClientFailure (Page m b)
-> m (Either ClientFailure (Page m b))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ClientFailure -> Either ClientFailure (Page m b)
forall a b. a -> Either a b
Left (Fails
failure Int
0 (PageRefusal -> FailureReason
IncompletePage (Int -> PageRefusal
PageCeilingReached Int
ceiling'))))
| Bool
otherwise = do
ex <- Transport m -> RawRequest -> m Exchange
forall (m :: * -> *). Transport m -> RawRequest -> m Exchange
exchange (Koios m -> Transport m
forall (m :: * -> *). Koios m -> Transport m
koiosTransport Koios m
k) (Int -> RawRequest
forall {a}. Show a => a -> RawRequest
pageRequest Int
offset)
let attempts = Exchange -> Int
exchangeAttempts Exchange
ex
refuse = ClientFailure -> Either ClientFailure b
forall a b. a -> Either a b
Left (ClientFailure -> Either ClientFailure b)
-> (PageRefusal -> ClientFailure)
-> PageRefusal
-> Either ClientFailure b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fails
failure Int
attempts (FailureReason -> ClientFailure)
-> (PageRefusal -> FailureReason) -> PageRefusal -> ClientFailure
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PageRefusal -> FailureReason
IncompletePage
page = do
a <- Fails -> Int -> Exchange -> Either ClientFailure Answer
answerOf Fails
failure Int
offset Exchange
ex
v <-
first
(failure attempts . IncompletePage . PageCutOff offset . reasonOf)
(parseBody (answerBody a))
rows <- first (failure attempts . Undecodable) (decode v)
pure (a, rows)
case page of
Left ClientFailure
f -> Either ClientFailure (Page m b)
-> m (Either ClientFailure (Page m b))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ClientFailure -> Either ClientFailure (Page m b)
forall a b. a -> Either a b
Left ClientFailure
f)
Right (Answer
a, [b]
rows) ->
let n :: Int
n = [b] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [b]
rows
here :: Integer
here = Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
offset Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
n
in case Answer -> Maybe (Maybe (Integer, Integer), Integer)
rangeOf Answer
a of
Maybe (Maybe (Integer, Integer), Integer)
_ | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
size -> Either ClientFailure (Page m b)
-> m (Either ClientFailure (Page m b))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PageRefusal -> Either ClientFailure (Page m b)
forall {b}. PageRefusal -> Either ClientFailure b
refuse (Int -> Int -> Int -> PageRefusal
PageOverLimit Int
offset Int
n Int
size))
Maybe (Maybe (Integer, Integer), Integer)
Nothing ->
Either ClientFailure (Page m b)
-> m (Either ClientFailure (Page m b))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PageRefusal -> Either ClientFailure (Page m b)
forall {b}. PageRefusal -> Either ClientFailure b
refuse (Int -> Maybe Text -> PageRefusal
TotalMissing Int
offset (Text -> Answer -> Maybe Text
header Text
"content-range" Answer
a)))
Just (Maybe (Integer, Integer)
span', Integer
t)
| Bool -> Bool
not (Int -> Int -> Maybe (Integer, Integer) -> Bool
spanMatches Int
offset Int
n Maybe (Integer, Integer)
span') Bool -> Bool -> Bool
|| Integer
here Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
t ->
Either ClientFailure (Page m b)
-> m (Either ClientFailure (Page m b))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PageRefusal -> Either ClientFailure (Page m b)
forall {b}. PageRefusal -> Either ClientFailure b
refuse (Int -> Text -> PageRefusal
RangeMismatch Int
offset (Answer -> Text
rangeText Answer
a)))
| Just Integer
t0 <- Maybe Integer
total
, Integer
t0 Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
/= Integer
t ->
Either ClientFailure (Page m b)
-> m (Either ClientFailure (Page m b))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PageRefusal -> Either ClientFailure (Page m b)
forall {b}. PageRefusal -> Either ClientFailure b
refuse (Int -> Integer -> Integer -> PageRefusal
TotalChanged Int
offset Integer
t0 Integer
t))
| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
size Bool -> Bool -> Bool
|| Integer
here Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
t ->
if Integer
here Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
t
then Either ClientFailure (Page m b)
-> m (Either ClientFailure (Page m b))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Page m b -> Either ClientFailure (Page m b)
forall a b. b -> Either a b
Right ([b] -> Maybe (m (Either ClientFailure (Page m b))) -> Page m b
forall (m :: * -> *) a.
[a] -> Maybe (m (Either ClientFailure (Page m a))) -> Page m a
Page [b]
rows Maybe (m (Either ClientFailure (Page m b)))
forall a. Maybe a
Nothing))
else Either ClientFailure (Page m b)
-> m (Either ClientFailure (Page m b))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PageRefusal -> Either ClientFailure (Page m b)
forall {b}. PageRefusal -> Either ClientFailure b
refuse (Integer -> Integer -> PageRefusal
RowsMissing Integer
t Integer
here))
| Bool
otherwise ->
Either ClientFailure (Page m b)
-> m (Either ClientFailure (Page m b))
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
( Page m b -> Either ClientFailure (Page m b)
forall a b. b -> Either a b
Right
( [b] -> Maybe (m (Either ClientFailure (Page m b))) -> Page m b
forall (m :: * -> *) a.
[a] -> Maybe (m (Either ClientFailure (Page m a))) -> Page m a
Page
[b]
rows
(m (Either ClientFailure (Page m b))
-> Maybe (m (Either ClientFailure (Page m b)))
forall a. a -> Maybe a
Just (Int -> Int -> Maybe Integer -> m (Either ClientFailure (Page m b))
go (Int
pages Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
offset Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
size) (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
t)))
)
)
reasonOf :: DecodeFailure -> Text
reasonOf = String -> Text
T.pack (String -> Text)
-> (DecodeFailure -> String) -> DecodeFailure -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DecodeFailure -> String
forall a. Show a => a -> String
show
rangeText :: Answer -> Text
rangeText = Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
"" (Maybe Text -> Text) -> (Answer -> Maybe Text) -> Answer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Answer -> Maybe Text
header Text
"content-range"
rangeOf :: Answer -> Maybe (Maybe (Integer, Integer), Integer)
rangeOf :: Answer -> Maybe (Maybe (Integer, Integer), Integer)
rangeOf Answer
a = do
range <- Text -> Answer -> Maybe Text
header Text
"content-range" Answer
a
let (span', rest) = T.breakOn "/" range
total <- readInteger (T.drop 1 rest)
case span' of
Text
"*" -> (Maybe (Integer, Integer), Integer)
-> Maybe (Maybe (Integer, Integer), Integer)
forall a. a -> Maybe a
Just (Maybe (Integer, Integer)
forall a. Maybe a
Nothing, Integer
total)
Text
_ ->
let (Text
from, Text
to) = HasCallStack => Text -> Text -> (Text, Text)
Text -> Text -> (Text, Text)
T.breakOn Text
"-" Text
span'
in do
f <- Text -> Maybe Integer
forall {a}. Read a => Text -> Maybe a
readInteger Text
from
t <- readInteger (T.drop 1 to)
Just (Just (f, t), total)
where
readInteger :: Text -> Maybe a
readInteger Text
t = case ReadS a
forall a. Read a => ReadS a
reads (Text -> String
T.unpack Text
t) of
[(a
n, String
"")] -> a -> Maybe a
forall a. a -> Maybe a
Just a
n
[(a, String)]
_ -> Maybe a
forall a. Maybe a
Nothing
spanMatches :: Int -> Int -> Maybe (Integer, Integer) -> Bool
spanMatches :: Int -> Int -> Maybe (Integer, Integer) -> Bool
spanMatches Int
offset Int
n = \case
Maybe (Integer, Integer)
Nothing -> Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
Just (Integer
from, Integer
to) ->
Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
Bool -> Bool -> Bool
&& Integer
from Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
offset
Bool -> Bool -> Bool
&& Integer
to Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
offset Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
1
firstOr
:: Fails
-> UnknownFact
-> Either ClientFailure (Int, [a])
-> Either ClientFailure a
firstOr :: forall a.
Fails
-> UnknownFact
-> Either ClientFailure (Int, [a])
-> Either ClientFailure a
firstOr Fails
failure UnknownFact
unknown = \case
Left ClientFailure
f -> ClientFailure -> Either ClientFailure a
forall a b. a -> Either a b
Left ClientFailure
f
Right (Int
_, a
x : [a]
_) -> a -> Either ClientFailure a
forall a b. b -> Either a b
Right a
x
Right (Int
attempts, []) -> ClientFailure -> Either ClientFailure a
forall a b. a -> Either a b
Left (Fails
failure Int
attempts (UnknownFact -> FailureReason
UnknownFact UnknownFact
unknown))
eachAsked
:: Fails
-> (a -> TxId)
-> [TxId]
-> Either ClientFailure (Int, [a])
-> Either ClientFailure [a]
eachAsked :: forall a.
Fails
-> (a -> TxId)
-> [TxId]
-> Either ClientFailure (Int, [a])
-> Either ClientFailure [a]
eachAsked Fails
failure a -> TxId
key [TxId]
ids Either ClientFailure (Int, [a])
result = do
(attempts, found) <- Either ClientFailure (Int, [a])
result
traverse
( \TxId
i -> case (a -> Bool) -> [a] -> Maybe a
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((TxId -> TxId -> Bool
forall a. Eq a => a -> a -> Bool
== TxId
i) (TxId -> Bool) -> (a -> TxId) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> TxId
key) [a]
found of
Just a
row -> a -> Either ClientFailure a
forall a b. b -> Either a b
Right a
row
Maybe a
Nothing -> ClientFailure -> Either ClientFailure a
forall a b. a -> Either a b
Left (Fails
failure Int
attempts (UnknownFact -> FailureReason
UnknownFact (TxId -> UnknownFact
UnknownTransaction TxId
i)))
)
ids
tip :: (Monad m) => Koios m -> m (Either ClientFailure Tip)
tip :: forall (m :: * -> *).
Monad m =>
Koios m -> m (Either ClientFailure Tip)
tip Koios m
k =
Fails
-> UnknownFact
-> Either ClientFailure (Int, [Tip])
-> Either ClientFailure Tip
forall a.
Fails
-> UnknownFact
-> Either ClientFailure (Int, [a])
-> Either ClientFailure a
firstOr (Call -> Fails
failing Call
CallTip) UnknownFact
UnknownTip (Either ClientFailure (Int, [Tip]) -> Either ClientFailure Tip)
-> m (Either ClientFailure (Int, [Tip]))
-> m (Either ClientFailure Tip)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [Tip])
-> m (Either ClientFailure (Int, [Tip]))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single Koios m
k Request 'Read
tipRequest Value -> Either DecodeFailure [Tip]
decodeTip
addressUtxos
:: (Monad m)
=> Koios m
-> [Addr]
-> m (Either ClientFailure [(TxIn, TxOut ConwayEra)])
addressUtxos :: forall (m :: * -> *).
Monad m =>
Koios m
-> [Addr] -> m (Either ClientFailure [(TxIn, TxOut ConwayEra)])
addressUtxos Koios m
k [Addr]
addrs = Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [(TxIn, BabbageTxOut ConwayEra)])
-> m (Either ClientFailure [(TxIn, BabbageTxOut ConwayEra)])
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure [b])
paged Koios m
k ([Addr] -> Request 'Read
addressUtxosRequest [Addr]
addrs) Value -> Either DecodeFailure [(TxIn, TxOut ConwayEra)]
Value -> Either DecodeFailure [(TxIn, BabbageTxOut ConwayEra)]
decodeUtxos
assetUtxos
:: (Monad m)
=> Koios m
-> [(PolicyID, AssetName)]
-> m (Either ClientFailure [(TxIn, TxOut ConwayEra)])
assetUtxos :: forall (m :: * -> *).
Monad m =>
Koios m
-> [(PolicyID, AssetName)]
-> m (Either ClientFailure [(TxIn, TxOut ConwayEra)])
assetUtxos Koios m
k [(PolicyID, AssetName)]
assets = Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [(TxIn, BabbageTxOut ConwayEra)])
-> m (Either ClientFailure [(TxIn, BabbageTxOut ConwayEra)])
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure [b])
paged Koios m
k ([(PolicyID, AssetName)] -> Request 'Read
assetUtxosRequest [(PolicyID, AssetName)]
assets) Value -> Either DecodeFailure [(TxIn, TxOut ConwayEra)]
Value -> Either DecodeFailure [(TxIn, BabbageTxOut ConwayEra)]
decodeUtxos
assetTxs
:: (Monad m)
=> Koios m
-> PolicyID
-> AssetName
-> m (Either ClientFailure [AssetTx])
assetTxs :: forall (m :: * -> *).
Monad m =>
Koios m
-> PolicyID -> AssetName -> m (Either ClientFailure [AssetTx])
assetTxs Koios m
k PolicyID
p AssetName
n = Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [AssetTx])
-> m (Either ClientFailure [AssetTx])
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure [b])
paged Koios m
k (PolicyID -> AssetName -> Request 'Read
assetTxsRequest PolicyID
p AssetName
n) Value -> Either DecodeFailure [AssetTx]
decodeAssetTxs
assetTxsPage
:: (Monad m)
=> Koios m
-> PolicyID
-> AssetName
-> m (Either ClientFailure (Page m AssetTx))
assetTxsPage :: forall (m :: * -> *).
Monad m =>
Koios m
-> PolicyID
-> AssetName
-> m (Either ClientFailure (Page m AssetTx))
assetTxsPage Koios m
k PolicyID
p AssetName
n = Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [AssetTx])
-> m (Either ClientFailure (Page m AssetTx))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure (Page m b))
firstPage Koios m
k (PolicyID -> AssetName -> Request 'Read
assetTxsRequest PolicyID
p AssetName
n) Value -> Either DecodeFailure [AssetTx]
decodeAssetTxs
txInfo
:: (Monad m) => Koios m -> [TxId] -> m (Either ClientFailure [TxInfo])
txInfo :: forall (m :: * -> *).
Monad m =>
Koios m -> [TxId] -> m (Either ClientFailure [TxInfo])
txInfo Koios m
k [TxId]
ids =
Fails
-> (TxInfo -> TxId)
-> [TxId]
-> Either ClientFailure (Int, [TxInfo])
-> Either ClientFailure [TxInfo]
forall a.
Fails
-> (a -> TxId)
-> [TxId]
-> Either ClientFailure (Int, [a])
-> Either ClientFailure [a]
eachAsked (Call -> Fails
failing Call
CallTxInfo) TxInfo -> TxId
txInfoId [TxId]
ids
(Either ClientFailure (Int, [TxInfo])
-> Either ClientFailure [TxInfo])
-> m (Either ClientFailure (Int, [TxInfo]))
-> m (Either ClientFailure [TxInfo])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [TxInfo])
-> m (Either ClientFailure (Int, [TxInfo]))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single Koios m
k ([TxId] -> Request 'Read
txInfoRequest [TxId]
ids) Value -> Either DecodeFailure [TxInfo]
decodeTxInfos
txCbor
:: (Monad m) => Koios m -> [TxId] -> m (Either ClientFailure [TxCbor])
txCbor :: forall (m :: * -> *).
Monad m =>
Koios m -> [TxId] -> m (Either ClientFailure [TxCbor])
txCbor Koios m
k [TxId]
ids =
Fails
-> (TxCbor -> TxId)
-> [TxId]
-> Either ClientFailure (Int, [TxCbor])
-> Either ClientFailure [TxCbor]
forall a.
Fails
-> (a -> TxId)
-> [TxId]
-> Either ClientFailure (Int, [a])
-> Either ClientFailure [a]
eachAsked (Call -> Fails
failing Call
CallTxCbor) TxCbor -> TxId
txCborId [TxId]
ids
(Either ClientFailure (Int, [TxCbor])
-> Either ClientFailure [TxCbor])
-> m (Either ClientFailure (Int, [TxCbor]))
-> m (Either ClientFailure [TxCbor])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [TxCbor])
-> m (Either ClientFailure (Int, [TxCbor]))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single Koios m
k ([TxId] -> Request 'Read
txCborRequest [TxId]
ids) Value -> Either DecodeFailure [TxCbor]
decodeTxCbors
epochParams
:: (Monad m)
=> Koios m
-> EpochNo
-> m (Either ClientFailure (PParams ConwayEra))
epochParams :: forall (m :: * -> *).
Monad m =>
Koios m -> EpochNo -> m (Either ClientFailure (PParams ConwayEra))
epochParams Koios m
k EpochNo
e =
Fails
-> UnknownFact
-> Either ClientFailure (Int, [PParams ConwayEra])
-> Either ClientFailure (PParams ConwayEra)
forall a.
Fails
-> UnknownFact
-> Either ClientFailure (Int, [a])
-> Either ClientFailure a
firstOr (Call -> Fails
failing Call
CallEpochParams) (EpochNo -> UnknownFact
UnknownEpoch EpochNo
e)
(Either ClientFailure (Int, [PParams ConwayEra])
-> Either ClientFailure (PParams ConwayEra))
-> m (Either ClientFailure (Int, [PParams ConwayEra]))
-> m (Either ClientFailure (PParams ConwayEra))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [PParams ConwayEra])
-> m (Either ClientFailure (Int, [PParams ConwayEra]))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single Koios m
k (EpochNo -> Request 'Read
epochParamsRequest EpochNo
e) Value -> Either DecodeFailure [PParams ConwayEra]
decodeEpochParams
cliProtocolParams
:: (Monad m)
=> Koios m
-> m (Either ClientFailure (PParams ConwayEra))
cliProtocolParams :: forall (m :: * -> *).
Monad m =>
Koios m -> m (Either ClientFailure (PParams ConwayEra))
cliProtocolParams Koios m
k =
((Int, PParams ConwayEra) -> PParams ConwayEra)
-> Either ClientFailure (Int, PParams ConwayEra)
-> Either ClientFailure (PParams ConwayEra)
forall a b.
(a -> b) -> Either ClientFailure a -> Either ClientFailure b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int, PParams ConwayEra) -> PParams ConwayEra
forall a b. (a, b) -> b
snd (Either ClientFailure (Int, PParams ConwayEra)
-> Either ClientFailure (PParams ConwayEra))
-> m (Either ClientFailure (Int, PParams ConwayEra))
-> m (Either ClientFailure (PParams ConwayEra))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure (PParams ConwayEra))
-> m (Either ClientFailure (Int, PParams ConwayEra))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single Koios m
k Request 'Read
cliProtocolParamsRequest Value -> Either DecodeFailure (PParams ConwayEra)
decodeCliProtocolParams
data SubmitOutcome
=
SubmitAccepted TxId
|
SubmitRefused Text
deriving stock (SubmitOutcome -> SubmitOutcome -> Bool
(SubmitOutcome -> SubmitOutcome -> Bool)
-> (SubmitOutcome -> SubmitOutcome -> Bool) -> Eq SubmitOutcome
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SubmitOutcome -> SubmitOutcome -> Bool
== :: SubmitOutcome -> SubmitOutcome -> Bool
$c/= :: SubmitOutcome -> SubmitOutcome -> Bool
/= :: SubmitOutcome -> SubmitOutcome -> Bool
Eq, Int -> SubmitOutcome -> ShowS
[SubmitOutcome] -> ShowS
SubmitOutcome -> String
(Int -> SubmitOutcome -> ShowS)
-> (SubmitOutcome -> String)
-> ([SubmitOutcome] -> ShowS)
-> Show SubmitOutcome
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SubmitOutcome -> ShowS
showsPrec :: Int -> SubmitOutcome -> ShowS
$cshow :: SubmitOutcome -> String
show :: SubmitOutcome -> String
$cshowList :: [SubmitOutcome] -> ShowS
showList :: [SubmitOutcome] -> ShowS
Show)
submitTx
:: (Monad m)
=> Koios m
-> SignedTx
-> m (Either ClientFailure SubmitOutcome)
submitTx :: forall (m :: * -> *).
Monad m =>
Koios m -> SignedTx -> m (Either ClientFailure SubmitOutcome)
submitTx Koios m
k SignedTx
tx = do
let bytes :: ByteString
bytes = Version -> ConwayTx -> ByteString
forall a. EncCBOR a => Version -> a -> ByteString
serialize' (forall era. Era era => Version
eraProtVerHigh @ConwayEra) (SignedTx -> ConwayTx
signedTx SignedTx
tx)
ex <- Transport m -> RawRequest -> m Exchange
forall (m :: * -> *). Transport m -> RawRequest -> m Exchange
exchange (Koios m -> Transport m
forall (m :: * -> *). Koios m -> Transport m
koiosTransport Koios m
k) (Request 'Submission -> RawRequest
forall (a :: Access). Request a -> RawRequest
rawRequest (ByteString -> Request 'Submission
submitTxRequest ByteString
bytes))
let failure = Call -> Fails
failing Call
CallSubmitTx
attempts = Exchange -> Int
exchangeAttempts Exchange
ex
pure $ case exchangeResult ex of
Right Answer
a
| Answer -> Int
answerStatus Answer
a Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
400 -> SubmitOutcome -> Either ClientFailure SubmitOutcome
forall a b. b -> Either a b
Right (Text -> SubmitOutcome
SubmitRefused (Answer -> Text
bodyText Answer
a))
Either NoAnswer Answer
_ -> do
a <- Fails -> Int -> Exchange -> Either ClientFailure Answer
answerOf Fails
failure Int
0 Exchange
ex
first
(failure attempts . Undecodable)
(SubmitAccepted <$> decodeSubmitted (answerBody a))
txStatus
:: (Monad m)
=> Koios m
-> [TxId]
-> m (Either ClientFailure [TxStatus])
txStatus :: forall (m :: * -> *).
Monad m =>
Koios m -> [TxId] -> m (Either ClientFailure [TxStatus])
txStatus Koios m
k [TxId]
ids =
((Int, [TxStatus]) -> [TxStatus])
-> Either ClientFailure (Int, [TxStatus])
-> Either ClientFailure [TxStatus]
forall a b.
(a -> b) -> Either ClientFailure a -> Either ClientFailure b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([TxStatus] -> [TxStatus]
forall {t :: * -> *}. Foldable t => t TxStatus -> [TxStatus]
complete ([TxStatus] -> [TxStatus])
-> ((Int, [TxStatus]) -> [TxStatus])
-> (Int, [TxStatus])
-> [TxStatus]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, [TxStatus]) -> [TxStatus]
forall a b. (a, b) -> b
snd)
(Either ClientFailure (Int, [TxStatus])
-> Either ClientFailure [TxStatus])
-> m (Either ClientFailure (Int, [TxStatus]))
-> m (Either ClientFailure [TxStatus])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [TxStatus])
-> m (Either ClientFailure (Int, [TxStatus]))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single Koios m
k ([TxId] -> Request 'Read
txStatusRequest [TxId]
ids) Value -> Either DecodeFailure [TxStatus]
decodeTxStatuses
where
complete :: t TxStatus -> [TxStatus]
complete t TxStatus
found =
[ TxStatus -> Maybe TxStatus -> TxStatus
forall a. a -> Maybe a -> a
fromMaybe (TxId -> Maybe Word64 -> TxStatus
TxStatus TxId
i Maybe Word64
forall a. Maybe a
Nothing) ((TxStatus -> Bool) -> t TxStatus -> Maybe TxStatus
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((TxId -> TxId -> Bool
forall a. Eq a => a -> a -> Bool
== TxId
i) (TxId -> Bool) -> (TxStatus -> TxId) -> TxStatus -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TxStatus -> TxId
txStatusId) t TxStatus
found)
| TxId
i <- [TxId]
ids
]
accountRegistered
:: (Monad m)
=> Koios m
-> AccountAddress
-> m (Either ClientFailure Bool)
accountRegistered :: forall (m :: * -> *).
Monad m =>
Koios m -> AccountAddress -> m (Either ClientFailure Bool)
accountRegistered Koios m
k AccountAddress
account = do
result <- Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [AccountStatus])
-> m (Either ClientFailure (Int, [AccountStatus]))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single Koios m
k (AccountAddress -> Request 'Read
accountInfoRequest AccountAddress
account) Value -> Either DecodeFailure [AccountStatus]
decodeAccountStatuses
let stake = AccountAddress -> Text
renderRewardAccount AccountAddress
account
pure $ do
(attempts, statuses) <- result
let unknown =
ClientFailure -> Either ClientFailure b
forall a b. a -> Either a b
Left
(ClientFailure -> Either ClientFailure b)
-> (Maybe Text -> ClientFailure)
-> Maybe Text
-> Either ClientFailure b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Call -> Fails
failing Call
CallAccountInfo Int
attempts
(FailureReason -> ClientFailure)
-> (Maybe Text -> FailureReason) -> Maybe Text -> ClientFailure
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UnknownFact -> FailureReason
UnknownFact
(UnknownFact -> FailureReason)
-> (Maybe Text -> UnknownFact) -> Maybe Text -> FailureReason
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Maybe Text -> UnknownFact
UnknownRegistration Text
stake
case find ((== stake) . accountStakeAddress) statuses of
Maybe AccountStatus
Nothing -> Maybe Text -> Either ClientFailure Bool
forall {b}. Maybe Text -> Either ClientFailure b
unknown Maybe Text
forall a. Maybe a
Nothing
Just AccountStatus{accountStatus :: AccountStatus -> Text
accountStatus = Text
s}
| Text
s Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
"registered" -> Bool -> Either ClientFailure Bool
forall a b. b -> Either a b
Right Bool
True
| Text
s Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
"not registered" -> Bool -> Either ClientFailure Bool
forall a b. b -> Either a b
Right Bool
False
| Bool
otherwise -> Maybe Text -> Either ClientFailure Bool
forall {b}. Maybe Text -> Either ClientFailure b
unknown (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
s)
referenceScriptUtxos
:: (Monad m)
=> Koios m
-> NonEmpty ScriptHash
-> m (Either ClientFailure [(ScriptHash, TxIn)])
referenceScriptUtxos :: forall (m :: * -> *).
Monad m =>
Koios m
-> NonEmpty ScriptHash
-> m (Either ClientFailure [(ScriptHash, TxIn)])
referenceScriptUtxos Koios m
k NonEmpty ScriptHash
hashes =
Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [(ScriptHash, TxIn)])
-> m (Either ClientFailure [(ScriptHash, TxIn)])
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure [b])
-> m (Either ClientFailure [b])
paged
Koios m
k
([ScriptHash] -> Request 'Read
referenceScriptUtxosRequest (NonEmpty ScriptHash -> [ScriptHash]
forall a. NonEmpty a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty ScriptHash
hashes))
Value -> Either DecodeFailure [(ScriptHash, TxIn)]
decodeReferenceScriptUtxos
utxoInfo
:: (Monad m)
=> Koios m
-> NonEmpty TxIn
-> m (Either ClientFailure [UtxoInfo])
utxoInfo :: forall (m :: * -> *).
Monad m =>
Koios m -> NonEmpty TxIn -> m (Either ClientFailure [UtxoInfo])
utxoInfo Koios m
k NonEmpty TxIn
references =
((Int, [UtxoInfo]) -> [UtxoInfo])
-> Either ClientFailure (Int, [UtxoInfo])
-> Either ClientFailure [UtxoInfo]
forall a b.
(a -> b) -> Either ClientFailure a -> Either ClientFailure b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int, [UtxoInfo]) -> [UtxoInfo]
forall a b. (a, b) -> b
snd
(Either ClientFailure (Int, [UtxoInfo])
-> Either ClientFailure [UtxoInfo])
-> m (Either ClientFailure (Int, [UtxoInfo]))
-> m (Either ClientFailure [UtxoInfo])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [UtxoInfo])
-> m (Either ClientFailure (Int, [UtxoInfo]))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single Koios m
k ([TxIn] -> Request 'Read
utxoInfoRequest (NonEmpty TxIn -> [TxIn]
forall a. NonEmpty a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty TxIn
references)) Value -> Either DecodeFailure [UtxoInfo]
decodeUtxoInfos
assetInfo
:: (Monad m)
=> Koios m
-> (PolicyID, AssetName)
-> m (Either ClientFailure (Maybe AssetInfo))
assetInfo :: forall (m :: * -> *).
Monad m =>
Koios m
-> (PolicyID, AssetName)
-> m (Either ClientFailure (Maybe AssetInfo))
assetInfo Koios m
k (PolicyID, AssetName)
asset =
((Int, [AssetInfo]) -> Maybe AssetInfo)
-> Either ClientFailure (Int, [AssetInfo])
-> Either ClientFailure (Maybe AssetInfo)
forall a b.
(a -> b) -> Either ClientFailure a -> Either ClientFailure b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([AssetInfo] -> Maybe AssetInfo
forall a. [a] -> Maybe a
listToMaybe ([AssetInfo] -> Maybe AssetInfo)
-> ((Int, [AssetInfo]) -> [AssetInfo])
-> (Int, [AssetInfo])
-> Maybe AssetInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, [AssetInfo]) -> [AssetInfo]
forall a b. (a, b) -> b
snd)
(Either ClientFailure (Int, [AssetInfo])
-> Either ClientFailure (Maybe AssetInfo))
-> m (Either ClientFailure (Int, [AssetInfo]))
-> m (Either ClientFailure (Maybe AssetInfo))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Koios m
-> Request 'Read
-> (Value -> Either DecodeFailure [AssetInfo])
-> m (Either ClientFailure (Int, [AssetInfo]))
forall (m :: * -> *) (a :: Access) b.
Monad m =>
Koios m
-> Request a
-> (Value -> Either DecodeFailure b)
-> m (Either ClientFailure (Int, b))
single Koios m
k ((PolicyID, AssetName) -> Request 'Read
assetInfoRequest (PolicyID, AssetName)
asset) Value -> Either DecodeFailure [AssetInfo]
decodeAssetInfos