solana-staking-csvs 0.1.1.0 → 0.1.2.0
raw patch · 5 files changed
+80/−23 lines, 5 filesdep ~textPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: text
API changes (from Hackage documentation)
+ Console.SolanaStaking.Api: getYearsStakeRewards :: (MonadIO m, MonadReader Config m) => StakingPubKey -> Integer -> m ([APIError], [StakeReward])
+ Console.SolanaStaking.Api: runApi :: Monad m => APIResponse a -> m (Either APIError a)
+ Console.SolanaStaking.Main: [argYear] :: Args -> Maybe Integer
- Console.SolanaStaking.Api: getAllStakeRewards :: forall m. (MonadIO m, MonadReader Config m) => StakingPubKey -> m ([APIError], [StakeReward])
+ Console.SolanaStaking.Api: getAllStakeRewards :: (MonadIO m, MonadReader Config m) => StakingPubKey -> m ([APIError], [StakeReward])
- Console.SolanaStaking.Main: Args :: String -> String -> Maybe String -> Bool -> Args
+ Console.SolanaStaking.Main: Args :: String -> String -> Maybe String -> Bool -> Maybe Integer -> Args
Files
- CHANGELOG.md +6/−0
- README.md +0/−1
- solana-staking-csvs.cabal +3/−3
- src/Console/SolanaStaking/Api.hs +58/−18
- src/Console/SolanaStaking/Main.hs +13/−1
CHANGELOG.md view
@@ -3,6 +3,12 @@ ## master +## v0.1.2.0++* Add `--year` flag to allow filtering the output by date.+* Bump dependency versions(aeson).++ ## v0.1.1.0 * Add `--cointracking` flag to format data for use with CoinTracking's Bulk
README.md view
@@ -15,7 +15,6 @@ TODO: -* Add `-Y <year>` flag to limit years exported(or start/end flags?). * Allow sourcing pubkey & apikey from env variables? * Move SolanaBeach API to separate, published package.
solana-staking-csvs.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: solana-staking-csvs-version: 0.1.1.0+version: 0.1.2.0 synopsis: Generate CSV Exports of your Solana Staking Rewards. description: @solana-staking-csvs@ is a CLI program that queries the Solana blockchain for an account's staking accounts and exports all their staking rewards to@@ -25,7 +25,7 @@ . See @solana-staking-csvs --help@ for additional options. category: Web, Finance, Console-homepage: https://github.com/prikhi/solana-staking-csv#readme+homepage: https://github.com/prikhi/solana-staking-csvs#readme bug-reports: https://github.com/prikhi/solana-staking-csvs/issues author: Pavan Rikhi maintainer: pavan.rikhi@gmail.com@@ -61,7 +61,7 @@ ViewPatterns ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -O2 build-depends:- aeson ==1.*+ aeson >=1 && <3 , base >=4.7 && <5 , bytestring <1 , cassava <1
src/Console/SolanaStaking/Api.hs view
@@ -13,6 +13,7 @@ -- * Requests / Responses , APIResponse(..) , APIError(..)+ , runApi , raiseAPIError -- ** Get Stake Accounts , getAccountStakes@@ -20,6 +21,7 @@ , StakingAccount(..) -- ** Get Staking Rewards , getAllStakeRewards+ , getYearsStakeRewards , getStakeRewards , StakeReward(..) -- ** Get Block@@ -47,12 +49,18 @@ , Value(Object) , withObject )+import Data.Bifunctor ( second ) import Data.Scientific ( FPFormat(Fixed) , Scientific , formatScientific ) import Data.Text.Encoding ( encodeUtf8 )-import Data.Time.Clock.POSIX ( POSIXTime )+import Data.Time ( toGregorian+ , utctDay+ )+import Data.Time.Clock.POSIX ( POSIXTime+ , posixSecondsToUTCTime+ ) import GHC.Generics ( Generic ) import Network.HTTP.Req ( (/:) , (/~)@@ -177,31 +185,59 @@ -- we have to use the earliest epoch as the @cursor@ in an additional -- request to see if there are any more rewards. getAllStakeRewards- :: forall m- . (MonadIO m, MonadReader Config m)+ :: (MonadIO m, MonadReader Config m) => StakingPubKey -> m ([APIError], [StakeReward]) getAllStakeRewards pubkey =- getStakeRewards pubkey Nothing >>= runExceptT . raiseAPIError >>= go+ getStakeRewards pubkey Nothing >>= runApi >>= getStakeRewardsUntil+ pubkey+ (const True) ([], [])++-- | Get the year's worth of staking rewards for the given account.+getYearsStakeRewards+ :: (MonadIO m, MonadReader Config m)+ => StakingPubKey+ -> Integer+ -> m ([APIError], [StakeReward])+getYearsStakeRewards pubkey year =+ fmap (second $ filter ((== year) . rewardYear))+ $ getStakeRewards pubkey Nothing+ >>= runApi+ >>= getStakeRewardsUntil pubkey stopAfterYear ([], []) where- go- :: ([APIError], [StakeReward])- -> Either APIError [StakeReward]- -> m ([APIError], [StakeReward])- go (errs, rws) = \case- Left err -> return (err : errs, rws)- Right rewards -> if length rewards < 5- then return (errs, rewards <> rws)- else- let minEpoch = minimum $ map srEpoch rewards- in getStakeRewards pubkey (Just minEpoch)- >>= runExceptT- . raiseAPIError- >>= go (errs, rewards <> rws)+ rewardYear :: StakeReward -> Integer+ rewardYear =+ (\(y, _, _) -> y)+ . toGregorian+ . utctDay+ . posixSecondsToUTCTime+ . srTimestamp + stopAfterYear :: [StakeReward] -> Bool+ stopAfterYear rewards =+ let years = map rewardYear rewards in any (< year) years +-- | Fetch staking rewards until we get less than 5 rewards or the general+-- predicate returns true.+getStakeRewardsUntil+ :: (MonadIO m, MonadReader Config m)+ => StakingPubKey+ -> ([StakeReward] -> Bool)+ -> ([APIError], [StakeReward])+ -> Either APIError [StakeReward]+ -> m ([APIError], [StakeReward])+getStakeRewardsUntil pubkey cond (errs, rws) = \case+ Left err -> return (err : errs, rws)+ Right rewards -> if length rewards < 5 || cond rewards+ then return (errs, rewards <> rws)+ else+ let minEpoch = minimum $ map srEpoch rewards+ in getStakeRewards pubkey (Just minEpoch)+ >>= runApi+ >>= getStakeRewardsUntil pubkey cond (errs, rewards <> rws) + -- | A Staking Reward Payment. data StakeReward = StakeReward { srEpoch :: Integer@@ -302,6 +338,10 @@ Just (_ :: Bool) -> return ProcessingResponse Nothing -> fmap SuccessfulReponse . parseJSON $ Object o _ -> SuccessfulReponse <$> parseJSON v++-- | Evaluate an API response.+runApi :: Monad m => APIResponse a -> m (Either APIError a)+runApi = runExceptT . raiseAPIError -- | Pull the inner value out of an 'APIResponse' or throw the respective -- 'APIError'.
src/Console/SolanaStaking/Main.hs view
@@ -63,7 +63,11 @@ -- Grab rewards for each stake account (stakeErrors, stakeRewards) <- fmap (bimap concat concat . unzip) . forM stakes $ \sa -> do- second (map (sa, )) <$> getAllStakeRewards (saPubKey sa)++ second (map (sa, ))+ <$> maybe (getAllStakeRewards (saPubKey sa))+ (getYearsStakeRewards $ saPubKey sa)+ argYear unless (null stakeErrors) . liftIO $ do hPutStrLn stderr "Got errors while fetching stake rewards:" mapM_ (hPutStrLn stderr . ("\t" <>) . show) stakeErrors@@ -94,6 +98,8 @@ , argCoinTracking :: Bool -- ^ Flag to enable writing/printing files formatted for CoinTracking -- Imports.+ , argYear :: Maybe Integer+ -- ^ Year to limit output to. } deriving (Show, Read, Eq, Data, Typeable) @@ -117,6 +123,12 @@ &= help "Generate a CoinTracking Import file." &= explicit &= name "cointracking"+ , argYear = Nothing+ &= help "Limit to given year"+ &= explicit+ &= name "y"+ &= name "year"+ &= typ "YYYY" } &= summary ( "solana-staking-csvs v"