api-rpc-pegnet 0.1.0.0 → 0.1.1.0
raw patch · 9 files changed
+1018/−50 lines, 9 filesdep +api-rpc-pegnetdep ~base
Dependencies added: api-rpc-pegnet
Dependency ranges changed: base
Files
- README.md +50/−18
- api-rpc-pegnet.cabal +34/−2
- src/PegNet/RPC/Api.hs +107/−30
- src/PegNet/RPC/Types/Balances.hs +224/−0
- src/PegNet/RPC/Types/Issuance.hs +267/−0
- src/PegNet/RPC/Types/Rates.hs +224/−0
- src/PegNet/RPC/Types/RichEntry.hs +50/−0
- src/PegNet/RPC/Types/TransactionStatus.hs +47/−0
- tests/Spec.hs +15/−0
README.md view
@@ -1,16 +1,26 @@-# Haskell JSON-RPC client for PegNet+# Haskell JSON-RPC client for PegNet daemon -[](https://travis-ci.com/kompendium-llc/api-rpc-factom)+[](https://travis-ci.com/kompendium-llc/api-rpc-pegnet)+[](https://coveralls.io/github/kompendium-llc/pegnetd-haskell-client?branch=master)+ [](https://github.com/kompendium-llc/api-rpc-factom/blob/master/LICENSE) -A JSON-RPC Haskell client for the PegNet [API](https://github.com/pegnet/pegnetd/wiki/API). Each response has special ADT(algebraic data type) that automatically converted from JSON response.+A JSON-RPC Haskell client for the PegNet [API](https://github.com/pegnet/pegnetd/wiki/API) daemon. Allows retrieval of data from PegNet dApp. Each response has special ADT(algebraic data type) that automatically converted from JSON response. Using [Remote Monad](https://ku-fpg.github.io/files/Gill-15-RemoteMonad.pdf) pattern multiple request can be batched and executed simulatenously, following more robust approach and reducing usage of expensive RPC calls. -# Installation+Choosing a batching strategy. There are two strategies:+- `Weak` - a single command or a single procedure, or+- `Strong` - a sequence of commands, optionally terminated by a procedure -You can install package from [Hackage](https://hackage.haskell.org/package/api-rpc-factom) and build with Cabal, but we recommend to use [Stack](https://haskellstack.org) tool. Add to you dependencies in stack.yaml and cabal file dependency `- api-rpc-factom`.+1. [Installation](#installation)+2. [Usage](#usage)+3. [Contributions](#contributions) -To run and test fromrepository+## Installation +You can install package from [Hackage](https://hackage.haskell.org/package/api-rpc-pegnet) and build with Cabal, but we recommend to use [Stack](https://haskellstack.org) tool. Add to you dependencies in stack.yaml and cabal file dependency `- api-rpc-pegnet`.++To run and test from repository:+ 1. Build with stack ```bash $ stack build@@ -36,23 +46,45 @@ 2. build communication session with ```-weakSession (traceSendAPI "" $ clientSendAPI endpoint)+weakSession (traceSendAPI "" $ clientSendAPIWithAlt endpoint) ``` 3. run required methods inside `RPC` monad -#### Retreiving a sync status+## Usage -```haskell--- build communication session-let s = weakSession (traceSendAPI "" $ clientSendAPI endpoint)+You can construct simple session with all methods available for further processings. Check following execution --- run Remote Monad-h <- send s $ do- -- run specific events by executing exposed+```haskell+main = do+ -- build communication session+ let s = weakSession $ traceSendAPI "" $ clientSendAPIWithAlt endpointRemote+ (h, i) <- send s $ do h <- reqGetSyncStatus- return h--- show converted ADT-print h--- or use for special business logic+ i <- reqPegNetIssuance+ b <- reqPegNetBalances "FA38cwer93mmPw1HxjScLmK1yF9iJTu5P87T2vdkbuLovm2YXyss"+ t <- reqGetTransaction "0-e4380e6334b0c42d4d6155fbd1378050b91c02a0df93d7fdfe6656f94c61e7eb"+ r <- reqPegNetRates 213000+ s <- reqGetTransactionStatus "a33d4f334a2658c17d3f44158af75f1c32cc6b2f3de9ddc337064c93043d8db0"+ rich <- reqGetRichList (Just "PEG") 5++ -- return values as N-ary tuple+ return (h, i)+ -- process resulted values+ print h+ -- or use for special business logic ```++Variables `h` and `i` mapped to exact data stucture. All types available for detailed overview in `Types` directory.++## Contributions++Please, feel free to contribute, fork the repo and submit PR.+++Say thanks, send a tip:++- `btc`: 39oVXpsgsyW8ZgzsnX3sV7HLdtXWfT96qN+- `fct`: FA38cwer93mmPw1HxjScLmK1yF9iJTu5P87T2vdkbuLovm2YXyss+- `eth`: 0x9cDBA6bb44772259B3A3fb89cf233A147a720f34+- `xlm`: GD2FROTYXYSNOQQREYXHCXVOYWV556EM6PAHMVUHJNJEUYTUXUSNUZQ3
api-rpc-pegnet.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: f998af876ee380cd0f3e17213282441322f7618fb4ea71159e87d583bb7e2f57+-- hash: fb6ef3f983f51f7adfb76bafdf6c7e81d8542bd82b78244f3cd8fbafe9fdffa4 name: api-rpc-pegnet-version: 0.1.0.0+version: 0.1.1.0 synopsis: simple json-rpc client for PegNet description: simple json-rpc client for PegNet integration category: Web@@ -31,8 +31,13 @@ PegNet.RPC.Api other-modules: PegNet.RPC.Types+ PegNet.RPC.Types.Balances+ PegNet.RPC.Types.Issuance+ PegNet.RPC.Types.Rates+ PegNet.RPC.Types.RichEntry PegNet.RPC.Types.SyncStatus PegNet.RPC.Types.Transaction+ PegNet.RPC.Types.TransactionStatus Paths_api_rpc_pegnet hs-source-dirs: src@@ -40,6 +45,33 @@ aeson , aeson-casing , base >=4.7 && <5+ , bytestring+ , http-client+ , http-client-tls+ , http-conduit+ , json-alt+ , network+ , remote-json+ , remote-json-client+ , remote-monad+ , text+ , time+ , transformers+ default-language: Haskell2010++test-suite factom-test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ Paths_api_rpc_pegnet+ hs-source-dirs:+ tests+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ aeson+ , aeson-casing+ , api-rpc-pegnet+ , base , bytestring , http-client , http-client-tls
src/PegNet/RPC/Api.hs view
@@ -12,7 +12,7 @@ module PegNet.RPC.Api where import Control.Concurrent-import Control.Exception (bracket)+import Control.Exception (bracket) import Control.Monad.IO.Class import Control.Remote.Monad.JSON import Control.Remote.Monad.JSON.Client@@ -21,20 +21,28 @@ import Data.Aeson import Data.Aeson.Types import Data.Text-import Network.Socket (HostName, ServiceName,- SocketType (Stream),- addrAddress, addrFamily,- addrProtocol, addrSocketType,- close, connect, defaultHints,- getAddrInfo, socket)+import Network.Socket (HostName, ServiceName,+ SocketType (Stream),+ addrAddress, addrFamily,+ addrProtocol,+ addrSocketType, close,+ connect, defaultHints,+ getAddrInfo, socket) +import PegNet.RPC.Types.Balances+import PegNet.RPC.Types.Issuance+import PegNet.RPC.Types.Rates+import PegNet.RPC.Types.RichEntry import PegNet.RPC.Types.SyncStatus import PegNet.RPC.Types.Transaction+import PegNet.RPC.Types.TransactionStatus -------------------------------------------------------------------------------- -endpoint = "http://localhost:8070/v1"-endpointRemote = "http://dev.pegnet.org/v1"+-- | Simple endpoint wrappers to use as different+-- local or remotte API endoint, keep default values+endpoint = "http://localhost:8070/v1"+endpointRemote = "https://api.pegnetd.com" -- | "get-sync-status" -- Return the current heights synced by pegnetd and the factomd it is communicating with@@ -43,36 +51,105 @@ method "get-sync-status" None -- $ List [toJSON height] -- | "get-transaction"--- Returns if a given entry hash is a pegnet transaction, and if so returns the transaction.-reqGetTransaction :: Text -> Text -> RPC Transaction-reqGetTransaction chainId entryHash =- method "get-transaction" $ List [String chainId, String entryHash]+-- Returns the given pegnet transaction if it exists.+reqGetTransaction :: Text -- ^ Transaction id+ -> RPC Transaction -- ^ Requested Transaction+reqGetTransaction txid =+ method "get-transaction"+ $ Named [("txid", String txid)] -reqPegNetIssuance :: RPC ()+-- | Get the total supply for each pegnet asset.+--+reqPegNetIssuance :: RPC NetIssuance reqPegNetIssuance = method "get-pegnet-issuance" None -reqPegNetBalances :: RPC ()-reqPegNetBalances =- method "get-pegnet-balances" None+-- | Get the pegnet asset balances for a given address+--+reqPegNetBalances :: Text -- ^ Address to get balances from+ -> RPC NetBalances -- ^ Resulting balances over all assets+reqPegNetBalances address =+ method "get-pegnet-balances"+ $ Named [("address", String address)] -reqPegNetRates :: RPC ()-reqPegNetRates =- method "get-pegnet-rates" None+-- | "get-pegnet-rates"+-- Returns the pegnet conversion rates for a given block height.+reqPegNetRates :: Int -- ^ Specified height to get rates at+ -> RPC Rates -- ^ Resulted Rates+reqPegNetRates height =+ method "get-pegnet-rates"+ $ Named [("height", toJSON height)] -reqGetTransactionStatus :: Text -> RPC ()-reqGetTransactionStatus id =- method "get-transaction-status" None+-- | "get-transaction-status"+-- Returns the status of a transaction.+-- The parameter `entryhash` can be either a winning OPR entry hash,+-- a transaction chain entry hash, or an FCT Burn transaction id.+reqGetTransactionStatus :: Text -- ^ Transaction chain entry hash+ -> RPC TransactionStatus -- ^ Current status of transaction+reqGetTransactionStatus entryHash =+ method "get-transaction-status"+ $ Named [("entryhash", String entryHash)] -reqGeTransactions :: RPC [Transaction]-reqGeTransactions =- method "get-transactions" None+-- | get-transactions+-- Returns a set of up to 50 transactions for the given parameters.+-- TODO: this many arguments including boolean combination is a case+-- for a bad API design. Better hide it with convinience functions+-- provided to library user+reqGetTransactions :: Maybe Text -- ^+ -> Maybe Text -- ^+ -> Maybe Int -- ^+ -> Maybe Int -- ^ offset+ -> Maybe Bool -- ^+ -> Maybe Bool -- ^+ -> Maybe Bool -- ^+ -> Maybe Bool -- ^+ -> Maybe Bool -- ^+ -> RPC [Transaction] -- ^ List of Transactions by specified parameters+reqGetTransactions mbEntryHash mbAddress mbHeight mbOffset b1 b2 b3 b4 b5 =+ method "get-transactions"+ $ Named ([]+ ++ (case mbEntryHash of+ Nothing -> []+ Just eh -> [("entryhash", String eh)])+ ++ (case mbAddress of+ Nothing -> []+ Just ad -> [("address", String ad)])+ ++ (case mbHeight of+ Nothing -> []+ Just hg -> [("height", toJSON hg)])) ++-- | "get-rich-list"+-- Returns the rich list of addresses for all assets or a specific asset.+reqGetRichList :: Maybe Text -- ^ Asset name, exclude to list by all assets+ -> Int -- ^ Number to limit from top+ -> RPC [RichEntry]+reqGetRichList mbAsset limit =+ method "get-rich-list"+ $ Named ([("count", toJSON limit)]+ ++ (case mbAsset of+ Nothing -> []+ Just asset -> [("asset", String asset)]))++ -------------------------------------------------------------------------------- +-- Testing access functionality+-- NB: Factom and PegNet API return results with `plain\text` headers, we+-- need to use alternative client to handle conversion issues, since Wreq+-- library automatically throws and error for responses that are not `application\json` main = do- let s = weakSession (traceSendAPI "" $ clientSendAPI endpoint)- h <- send s $ do+ let s = weakSession $ traceSendAPI "" $ clientSendAPIWithAlt endpointRemote+ (h, i) <- send s $ do h <- reqGetSyncStatus- return h- print h+ i <- reqPegNetIssuance+ --b <- reqPegNetBalances "FA38cwer93mmPw1HxjScLmK1yF9iJTu5P87T2vdkbuLovm2YXyss"+ --t <- reqGetTransaction "0-e4380e6334b0c42d4d6155fbd1378050b91c02a0df93d7fdfe6656f94c61e7eb"+ --r <- reqPegNetRates 213000+ -- s <- reqGetTransactionStatus "a33d4f334a2658c17d3f44158af75f1c32cc6b2f3de9ddc337064c93043d8db0"+ rich <- reqGetRichList (Just "PEG") 5+ return (h, i)+ -- process resulted values+ --print h+ --print i+ return ()
+ src/PegNet/RPC/Types/Balances.hs view
@@ -0,0 +1,224 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}++module PegNet.RPC.Types.Balances where++import Control.Applicative+import Control.Monad (forM_, join, mzero)+import Data.Aeson (FromJSON (..), ToJSON (..),+ Value (..), decode, object,+ pairs, (.:), (.:?), (.=))+import Data.Aeson.AutoType.Alternative+import qualified Data.ByteString.Lazy.Char8 as BSL+import Data.Monoid+import Data.Text (Text)+import qualified GHC.Generics+import System.Environment (getArgs)+import System.Exit (exitFailure, exitSuccess)+import System.IO (hPutStrLn, stderr)++--------------------------------------------------------------------------------++-- | Workaround for https://github.com/bos/aeson/issues/287.+o .:?? val = fmap join (o .:? val)+++data NetBalances = NetBalances {+ topLevelPBRL :: Double,+ topLevelPRVN :: Double,+ topLevelPEUR :: Double,+ topLevelPUSD :: Double,+ topLevelPEG :: Double,+ topLevelPCHF :: Double,+ topLevelPDCR :: Double,+ topLevelPLTC :: Double,+ topLevelPMXN :: Double,+ topLevelPKRW :: Double,+ topLevelPXBT :: Double,+ topLevelPBNB :: Double,+ topLevelPCAD :: Double,+ topLevelPZEC :: Double,+ topLevelPXAU :: Double,+ topLevelPADA :: Double,+ topLevelPCNY :: Double,+ topLevelPXMR :: Double,+ topLevelPHKD :: Double,+ topLevelPINR :: Double,+ topLevelPGBP :: Double,+ topLevelPSGD :: Double,+ topLevelPPHP :: Double,+ topLevelPJPY :: Double,+ topLevelPDASH :: Double,+ topLevelPXAG :: Double,+ topLevelPXBC :: Double,+ topLevelPFCT :: Double,+ topLevelPXLM :: Double,+ topLevelPETH :: Double+ } deriving (Show,Eq,GHC.Generics.Generic)+++instance FromJSON NetBalances where+ parseJSON (Object v) =+ NetBalances+ <$> v+ .: "pBRL"+ <*> v+ .: "pRVN"+ <*> v+ .: "pEUR"+ <*> v+ .: "pUSD"+ <*> v+ .: "PEG"+ <*> v+ .: "pCHF"+ <*> v+ .: "pDCR"+ <*> v+ .: "pLTC"+ <*> v+ .: "pMXN"+ <*> v+ .: "pKRW"+ <*> v+ .: "pXBT"+ <*> v+ .: "pBNB"+ <*> v+ .: "pCAD"+ <*> v+ .: "pZEC"+ <*> v+ .: "pXAU"+ <*> v+ .: "pADA"+ <*> v+ .: "pCNY"+ <*> v+ .: "pXMR"+ <*> v+ .: "pHKD"+ <*> v+ .: "pINR"+ <*> v+ .: "pGBP"+ <*> v+ .: "pSGD"+ <*> v+ .: "pPHP"+ <*> v+ .: "pJPY"+ <*> v+ .: "pDASH"+ <*> v+ .: "pXAG"+ <*> v+ .: "pXBC"+ <*> v+ .: "pFCT"+ <*> v+ .: "pXLM"+ <*> v+ .: "pETH"+ parseJSON _ = mzero+++instance ToJSON NetBalances where+ toJSON (NetBalances {..}) = object+ [ "pBRL" .= topLevelPBRL+ , "pRVN" .= topLevelPRVN+ , "pEUR" .= topLevelPEUR+ , "pUSD" .= topLevelPUSD+ , "PEG" .= topLevelPEG+ , "pCHF" .= topLevelPCHF+ , "pDCR" .= topLevelPDCR+ , "pLTC" .= topLevelPLTC+ , "pMXN" .= topLevelPMXN+ , "pKRW" .= topLevelPKRW+ , "pXBT" .= topLevelPXBT+ , "pBNB" .= topLevelPBNB+ , "pCAD" .= topLevelPCAD+ , "pZEC" .= topLevelPZEC+ , "pXAU" .= topLevelPXAU+ , "pADA" .= topLevelPADA+ , "pCNY" .= topLevelPCNY+ , "pXMR" .= topLevelPXMR+ , "pHKD" .= topLevelPHKD+ , "pINR" .= topLevelPINR+ , "pGBP" .= topLevelPGBP+ , "pSGD" .= topLevelPSGD+ , "pPHP" .= topLevelPPHP+ , "pJPY" .= topLevelPJPY+ , "pDASH" .= topLevelPDASH+ , "pXAG" .= topLevelPXAG+ , "pXBC" .= topLevelPXBC+ , "pFCT" .= topLevelPFCT+ , "pXLM" .= topLevelPXLM+ , "pETH" .= topLevelPETH+ ]+ toEncoding (NetBalances {..}) = pairs+ ( "pBRL"+ .= topLevelPBRL+ <> "pRVN"+ .= topLevelPRVN+ <> "pEUR"+ .= topLevelPEUR+ <> "pUSD"+ .= topLevelPUSD+ <> "PEG"+ .= topLevelPEG+ <> "pCHF"+ .= topLevelPCHF+ <> "pDCR"+ .= topLevelPDCR+ <> "pLTC"+ .= topLevelPLTC+ <> "pMXN"+ .= topLevelPMXN+ <> "pKRW"+ .= topLevelPKRW+ <> "pXBT"+ .= topLevelPXBT+ <> "pBNB"+ .= topLevelPBNB+ <> "pCAD"+ .= topLevelPCAD+ <> "pZEC"+ .= topLevelPZEC+ <> "pXAU"+ .= topLevelPXAU+ <> "pADA"+ .= topLevelPADA+ <> "pCNY"+ .= topLevelPCNY+ <> "pXMR"+ .= topLevelPXMR+ <> "pHKD"+ .= topLevelPHKD+ <> "pINR"+ .= topLevelPINR+ <> "pGBP"+ .= topLevelPGBP+ <> "pSGD"+ .= topLevelPSGD+ <> "pPHP"+ .= topLevelPPHP+ <> "pJPY"+ .= topLevelPJPY+ <> "pDASH"+ .= topLevelPDASH+ <> "pXAG"+ .= topLevelPXAG+ <> "pXBC"+ .= topLevelPXBC+ <> "pFCT"+ .= topLevelPFCT+ <> "pXLM"+ .= topLevelPXLM+ <> "pETH"+ .= topLevelPETH+ )
+ src/PegNet/RPC/Types/Issuance.hs view
@@ -0,0 +1,267 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}++module PegNet.RPC.Types.Issuance where++import Control.Applicative+import Control.Monad (forM_, join, mzero)+import Data.Aeson (FromJSON (..), ToJSON (..),+ Value (..), decode, object,+ pairs, (.:), (.:?), (.=))+import Data.Aeson.AutoType.Alternative+import qualified Data.ByteString.Lazy.Char8 as BSL+import Data.Monoid+import Data.Text (Text)+import qualified GHC.Generics+import System.Environment (getArgs)+import System.Exit (exitFailure, exitSuccess)+import System.IO (hPutStrLn, stderr)++--------------------------------------------------------------------------------++-- | Workaround for https://github.com/bos/aeson/issues/287.+o .:?? val = fmap join (o .:? val)+++data Issuance = Issuance {+ issuancePBRL :: Double,+ issuancePRVN :: Double,+ issuancePEUR :: Double,+ issuancePUSD :: Double,+ issuancePEG :: Double,+ issuancePCHF :: Double,+ issuancePDCR :: Double,+ issuancePLTC :: Double,+ issuancePMXN :: Double,+ issuancePKRW :: Double,+ issuancePXBT :: Double,+ issuancePBNB :: Double,+ issuancePCAD :: Double,+ issuancePZEC :: Double,+ issuancePXAU :: Double,+ issuancePADA :: Double,+ issuancePCNY :: Double,+ issuancePXMR :: Double,+ issuancePHKD :: Double,+ issuancePINR :: Double,+ issuancePGBP :: Double,+ issuancePSGD :: Double,+ issuancePPHP :: Double,+ issuancePJPY :: Double,+ issuancePDASH :: Double,+ issuancePXAG :: Double,+ issuancePXBC :: Double,+ issuancePFCT :: Double,+ issuancePXLM :: Double,+ issuancePETH :: Double+ } deriving (Show,Eq,GHC.Generics.Generic)+++instance FromJSON Issuance where+ parseJSON (Object v) =+ Issuance+ <$> v+ .: "pBRL"+ <*> v+ .: "pRVN"+ <*> v+ .: "pEUR"+ <*> v+ .: "pUSD"+ <*> v+ .: "PEG"+ <*> v+ .: "pCHF"+ <*> v+ .: "pDCR"+ <*> v+ .: "pLTC"+ <*> v+ .: "pMXN"+ <*> v+ .: "pKRW"+ <*> v+ .: "pXBT"+ <*> v+ .: "pBNB"+ <*> v+ .: "pCAD"+ <*> v+ .: "pZEC"+ <*> v+ .: "pXAU"+ <*> v+ .: "pADA"+ <*> v+ .: "pCNY"+ <*> v+ .: "pXMR"+ <*> v+ .: "pHKD"+ <*> v+ .: "pINR"+ <*> v+ .: "pGBP"+ <*> v+ .: "pSGD"+ <*> v+ .: "pPHP"+ <*> v+ .: "pJPY"+ <*> v+ .: "pDASH"+ <*> v+ .: "pXAG"+ <*> v+ .: "pXBC"+ <*> v+ .: "pFCT"+ <*> v+ .: "pXLM"+ <*> v+ .: "pETH"+ parseJSON _ = mzero+++instance ToJSON Issuance where+ toJSON (Issuance {..}) = object+ [ "pBRL" .= issuancePBRL+ , "pRVN" .= issuancePRVN+ , "pEUR" .= issuancePEUR+ , "pUSD" .= issuancePUSD+ , "PEG" .= issuancePEG+ , "pCHF" .= issuancePCHF+ , "pDCR" .= issuancePDCR+ , "pLTC" .= issuancePLTC+ , "pMXN" .= issuancePMXN+ , "pKRW" .= issuancePKRW+ , "pXBT" .= issuancePXBT+ , "pBNB" .= issuancePBNB+ , "pCAD" .= issuancePCAD+ , "pZEC" .= issuancePZEC+ , "pXAU" .= issuancePXAU+ , "pADA" .= issuancePADA+ , "pCNY" .= issuancePCNY+ , "pXMR" .= issuancePXMR+ , "pHKD" .= issuancePHKD+ , "pINR" .= issuancePINR+ , "pGBP" .= issuancePGBP+ , "pSGD" .= issuancePSGD+ , "pPHP" .= issuancePPHP+ , "pJPY" .= issuancePJPY+ , "pDASH" .= issuancePDASH+ , "pXAG" .= issuancePXAG+ , "pXBC" .= issuancePXBC+ , "pFCT" .= issuancePFCT+ , "pXLM" .= issuancePXLM+ , "pETH" .= issuancePETH+ ]+ toEncoding (Issuance {..}) = pairs+ ( "pBRL"+ .= issuancePBRL+ <> "pRVN"+ .= issuancePRVN+ <> "pEUR"+ .= issuancePEUR+ <> "pUSD"+ .= issuancePUSD+ <> "PEG"+ .= issuancePEG+ <> "pCHF"+ .= issuancePCHF+ <> "pDCR"+ .= issuancePDCR+ <> "pLTC"+ .= issuancePLTC+ <> "pMXN"+ .= issuancePMXN+ <> "pKRW"+ .= issuancePKRW+ <> "pXBT"+ .= issuancePXBT+ <> "pBNB"+ .= issuancePBNB+ <> "pCAD"+ .= issuancePCAD+ <> "pZEC"+ .= issuancePZEC+ <> "pXAU"+ .= issuancePXAU+ <> "pADA"+ .= issuancePADA+ <> "pCNY"+ .= issuancePCNY+ <> "pXMR"+ .= issuancePXMR+ <> "pHKD"+ .= issuancePHKD+ <> "pINR"+ .= issuancePINR+ <> "pGBP"+ .= issuancePGBP+ <> "pSGD"+ .= issuancePSGD+ <> "pPHP"+ .= issuancePPHP+ <> "pJPY"+ .= issuancePJPY+ <> "pDASH"+ .= issuancePDASH+ <> "pXAG"+ .= issuancePXAG+ <> "pXBC"+ .= issuancePXBC+ <> "pFCT"+ .= issuancePFCT+ <> "pXLM"+ .= issuancePXLM+ <> "pETH"+ .= issuancePETH+ )+++data Syncstatus = Syncstatus {+ syncstatusFactomheight :: Double,+ syncstatusSyncheight :: Double+ } deriving (Show,Eq,GHC.Generics.Generic)+++instance FromJSON Syncstatus where+ parseJSON (Object v) =+ Syncstatus <$> v .: "factomheight" <*> v .: "syncheight"+ parseJSON _ = mzero+++instance ToJSON Syncstatus where+ toJSON (Syncstatus {..}) = object+ [ "factomheight" .= syncstatusFactomheight+ , "syncheight" .= syncstatusSyncheight+ ]+ toEncoding (Syncstatus {..}) = pairs+ ( "factomheight"+ .= syncstatusFactomheight+ <> "syncheight"+ .= syncstatusSyncheight+ )+++data NetIssuance = NetIssuance {+ topLevelIssuance :: Issuance,+ topLevelSyncstatus :: Syncstatus+ } deriving (Show,Eq,GHC.Generics.Generic)+++instance FromJSON NetIssuance where+ parseJSON (Object v) = NetIssuance <$> v .: "issuance" <*> v .: "syncstatus"+ parseJSON _ = mzero+++instance ToJSON NetIssuance where+ toJSON (NetIssuance {..}) =+ object ["issuance" .= topLevelIssuance, "syncstatus" .= topLevelSyncstatus]+ toEncoding (NetIssuance {..}) =+ pairs ("issuance" .= topLevelIssuance <> "syncstatus" .= topLevelSyncstatus)
+ src/PegNet/RPC/Types/Rates.hs view
@@ -0,0 +1,224 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}++module PegNet.RPC.Types.Rates where++import Control.Applicative+import Control.Monad (forM_, join, mzero)+import Data.Aeson (FromJSON (..), ToJSON (..),+ Value (..), decode, object,+ pairs, (.:), (.:?), (.=))+import Data.Aeson.AutoType.Alternative+import qualified Data.ByteString.Lazy.Char8 as BSL+import Data.Monoid+import Data.Text (Text)+import qualified GHC.Generics+import System.Environment (getArgs)+import System.Exit (exitFailure, exitSuccess)+import System.IO (hPutStrLn, stderr)++--------------------------------------------------------------------------------++-- | Workaround for https://github.com/bos/aeson/issues/287.+o .:?? val = fmap join (o .:? val)+++data Rates = Rates {+ ratePBRL :: Double,+ ratePRVN :: Double,+ ratePEUR :: Double,+ ratePUSD :: Double,+ ratePEG :: Double,+ ratePCHF :: Double,+ ratePDCR :: Double,+ ratePLTC :: Double,+ ratePMXN :: Double,+ ratePKRW :: Double,+ ratePXBT :: Double,+ ratePBNB :: Double,+ ratePCAD :: Double,+ ratePZEC :: Double,+ ratePXAU :: Double,+ ratePADA :: Double,+ ratePCNY :: Double,+ ratePXMR :: Double,+ ratePHKD :: Double,+ ratePINR :: Double,+ ratePGBP :: Double,+ ratePSGD :: Double,+ ratePPHP :: Double,+ ratePJPY :: Double,+ ratePDASH :: Double,+ ratePXAG :: Double,+ ratePXBC :: Double,+ ratePFCT :: Double,+ ratePXLM :: Double,+ ratePETH :: Double+ } deriving (Show,Eq,GHC.Generics.Generic)+++instance FromJSON Rates where+ parseJSON (Object v) =+ Rates+ <$> v+ .: "pBRL"+ <*> v+ .: "pRVN"+ <*> v+ .: "pEUR"+ <*> v+ .: "pUSD"+ <*> v+ .: "PEG"+ <*> v+ .: "pCHF"+ <*> v+ .: "pDCR"+ <*> v+ .: "pLTC"+ <*> v+ .: "pMXN"+ <*> v+ .: "pKRW"+ <*> v+ .: "pXBT"+ <*> v+ .: "pBNB"+ <*> v+ .: "pCAD"+ <*> v+ .: "pZEC"+ <*> v+ .: "pXAU"+ <*> v+ .: "pADA"+ <*> v+ .: "pCNY"+ <*> v+ .: "pXMR"+ <*> v+ .: "pHKD"+ <*> v+ .: "pINR"+ <*> v+ .: "pGBP"+ <*> v+ .: "pSGD"+ <*> v+ .: "pPHP"+ <*> v+ .: "pJPY"+ <*> v+ .: "pDASH"+ <*> v+ .: "pXAG"+ <*> v+ .: "pXBC"+ <*> v+ .: "pFCT"+ <*> v+ .: "pXLM"+ <*> v+ .: "pETH"+ parseJSON _ = mzero+++instance ToJSON Rates where+ toJSON (Rates {..}) = object+ [ "pBRL" .= ratePBRL+ , "pRVN" .= ratePRVN+ , "pEUR" .= ratePEUR+ , "pUSD" .= ratePUSD+ , "PEG" .= ratePEG+ , "pCHF" .= ratePCHF+ , "pDCR" .= ratePDCR+ , "pLTC" .= ratePLTC+ , "pMXN" .= ratePMXN+ , "pKRW" .= ratePKRW+ , "pXBT" .= ratePXBT+ , "pBNB" .= ratePBNB+ , "pCAD" .= ratePCAD+ , "pZEC" .= ratePZEC+ , "pXAU" .= ratePXAU+ , "pADA" .= ratePADA+ , "pCNY" .= ratePCNY+ , "pXMR" .= ratePXMR+ , "pHKD" .= ratePHKD+ , "pINR" .= ratePINR+ , "pGBP" .= ratePGBP+ , "pSGD" .= ratePSGD+ , "pPHP" .= ratePPHP+ , "pJPY" .= ratePJPY+ , "pDASH" .= ratePDASH+ , "pXAG" .= ratePXAG+ , "pXBC" .= ratePXBC+ , "pFCT" .= ratePFCT+ , "pXLM" .= ratePXLM+ , "pETH" .= ratePETH+ ]+ toEncoding (Rates {..}) = pairs+ ( "pBRL"+ .= ratePBRL+ <> "pRVN"+ .= ratePRVN+ <> "pEUR"+ .= ratePEUR+ <> "pUSD"+ .= ratePUSD+ <> "PEG"+ .= ratePEG+ <> "pCHF"+ .= ratePCHF+ <> "pDCR"+ .= ratePDCR+ <> "pLTC"+ .= ratePLTC+ <> "pMXN"+ .= ratePMXN+ <> "pKRW"+ .= ratePKRW+ <> "pXBT"+ .= ratePXBT+ <> "pBNB"+ .= ratePBNB+ <> "pCAD"+ .= ratePCAD+ <> "pZEC"+ .= ratePZEC+ <> "pXAU"+ .= ratePXAU+ <> "pADA"+ .= ratePADA+ <> "pCNY"+ .= ratePCNY+ <> "pXMR"+ .= ratePXMR+ <> "pHKD"+ .= ratePHKD+ <> "pINR"+ .= ratePINR+ <> "pGBP"+ .= ratePGBP+ <> "pSGD"+ .= ratePSGD+ <> "pPHP"+ .= ratePPHP+ <> "pJPY"+ .= ratePJPY+ <> "pDASH"+ .= ratePDASH+ <> "pXAG"+ .= ratePXAG+ <> "pXBC"+ .= ratePXBC+ <> "pFCT"+ .= ratePFCT+ <> "pXLM"+ .= ratePXLM+ <> "pETH"+ .= ratePETH+ )
+ src/PegNet/RPC/Types/RichEntry.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}++module PegNet.RPC.Types.RichEntry where++import Control.Applicative+import Control.Monad (forM_, join, mzero)+import Data.Aeson (FromJSON (..), ToJSON (..),+ Value (..), decode, object,+ pairs, (.:), (.:?), (.=))+import Data.Aeson.AutoType.Alternative+import qualified Data.ByteString.Lazy.Char8 as BSL+import Data.Monoid+import Data.Text (Text)+import qualified GHC.Generics+import System.Environment (getArgs)+import System.Exit (exitFailure, exitSuccess)+import System.IO (hPutStrLn, stderr)++--------------------------------------------------------------------------------++data RichEntry =+ RichEntry+ { reAmount :: Int+ , rePusd :: Int+ , reAddress :: Text+ } deriving (Show, Eq, GHC.Generics.Generic)++instance FromJSON RichEntry where+ parseJSON (Object v) =+ RichEntry+ <$> v .: "amount"+ <*> v .: "pusd"+ <*> v .: "address"+ parseJSON _ = mzero++instance ToJSON RichEntry where+ toJSON (RichEntry {..}) =+ object [ "amount" .= reAmount+ , "pusd" .= rePusd+ , "address" .= reAddress+ ]+ toEncoding (RichEntry {..}) =+ pairs ( "amount" .= reAmount+ <> "pusd" .= rePusd+ <> "address" .= reAddress)
+ src/PegNet/RPC/Types/TransactionStatus.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}++module PegNet.RPC.Types.TransactionStatus where++import Control.Applicative+import Control.Monad (forM_, join, mzero)+import Data.Aeson (FromJSON (..), ToJSON (..),+ Value (..), decode, object,+ pairs, (.:), (.:?), (.=))+import Data.Aeson.AutoType.Alternative+import qualified Data.ByteString.Lazy.Char8 as BSL+import Data.Monoid+import Data.Text (Text)+import qualified GHC.Generics+import System.Environment (getArgs)+import System.Exit (exitFailure, exitSuccess)+import System.IO (hPutStrLn, stderr)++--------------------------------------------------------------------------------++data TransactionStatus =+ TransactionStatus {+ txHeight :: Int,+ txExecuted :: Int+ } deriving (Show,Eq,GHC.Generics.Generic)++instance FromJSON TransactionStatus where+ parseJSON (Object v) =+ TransactionStatus+ <$> v .: "height"+ <*> v .: "executed"+ parseJSON _ = mzero++instance ToJSON TransactionStatus where+ toJSON (TransactionStatus {..}) =+ object [ "height" .= txHeight+ , "executed" .= txExecuted+ ]+ toEncoding (TransactionStatus {..}) =+ pairs ( "height" .= txHeight+ <> "executed" .= txExecuted+ )
+ tests/Spec.hs view
@@ -0,0 +1,15 @@+import Test.Hspec+import Test.QuickCheck+import Control.Exception (evaluate)++main :: IO ()+main = hspec $ do+ describe "Prelude.head" $ do+ it "returns the first element of a list" $ do+ head [23 ..] `shouldBe` (23 :: Int)++ it "returns the first element of an *arbitrary* list" $+ property $ \x xs -> head (x:xs) == (x :: Int)++ it "throws an exception if used with an empty list" $ do+ evaluate (head []) `shouldThrow` anyException