{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE RecordWildCards #-}
module Console.SolanaStaking.Main
( run
, getArgs
, Args (..)
) where
import Control.Monad (foldM, forM, unless, (<=<))
import Control.Monad.Except (ExceptT, runExceptT)
import Control.Monad.Reader (MonadIO, ReaderT, liftIO, runReaderT)
import Data.Bifunctor (bimap, second)
import Data.List (sortOn)
import Data.Maybe (fromMaybe, mapMaybe)
import Data.Time (LocalTime (..), ZonedTime (..), utcToLocalZonedTime)
import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
import Data.Version (showVersion)
import System.Console.CmdArgs
( Data
, Typeable
, argPos
, cmdArgs
, def
, explicit
, help
, helpArg
, name
, program
, summary
, typ
, (&=)
)
import System.IO (hPutStrLn, stderr)
import Console.SolanaStaking.Api
import Console.SolanaStaking.CoinTracking (makeCoinTrackingImport)
import Console.SolanaStaking.Csv (makeCsvContents)
import Paths_solana_staking_csvs (version)
import Data.ByteString.Lazy qualified as LBS
import Data.Map.Strict qualified as M
import Data.Text qualified as T
run :: Args -> IO ()
run :: Args -> IO ()
run Args {Bool
String
Maybe Integer
Maybe String
argApiKey :: String
argPubKey :: String
argOutputFile :: Maybe String
argCoinTracking :: Bool
argYear :: Maybe Integer
argAggregate :: Bool
argApiKey :: Args -> String
argPubKey :: Args -> String
argOutputFile :: Args -> Maybe String
argCoinTracking :: Args -> Bool
argYear :: Args -> Maybe Integer
argAggregate :: Args -> Bool
..} = (APIError -> IO ()) -> (() -> IO ()) -> Either APIError () -> IO ()
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> IO ()
forall a. HasCallStack => String -> a
error (String -> IO ()) -> (APIError -> String) -> APIError -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. APIError -> String
forall a. Show a => a -> String
show) () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either APIError () -> IO ())
-> (ReaderT Config (ExceptT APIError IO) ()
-> IO (Either APIError ()))
-> ReaderT Config (ExceptT APIError IO) ()
-> IO ()
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< ReaderT Config (ExceptT APIError IO) () -> IO (Either APIError ())
forall a.
ReaderT Config (ExceptT APIError IO) a -> IO (Either APIError a)
runner (ReaderT Config (ExceptT APIError IO) () -> IO ())
-> ReaderT Config (ExceptT APIError IO) () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
[StakingAccount]
stakes <- StakingAccounts -> [StakingAccount]
saResults (StakingAccounts -> [StakingAccount])
-> ReaderT Config (ExceptT APIError IO) StakingAccounts
-> ReaderT Config (ExceptT APIError IO) [StakingAccount]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ReaderT Config (ExceptT APIError IO) (APIResponse StakingAccounts)
forall (m :: * -> *).
(MonadReader Config m, MonadCatch m, MonadIO m) =>
m (APIResponse StakingAccounts)
getAccountStakes ReaderT Config (ExceptT APIError IO) (APIResponse StakingAccounts)
-> (APIResponse StakingAccounts
-> ReaderT Config (ExceptT APIError IO) StakingAccounts)
-> ReaderT Config (ExceptT APIError IO) StakingAccounts
forall a b.
ReaderT Config (ExceptT APIError IO) a
-> (a -> ReaderT Config (ExceptT APIError IO) b)
-> ReaderT Config (ExceptT APIError IO) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= APIResponse StakingAccounts
-> ReaderT Config (ExceptT APIError IO) StakingAccounts
forall (m :: * -> *) a.
MonadError APIError m =>
APIResponse a -> m a
raiseAPIError)
([APIError]
stakeErrors, [(StakingAccount, StakeReward)]
stakeRewards) <-
([([APIError], [(StakingAccount, StakeReward)])]
-> ([APIError], [(StakingAccount, StakeReward)]))
-> ReaderT
Config
(ExceptT APIError IO)
[([APIError], [(StakingAccount, StakeReward)])]
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)])
forall a b.
(a -> b)
-> ReaderT Config (ExceptT APIError IO) a
-> ReaderT Config (ExceptT APIError IO) b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([[APIError]] -> [APIError])
-> ([[(StakingAccount, StakeReward)]]
-> [(StakingAccount, StakeReward)])
-> ([[APIError]], [[(StakingAccount, StakeReward)]])
-> ([APIError], [(StakingAccount, StakeReward)])
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap [[APIError]] -> [APIError]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[(StakingAccount, StakeReward)]]
-> [(StakingAccount, StakeReward)]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (([[APIError]], [[(StakingAccount, StakeReward)]])
-> ([APIError], [(StakingAccount, StakeReward)]))
-> ([([APIError], [(StakingAccount, StakeReward)])]
-> ([[APIError]], [[(StakingAccount, StakeReward)]]))
-> [([APIError], [(StakingAccount, StakeReward)])]
-> ([APIError], [(StakingAccount, StakeReward)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [([APIError], [(StakingAccount, StakeReward)])]
-> ([[APIError]], [[(StakingAccount, StakeReward)]])
forall a b. [(a, b)] -> ([a], [b])
unzip) (ReaderT
Config
(ExceptT APIError IO)
[([APIError], [(StakingAccount, StakeReward)])]
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)]))
-> ((StakingAccount
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)]))
-> ReaderT
Config
(ExceptT APIError IO)
[([APIError], [(StakingAccount, StakeReward)])])
-> (StakingAccount
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)]))
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [StakingAccount]
-> (StakingAccount
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)]))
-> ReaderT
Config
(ExceptT APIError IO)
[([APIError], [(StakingAccount, StakeReward)])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [StakingAccount]
stakes ((StakingAccount
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)]))
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)]))
-> (StakingAccount
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)]))
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)])
forall a b. (a -> b) -> a -> b
$ \StakingAccount
sa -> do
([StakeReward] -> [(StakingAccount, StakeReward)])
-> ([APIError], [StakeReward])
-> ([APIError], [(StakingAccount, StakeReward)])
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ((StakeReward -> (StakingAccount, StakeReward))
-> [StakeReward] -> [(StakingAccount, StakeReward)]
forall a b. (a -> b) -> [a] -> [b]
map (StakingAccount
sa,))
(([APIError], [StakeReward])
-> ([APIError], [(StakingAccount, StakeReward)]))
-> ReaderT Config (ExceptT APIError IO) ([APIError], [StakeReward])
-> ReaderT
Config
(ExceptT APIError IO)
([APIError], [(StakingAccount, StakeReward)])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT Config (ExceptT APIError IO) ([APIError], [StakeReward])
-> (Integer
-> ReaderT
Config (ExceptT APIError IO) ([APIError], [StakeReward]))
-> Maybe Integer
-> ReaderT Config (ExceptT APIError IO) ([APIError], [StakeReward])
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
(StakingPubKey
-> ReaderT Config (ExceptT APIError IO) ([APIError], [StakeReward])
forall (m :: * -> *).
(MonadReader Config m, MonadCatch m, MonadIO m) =>
StakingPubKey -> m ([APIError], [StakeReward])
getAllStakeRewards (StakingAccount -> StakingPubKey
saPubKey StakingAccount
sa))
(StakingPubKey
-> Integer
-> ReaderT Config (ExceptT APIError IO) ([APIError], [StakeReward])
forall (m :: * -> *).
(MonadReader Config m, MonadCatch m, MonadIO m) =>
StakingPubKey -> Integer -> m ([APIError], [StakeReward])
getYearsStakeRewards (StakingPubKey
-> Integer
-> ReaderT
Config (ExceptT APIError IO) ([APIError], [StakeReward]))
-> StakingPubKey
-> Integer
-> ReaderT Config (ExceptT APIError IO) ([APIError], [StakeReward])
forall a b. (a -> b) -> a -> b
$ StakingAccount -> StakingPubKey
saPubKey StakingAccount
sa)
Maybe Integer
argYear
Bool
-> ReaderT Config (ExceptT APIError IO) ()
-> ReaderT Config (ExceptT APIError IO) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([APIError] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [APIError]
stakeErrors) (ReaderT Config (ExceptT APIError IO) ()
-> ReaderT Config (ExceptT APIError IO) ())
-> (IO () -> ReaderT Config (ExceptT APIError IO) ())
-> IO ()
-> ReaderT Config (ExceptT APIError IO) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO () -> ReaderT Config (ExceptT APIError IO) ()
forall a. IO a -> ReaderT Config (ExceptT APIError IO) a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ReaderT Config (ExceptT APIError IO) ())
-> IO () -> ReaderT Config (ExceptT APIError IO) ()
forall a b. (a -> b) -> a -> b
$ do
Handle -> String -> IO ()
hPutStrLn Handle
stderr String
"Got errors while fetching stake rewards:"
(APIError -> IO ()) -> [APIError] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Handle -> String -> IO ()
hPutStrLn Handle
stderr (String -> IO ()) -> (APIError -> String) -> APIError -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String
"\t" String -> String -> String
forall a. Semigroup a => a -> a -> a
<>) (String -> String) -> (APIError -> String) -> APIError -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. APIError -> String
forall a. Show a => a -> String
show) [APIError]
stakeErrors
let orderedRewards :: [(StakingAccount, StakeReward)]
orderedRewards = ((StakingAccount, StakeReward) -> POSIXTime)
-> [(StakingAccount, StakeReward)]
-> [(StakingAccount, StakeReward)]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (StakeReward -> POSIXTime
srTimestamp (StakeReward -> POSIXTime)
-> ((StakingAccount, StakeReward) -> StakeReward)
-> (StakingAccount, StakeReward)
-> POSIXTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StakingAccount, StakeReward) -> StakeReward
forall a b. (a, b) -> b
snd) [(StakingAccount, StakeReward)]
stakeRewards
aggregator :: [(StakingAccount, StakeReward)]
-> ReaderT
Config (ExceptT APIError IO) [(StakingAccount, StakeReward)]
aggregator = if Bool
argAggregate then [(StakingAccount, StakeReward)]
-> ReaderT
Config (ExceptT APIError IO) [(StakingAccount, StakeReward)]
forall (m :: * -> *).
MonadIO m =>
[(StakingAccount, StakeReward)]
-> m [(StakingAccount, StakeReward)]
aggregateRewards else [(StakingAccount, StakeReward)]
-> ReaderT
Config (ExceptT APIError IO) [(StakingAccount, StakeReward)]
forall a. a -> ReaderT Config (ExceptT APIError IO) a
forall (m :: * -> *) a. Monad m => a -> m a
return
outputFile :: String
outputFile = String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
"-" Maybe String
argOutputFile
[(StakingAccount, StakeReward)]
rewards <- [(StakingAccount, StakeReward)]
-> ReaderT
Config (ExceptT APIError IO) [(StakingAccount, StakeReward)]
aggregator [(StakingAccount, StakeReward)]
orderedRewards
if Bool
argCoinTracking
then IO () -> ReaderT Config (ExceptT APIError IO) ()
forall a. IO a -> ReaderT Config (ExceptT APIError IO) a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ReaderT Config (ExceptT APIError IO) ())
-> IO () -> ReaderT Config (ExceptT APIError IO) ()
forall a b. (a -> b) -> a -> b
$ String -> [(StakingAccount, StakeReward)] -> IO ()
makeCoinTrackingImport String
outputFile [(StakingAccount, StakeReward)]
rewards
else do
let output :: ByteString
output = [(StakingAccount, StakeReward)] -> ByteString
makeCsvContents [(StakingAccount, StakeReward)]
rewards
if String
outputFile String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"-"
then IO () -> ReaderT Config (ExceptT APIError IO) ()
forall a. IO a -> ReaderT Config (ExceptT APIError IO) a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ReaderT Config (ExceptT APIError IO) ())
-> IO () -> ReaderT Config (ExceptT APIError IO) ()
forall a b. (a -> b) -> a -> b
$ ByteString -> IO ()
LBS.putStr ByteString
output
else IO () -> ReaderT Config (ExceptT APIError IO) ()
forall a. IO a -> ReaderT Config (ExceptT APIError IO) a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ReaderT Config (ExceptT APIError IO) ())
-> IO () -> ReaderT Config (ExceptT APIError IO) ()
forall a b. (a -> b) -> a -> b
$ String -> ByteString -> IO ()
LBS.writeFile String
outputFile ByteString
output
where
runner :: ReaderT Config (ExceptT APIError IO) a -> IO (Either APIError a)
runner :: forall a.
ReaderT Config (ExceptT APIError IO) a -> IO (Either APIError a)
runner = ExceptT APIError IO a -> IO (Either APIError a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT APIError IO a -> IO (Either APIError a))
-> (ReaderT Config (ExceptT APIError IO) a
-> ExceptT APIError IO a)
-> ReaderT Config (ExceptT APIError IO) a
-> IO (Either APIError a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ReaderT Config (ExceptT APIError IO) a
-> Config -> ExceptT APIError IO a)
-> Config
-> ReaderT Config (ExceptT APIError IO) a
-> ExceptT APIError IO a
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT Config (ExceptT APIError IO) a
-> Config -> ExceptT APIError IO a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (String -> String -> Config
mkConfig String
argApiKey String
argPubKey)
aggregateRewards :: (MonadIO m) => [(StakingAccount, StakeReward)] -> m [(StakingAccount, StakeReward)]
aggregateRewards :: forall (m :: * -> *).
MonadIO m =>
[(StakingAccount, StakeReward)]
-> m [(StakingAccount, StakeReward)]
aggregateRewards =
(Map Day [(StakingAccount, StakeReward)]
-> [(StakingAccount, StakeReward)])
-> m (Map Day [(StakingAccount, StakeReward)])
-> m [(StakingAccount, StakeReward)]
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (((Day, [(StakingAccount, StakeReward)])
-> Maybe (StakingAccount, StakeReward))
-> [(Day, [(StakingAccount, StakeReward)])]
-> [(StakingAccount, StakeReward)]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ([(StakingAccount, StakeReward)]
-> Maybe (StakingAccount, StakeReward)
aggregate ([(StakingAccount, StakeReward)]
-> Maybe (StakingAccount, StakeReward))
-> ((Day, [(StakingAccount, StakeReward)])
-> [(StakingAccount, StakeReward)])
-> (Day, [(StakingAccount, StakeReward)])
-> Maybe (StakingAccount, StakeReward)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Day, [(StakingAccount, StakeReward)])
-> [(StakingAccount, StakeReward)]
forall a b. (a, b) -> b
snd) ([(Day, [(StakingAccount, StakeReward)])]
-> [(StakingAccount, StakeReward)])
-> (Map Day [(StakingAccount, StakeReward)]
-> [(Day, [(StakingAccount, StakeReward)])])
-> Map Day [(StakingAccount, StakeReward)]
-> [(StakingAccount, StakeReward)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map Day [(StakingAccount, StakeReward)]
-> [(Day, [(StakingAccount, StakeReward)])]
forall k a. Map k a -> [(k, a)]
M.toList)
(m (Map Day [(StakingAccount, StakeReward)])
-> m [(StakingAccount, StakeReward)])
-> ([(StakingAccount, StakeReward)]
-> m (Map Day [(StakingAccount, StakeReward)]))
-> [(StakingAccount, StakeReward)]
-> m [(StakingAccount, StakeReward)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Map Day [(StakingAccount, StakeReward)]
-> (StakingAccount, StakeReward)
-> m (Map Day [(StakingAccount, StakeReward)]))
-> Map Day [(StakingAccount, StakeReward)]
-> [(StakingAccount, StakeReward)]
-> m (Map Day [(StakingAccount, StakeReward)])
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM
( \Map Day [(StakingAccount, StakeReward)]
acc (StakingAccount, StakeReward)
r -> do
ZonedTime
rewardTime <- IO ZonedTime -> m ZonedTime
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ZonedTime -> m ZonedTime)
-> (UTCTime -> IO ZonedTime) -> UTCTime -> m ZonedTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> IO ZonedTime
utcToLocalZonedTime (UTCTime -> m ZonedTime) -> UTCTime -> m ZonedTime
forall a b. (a -> b) -> a -> b
$ POSIXTime -> UTCTime
posixSecondsToUTCTime (POSIXTime -> UTCTime) -> POSIXTime -> UTCTime
forall a b. (a -> b) -> a -> b
$ StakeReward -> POSIXTime
srTimestamp (StakeReward -> POSIXTime) -> StakeReward -> POSIXTime
forall a b. (a -> b) -> a -> b
$ (StakingAccount, StakeReward) -> StakeReward
forall a b. (a, b) -> b
snd (StakingAccount, StakeReward)
r
Map Day [(StakingAccount, StakeReward)]
-> m (Map Day [(StakingAccount, StakeReward)])
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Map Day [(StakingAccount, StakeReward)]
-> m (Map Day [(StakingAccount, StakeReward)]))
-> Map Day [(StakingAccount, StakeReward)]
-> m (Map Day [(StakingAccount, StakeReward)])
forall a b. (a -> b) -> a -> b
$
([(StakingAccount, StakeReward)]
-> [(StakingAccount, StakeReward)]
-> [(StakingAccount, StakeReward)])
-> Day
-> [(StakingAccount, StakeReward)]
-> Map Day [(StakingAccount, StakeReward)]
-> Map Day [(StakingAccount, StakeReward)]
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
M.insertWith
[(StakingAccount, StakeReward)]
-> [(StakingAccount, StakeReward)]
-> [(StakingAccount, StakeReward)]
forall a. Semigroup a => a -> a -> a
(<>)
(LocalTime -> Day
localDay (LocalTime -> Day) -> LocalTime -> Day
forall a b. (a -> b) -> a -> b
$ ZonedTime -> LocalTime
zonedTimeToLocalTime ZonedTime
rewardTime)
[(StakingAccount, StakeReward)
r]
Map Day [(StakingAccount, StakeReward)]
acc
)
Map Day [(StakingAccount, StakeReward)]
forall k a. Map k a
M.empty
aggregate :: [(StakingAccount, StakeReward)] -> Maybe (StakingAccount, StakeReward)
aggregate :: [(StakingAccount, StakeReward)]
-> Maybe (StakingAccount, StakeReward)
aggregate = \case
[] -> Maybe (StakingAccount, StakeReward)
forall a. Maybe a
Nothing
[(StakingAccount, StakeReward)]
rs ->
(StakingAccount, StakeReward)
-> Maybe (StakingAccount, StakeReward)
forall a. a -> Maybe a
Just
( StakingAccount
{ saValidatorName :: Text
saValidatorName = Text
"AGGREGATE-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ [(StakingAccount, StakeReward)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(StakingAccount, StakeReward)]
rs)
, saPubKey :: StakingPubKey
saPubKey = Text -> StakingPubKey
StakingPubKey (Text -> StakingPubKey) -> Text -> StakingPubKey
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack String
argPubKey
, saLamports :: Lamports
saLamports = [Lamports] -> Lamports
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Lamports] -> Lamports) -> [Lamports] -> Lamports
forall a b. (a -> b) -> a -> b
$ ((StakingAccount, StakeReward) -> Lamports)
-> [(StakingAccount, StakeReward)] -> [Lamports]
forall a b. (a -> b) -> [a] -> [b]
map (StakingAccount -> Lamports
saLamports (StakingAccount -> Lamports)
-> ((StakingAccount, StakeReward) -> StakingAccount)
-> (StakingAccount, StakeReward)
-> Lamports
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StakingAccount, StakeReward) -> StakingAccount
forall a b. (a, b) -> a
fst) [(StakingAccount, StakeReward)]
rs
}
, StakeReward
{ srTimestamp :: POSIXTime
srTimestamp = [POSIXTime] -> POSIXTime
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum ([POSIXTime] -> POSIXTime) -> [POSIXTime] -> POSIXTime
forall a b. (a -> b) -> a -> b
$ ((StakingAccount, StakeReward) -> POSIXTime)
-> [(StakingAccount, StakeReward)] -> [POSIXTime]
forall a b. (a -> b) -> [a] -> [b]
map (StakeReward -> POSIXTime
srTimestamp (StakeReward -> POSIXTime)
-> ((StakingAccount, StakeReward) -> StakeReward)
-> (StakingAccount, StakeReward)
-> POSIXTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StakingAccount, StakeReward) -> StakeReward
forall a b. (a, b) -> b
snd) [(StakingAccount, StakeReward)]
rs
, srSlot :: Integer
srSlot = StakeReward -> Integer
srSlot (StakeReward -> Integer) -> StakeReward -> Integer
forall a b. (a -> b) -> a -> b
$ (StakingAccount, StakeReward) -> StakeReward
forall a b. (a, b) -> b
snd ((StakingAccount, StakeReward) -> StakeReward)
-> (StakingAccount, StakeReward) -> StakeReward
forall a b. (a -> b) -> a -> b
$ [(StakingAccount, StakeReward)] -> (StakingAccount, StakeReward)
forall a. HasCallStack => [a] -> a
head [(StakingAccount, StakeReward)]
rs
, srEpoch :: Integer
srEpoch = StakeReward -> Integer
srEpoch (StakeReward -> Integer) -> StakeReward -> Integer
forall a b. (a -> b) -> a -> b
$ (StakingAccount, StakeReward) -> StakeReward
forall a b. (a, b) -> b
snd ((StakingAccount, StakeReward) -> StakeReward)
-> (StakingAccount, StakeReward) -> StakeReward
forall a b. (a -> b) -> a -> b
$ [(StakingAccount, StakeReward)] -> (StakingAccount, StakeReward)
forall a. HasCallStack => [a] -> a
head [(StakingAccount, StakeReward)]
rs
, srAmount :: Lamports
srAmount = [Lamports] -> Lamports
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Lamports] -> Lamports) -> [Lamports] -> Lamports
forall a b. (a -> b) -> a -> b
$ ((StakingAccount, StakeReward) -> Lamports)
-> [(StakingAccount, StakeReward)] -> [Lamports]
forall a b. (a -> b) -> [a] -> [b]
map (StakeReward -> Lamports
srAmount (StakeReward -> Lamports)
-> ((StakingAccount, StakeReward) -> StakeReward)
-> (StakingAccount, StakeReward)
-> Lamports
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StakingAccount, StakeReward) -> StakeReward
forall a b. (a, b) -> b
snd) [(StakingAccount, StakeReward)]
rs
}
)
data Args = Args
{ Args -> String
argApiKey :: String
, Args -> String
argPubKey :: String
, Args -> Maybe String
argOutputFile :: Maybe String
, Args -> Bool
argCoinTracking :: Bool
, Args -> Maybe Integer
argYear :: Maybe Integer
, Args -> Bool
argAggregate :: Bool
}
deriving (Int -> Args -> String -> String
[Args] -> String -> String
Args -> String
(Int -> Args -> String -> String)
-> (Args -> String) -> ([Args] -> String -> String) -> Show Args
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> Args -> String -> String
showsPrec :: Int -> Args -> String -> String
$cshow :: Args -> String
show :: Args -> String
$cshowList :: [Args] -> String -> String
showList :: [Args] -> String -> String
Show, ReadPrec [Args]
ReadPrec Args
Int -> ReadS Args
ReadS [Args]
(Int -> ReadS Args)
-> ReadS [Args] -> ReadPrec Args -> ReadPrec [Args] -> Read Args
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS Args
readsPrec :: Int -> ReadS Args
$creadList :: ReadS [Args]
readList :: ReadS [Args]
$creadPrec :: ReadPrec Args
readPrec :: ReadPrec Args
$creadListPrec :: ReadPrec [Args]
readListPrec :: ReadPrec [Args]
Read, Args -> Args -> Bool
(Args -> Args -> Bool) -> (Args -> Args -> Bool) -> Eq Args
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Args -> Args -> Bool
== :: Args -> Args -> Bool
$c/= :: Args -> Args -> Bool
/= :: Args -> Args -> Bool
Eq, Typeable Args
Typeable Args =>
(forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Args -> c Args)
-> (forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Args)
-> (Args -> Constr)
-> (Args -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Args))
-> (forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Args))
-> ((forall b. Data b => b -> b) -> Args -> Args)
-> (forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Args -> r)
-> (forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Args -> r)
-> (forall u. (forall d. Data d => d -> u) -> Args -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> Args -> u)
-> (forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Args -> m Args)
-> (forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Args -> m Args)
-> (forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Args -> m Args)
-> Data Args
Args -> Constr
Args -> DataType
(forall b. Data b => b -> b) -> Args -> Args
forall a.
Typeable a =>
(forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> Args -> u
forall u. (forall d. Data d => d -> u) -> Args -> [u]
forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Args -> r
forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Args -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Args -> m Args
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Args -> m Args
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Args
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Args -> c Args
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Args)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Args)
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Args -> c Args
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Args -> c Args
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Args
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Args
$ctoConstr :: Args -> Constr
toConstr :: Args -> Constr
$cdataTypeOf :: Args -> DataType
dataTypeOf :: Args -> DataType
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Args)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Args)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Args)
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Args)
$cgmapT :: (forall b. Data b => b -> b) -> Args -> Args
gmapT :: (forall b. Data b => b -> b) -> Args -> Args
$cgmapQl :: forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Args -> r
gmapQl :: forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Args -> r
$cgmapQr :: forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Args -> r
gmapQr :: forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Args -> r
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> Args -> [u]
gmapQ :: forall u. (forall d. Data d => d -> u) -> Args -> [u]
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Args -> u
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Args -> u
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Args -> m Args
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Args -> m Args
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Args -> m Args
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Args -> m Args
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Args -> m Args
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Args -> m Args
Data, Typeable)
getArgs :: IO Args
getArgs :: IO Args
getArgs = Args -> IO Args
forall a. Data a => a -> IO a
cmdArgs Args
argSpec
argSpec :: Args
argSpec :: Args
argSpec =
Args
{ argApiKey :: String
argApiKey = String
forall a. Default a => a
def String -> Ann -> String
forall val. Data val => val -> Ann -> val
&= Int -> Ann
argPos Int
0 String -> Ann -> String
forall val. Data val => val -> Ann -> val
&= String -> Ann
typ String
"API_KEY"
, argPubKey :: String
argPubKey = String
forall a. Default a => a
def String -> Ann -> String
forall val. Data val => val -> Ann -> val
&= Int -> Ann
argPos Int
1 String -> Ann -> String
forall val. Data val => val -> Ann -> val
&= String -> Ann
typ String
"ACCOUNT_PUBKEY"
, argOutputFile :: Maybe String
argOutputFile =
Maybe String
forall a. Maybe a
Nothing
Maybe String -> Ann -> Maybe String
forall val. Data val => val -> Ann -> val
&= String -> Ann
help String
"File to write the export to. Default: stdout"
Maybe String -> Ann -> Maybe String
forall val. Data val => val -> Ann -> val
&= Ann
explicit
Maybe String -> Ann -> Maybe String
forall val. Data val => val -> Ann -> val
&= String -> Ann
name String
"output-file"
Maybe String -> Ann -> Maybe String
forall val. Data val => val -> Ann -> val
&= String -> Ann
name String
"o"
Maybe String -> Ann -> Maybe String
forall val. Data val => val -> Ann -> val
&= String -> Ann
typ String
"FILE"
, argCoinTracking :: Bool
argCoinTracking =
Bool
False
Bool -> Ann -> Bool
forall val. Data val => val -> Ann -> val
&= String -> Ann
help String
"Generate a CoinTracking Import file."
Bool -> Ann -> Bool
forall val. Data val => val -> Ann -> val
&= Ann
explicit
Bool -> Ann -> Bool
forall val. Data val => val -> Ann -> val
&= String -> Ann
name String
"cointracking"
, argYear :: Maybe Integer
argYear =
Maybe Integer
forall a. Maybe a
Nothing
Maybe Integer -> Ann -> Maybe Integer
forall val. Data val => val -> Ann -> val
&= String -> Ann
help String
"Limit to given year"
Maybe Integer -> Ann -> Maybe Integer
forall val. Data val => val -> Ann -> val
&= Ann
explicit
Maybe Integer -> Ann -> Maybe Integer
forall val. Data val => val -> Ann -> val
&= String -> Ann
name String
"y"
Maybe Integer -> Ann -> Maybe Integer
forall val. Data val => val -> Ann -> val
&= String -> Ann
name String
"year"
Maybe Integer -> Ann -> Maybe Integer
forall val. Data val => val -> Ann -> val
&= String -> Ann
typ String
"YYYY"
, argAggregate :: Bool
argAggregate =
Bool
False
Bool -> Ann -> Bool
forall val. Data val => val -> Ann -> val
&= String -> Ann
help String
"Output one aggregate row per day."
Bool -> Ann -> Bool
forall val. Data val => val -> Ann -> val
&= Ann
explicit
Bool -> Ann -> Bool
forall val. Data val => val -> Ann -> val
&= String -> Ann
name String
"aggregate"
}
Args -> Ann -> Args
forall val. Data val => val -> Ann -> val
&= String -> Ann
summary
( String
"solana-staking-csvs v"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Version -> String
showVersion Version
version
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
", Pavan Rikhi 2021-2024"
)
Args -> Ann -> Args
forall val. Data val => val -> Ann -> val
&= String -> Ann
program String
"solana-staking-csvs"
Args -> Ann -> Args
forall val. Data val => val -> Ann -> val
&= [Ann] -> Ann
helpArg [String -> Ann
name String
"h"]
Args -> Ann -> Args
forall val. Data val => val -> Ann -> val
&= String -> Ann
help String
"Generate CSV Exports of your Solana Staking Rewards."