Implement marking of orders as paid
This commit is contained in:
parent
738b28a4ef
commit
20061285a2
5 changed files with 74 additions and 20 deletions
|
@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- New functionality to read transactions for the given viewing keys
|
||||||
|
- New functionality to mark orders as paid once payment is found on-chain
|
||||||
- New `Config` type to house the configuration parameters
|
- New `Config` type to house the configuration parameters
|
||||||
- New field in `Owner` type to store toggle for payment confirmation
|
- New field in `Owner` type to store toggle for payment confirmation
|
||||||
- New field in `Owner` type to store viewing key
|
- New field in `Owner` type to store viewing key
|
||||||
|
|
|
@ -32,6 +32,7 @@ main = do
|
||||||
else fail "MongoDB connection failed!"
|
else fail "MongoDB connection failed!"
|
||||||
_ <- forkIO (setInterval 60 (checkZcashPrices pipe (c_dbName loadedConfig)))
|
_ <- forkIO (setInterval 60 (checkZcashPrices pipe (c_dbName loadedConfig)))
|
||||||
_ <- forkIO (setInterval 75 (scanZcash loadedConfig pipe))
|
_ <- forkIO (setInterval 75 (scanZcash loadedConfig pipe))
|
||||||
|
_ <- forkIO (setInterval 90 (scanPayments loadedConfig pipe))
|
||||||
_ <- forkIO (setInterval 60 (checkPayments pipe (c_dbName loadedConfig)))
|
_ <- forkIO (setInterval 60 (checkPayments pipe (c_dbName loadedConfig)))
|
||||||
_ <- forkIO (setInterval 60 (expireOwners pipe (c_dbName loadedConfig)))
|
_ <- forkIO (setInterval 60 (expireOwners pipe (c_dbName loadedConfig)))
|
||||||
_ <- forkIO (setInterval 60 (updateLogins pipe loadedConfig))
|
_ <- forkIO (setInterval 60 (updateLogins pipe loadedConfig))
|
||||||
|
|
|
@ -50,6 +50,7 @@ library:
|
||||||
- warp-tls
|
- warp-tls
|
||||||
- hexstring
|
- hexstring
|
||||||
- configurator
|
- configurator
|
||||||
|
- scientific
|
||||||
|
|
||||||
executables:
|
executables:
|
||||||
zgo-backend-exe:
|
zgo-backend-exe:
|
||||||
|
|
|
@ -18,6 +18,7 @@ import Data.Char
|
||||||
import qualified Data.HashMap.Strict as HM
|
import qualified Data.HashMap.Strict as HM
|
||||||
import Data.HexString
|
import Data.HexString
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import qualified Data.Scientific as Scientific
|
||||||
import Data.SecureMem
|
import Data.SecureMem
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
|
@ -137,11 +138,19 @@ instance FromJSON ZcashTx where
|
||||||
aZ <- obj .: "amountZat"
|
aZ <- obj .: "amountZat"
|
||||||
bh <- obj .: "blockheight"
|
bh <- obj .: "blockheight"
|
||||||
bt <- obj .: "blocktime"
|
bt <- obj .: "blocktime"
|
||||||
c <- obj .: "change"
|
c <- obj .:? "change"
|
||||||
conf <- obj .: "confirmations"
|
conf <- obj .: "confirmations"
|
||||||
m <- obj .: "memo"
|
m <- obj .: "memo"
|
||||||
pure $
|
pure $
|
||||||
ZcashTx t a aZ bh bt c conf (T.filter (/= '\NUL') $ decodeHexText m)
|
ZcashTx
|
||||||
|
t
|
||||||
|
a
|
||||||
|
aZ
|
||||||
|
bh
|
||||||
|
bt
|
||||||
|
(fromMaybe False c)
|
||||||
|
conf
|
||||||
|
(T.filter (/= '\NUL') $ decodeHexText m)
|
||||||
|
|
||||||
instance ToJSON ZcashTx where
|
instance ToJSON ZcashTx where
|
||||||
toJSON (ZcashTx t a aZ bh bt c conf m) =
|
toJSON (ZcashTx t a aZ bh bt c conf m) =
|
||||||
|
@ -315,8 +324,8 @@ zToZGoTx (ZcashTx t a aZ bh bt c conf m) = do
|
||||||
if not (null reg)
|
if not (null reg)
|
||||||
then do
|
then do
|
||||||
let sess = T.pack (fst $ head reg ! 1)
|
let sess = T.pack (fst $ head reg ! 1)
|
||||||
let addy = T.pack (fst $ head reg ! 2)
|
let nAddy = T.pack (fst $ head reg ! 2)
|
||||||
ZGoTx Nothing addy sess conf bt a t m
|
ZGoTx Nothing nAddy sess conf bt a t m
|
||||||
else do
|
else do
|
||||||
if not (null reg2)
|
if not (null reg2)
|
||||||
then do
|
then do
|
||||||
|
@ -711,19 +720,34 @@ checkZcashPrices p db = do
|
||||||
q <- getZcashPrices
|
q <- getZcashPrices
|
||||||
mapM_ (access p master db) (updatePrices (getResponseBody q))
|
mapM_ (access p master db) (updatePrices (getResponseBody q))
|
||||||
|
|
||||||
|
-- | Function to search for transactions for an address
|
||||||
|
listTxs ::
|
||||||
|
BS.ByteString
|
||||||
|
-> BS.ByteString
|
||||||
|
-> T.Text
|
||||||
|
-> Integer
|
||||||
|
-> IO (Either T.Text [ZcashTx])
|
||||||
|
listTxs user pwd a confs = do
|
||||||
|
res <-
|
||||||
|
liftIO $
|
||||||
|
makeZcashCall
|
||||||
|
user
|
||||||
|
pwd
|
||||||
|
"z_listreceivedbyaddress"
|
||||||
|
[Data.Aeson.String a, Data.Aeson.Number $ Scientific.scientific confs 0]
|
||||||
|
let content = getResponseBody res :: RpcResponse [ZcashTx]
|
||||||
|
case err content of
|
||||||
|
Nothing ->
|
||||||
|
return $ Right $ filter (not . zchange) $ fromMaybe [] $ result content
|
||||||
|
Just e -> return $ Left $ "Error reading transactions: " <> emessage e
|
||||||
|
|
||||||
-- | Function to check the ZGo full node for new txs
|
-- | Function to check the ZGo full node for new txs
|
||||||
scanZcash :: Config -> Pipe -> IO ()
|
scanZcash :: Config -> Pipe -> IO ()
|
||||||
scanZcash config pipe = do
|
scanZcash config pipe = do
|
||||||
res <-
|
myTxs <-
|
||||||
makeZcashCall
|
listTxs (c_nodeUser config) (c_nodePwd config) (c_nodeAddress config) 1
|
||||||
(c_nodeUser config)
|
case myTxs of
|
||||||
(c_nodePwd config)
|
Right txs -> do
|
||||||
"z_listreceivedbyaddress"
|
|
||||||
[Data.Aeson.String (c_nodeAddress config)]
|
|
||||||
let content = getResponseBody res :: RpcResponse [ZcashTx]
|
|
||||||
case err content of
|
|
||||||
Nothing -> do
|
|
||||||
let txs = filter (not . zchange) $ fromMaybe [] $ result content
|
|
||||||
let r =
|
let r =
|
||||||
mkRegex
|
mkRegex
|
||||||
".*ZGO::([0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12})\\sReply-To:\\s(zs[a-z0-9]{76}).*"
|
".*ZGO::([0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12})\\sReply-To:\\s(zs[a-z0-9]{76}).*"
|
||||||
|
@ -734,15 +758,40 @@ scanZcash config pipe = do
|
||||||
mapM_ (access pipe master (c_dbName config) . upsertZGoTx "txs") k
|
mapM_ (access pipe master (c_dbName config) . upsertZGoTx "txs") k
|
||||||
let j = map zToZGoTx (filter (isRelevant p) txs)
|
let j = map zToZGoTx (filter (isRelevant p) txs)
|
||||||
mapM_ (access pipe master (c_dbName config) . upsertPayment) j
|
mapM_ (access pipe master (c_dbName config) . upsertPayment) j
|
||||||
Just e -> do
|
Left e -> do
|
||||||
putStrLn $ "Error scanning node transactions: " ++ T.unpack (emessage e)
|
putStrLn $ "Error scanning node transactions: " ++ T.unpack e
|
||||||
return ()
|
return ()
|
||||||
where
|
|
||||||
isRelevant :: Text.Regex.Regex -> ZcashTx -> Bool
|
-- | Function to filter transactions
|
||||||
isRelevant re t
|
isRelevant :: Text.Regex.Regex -> ZcashTx -> Bool
|
||||||
|
isRelevant re t
|
||||||
| zconfirmations t < 10 && (matchTest re . T.unpack . zmemo) t = True
|
| zconfirmations t < 10 && (matchTest re . T.unpack . zmemo) t = True
|
||||||
| otherwise = False
|
| otherwise = False
|
||||||
|
|
||||||
|
-- | Function to scan loaded viewing keys for payments
|
||||||
|
scanPayments :: Config -> Pipe -> IO ()
|
||||||
|
scanPayments config pipe = do
|
||||||
|
shops <- listAddresses (c_nodeUser config) (c_nodePwd config)
|
||||||
|
mapM_ (findPaidOrders config pipe) shops
|
||||||
|
where
|
||||||
|
findPaidOrders :: Config -> Pipe -> ZcashAddress -> IO ()
|
||||||
|
findPaidOrders c p z = do
|
||||||
|
paidTxs <- listTxs (c_nodeUser c) (c_nodePwd c) (addy z) 5
|
||||||
|
case paidTxs of
|
||||||
|
Right txs -> do
|
||||||
|
let r = mkRegex ".*ZGo Order::([0-9a-fA-F]{24}).*"
|
||||||
|
let k = filter (isRelevant r) txs
|
||||||
|
let j = map (getOrderId r) k
|
||||||
|
mapM_ (access p master (c_dbName config) . markOrderPaid) j
|
||||||
|
Left e -> putStrLn $ T.unpack e
|
||||||
|
getOrderId :: Text.Regex.Regex -> ZcashTx -> String
|
||||||
|
getOrderId re t = do
|
||||||
|
let reg = matchAllText re (T.unpack $ zmemo t)
|
||||||
|
if not (null reg)
|
||||||
|
then do
|
||||||
|
fst $ head reg ! 1
|
||||||
|
else ""
|
||||||
|
|
||||||
-- | RPC methods
|
-- | RPC methods
|
||||||
-- | List addresses with viewing keys loaded
|
-- | List addresses with viewing keys loaded
|
||||||
listAddresses :: BS.ByteString -> BS.ByteString -> IO [ZcashAddress]
|
listAddresses :: BS.ByteString -> BS.ByteString -> IO [ZcashAddress]
|
||||||
|
|
|
@ -54,6 +54,7 @@ library
|
||||||
, random
|
, random
|
||||||
, regex-base
|
, regex-base
|
||||||
, regex-compat
|
, regex-compat
|
||||||
|
, scientific
|
||||||
, scotty
|
, scotty
|
||||||
, securemem
|
, securemem
|
||||||
, text
|
, text
|
||||||
|
|
Loading…
Reference in a new issue