From 462c72c882cd1fef9b9af9e241c522afcecee463 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 27 Jun 2022 09:25:36 -0500 Subject: [PATCH] Enhances memo decoding --- CHANGELOG.md | 10 ++++++++++ README.md | 3 +++ app/Main.hs | 3 ++- package.yaml | 1 + src/Zenith.hs | 28 +++++++++++++++++----------- stack.yaml | 2 +- zenith.cabal | 2 +- 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 958ceb8..16a9670 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.3.0.0] + +### Changed + +- Changed decoding of memos to support Unicode (emojis!) + +### Fixed + +- Displaying transactions for view-only addresses + ## [0.2.0.0] ### Added diff --git a/README.md b/README.md index 7defc84..04d1afd 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,9 @@ Zenith will attempt to connect to the node and check compatibility. Connections - `send`: Prompts the user to prepare an outgoing transaction, selecting the source address, validating the destination address, the amount and the memo. - If the source is a transparent address, the privacy policy is set to `AllowRevealedSenders`, favoring the shielding of funds when sent to a UA. - If the source is a shielded address, the privacy policy is set to `AllowRevealedAmounts`, favoring the move of funds from legacy shielded pools to Orchard. +- `uri`: Prompts the user to select the source account and to enter a [ZIP-321](https://zips.z.cash/zip-0321) compliant URI to generate and send a transaction. - `exit`: Ends the session. +### Support +If you would like to support the development of Zenith, please visit our [Free2Z](https://free2z.com/zenith-full-node-cli) page. diff --git a/app/Main.hs b/app/Main.hs index 96b2034..ced5fdc 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -9,6 +9,7 @@ import Data.Configurator import Data.Default (def) import Data.Sort import qualified Data.Text as T +import qualified Data.Text.IO as TIO import Data.Time.Clock.POSIX import System.Console.StructuredCLI import System.Exit @@ -155,7 +156,7 @@ displayTx t = do putStr "Zats: " print $ zamountZat t putStr "Memo: " - putStrLn $ T.unpack $ zmemo t + TIO.putStrLn $ zmemo t putStrLn "-----" processUri :: B.ByteString -> B.ByteString -> Commands () diff --git a/package.yaml b/package.yaml index 4548b1d..1ff8b69 100644 --- a/package.yaml +++ b/package.yaml @@ -50,6 +50,7 @@ executables: - -rtsopts - -with-rtsopts=-N - -Wall + - -Wunused-imports dependencies: - zenith - configurator diff --git a/src/Zenith.hs b/src/Zenith.hs index 900d540..df0c5c7 100644 --- a/src/Zenith.hs +++ b/src/Zenith.hs @@ -19,7 +19,10 @@ import Data.Functor (void) import Data.Maybe import qualified Data.Scientific as Scientific import qualified Data.Text as T +import qualified Data.Text.Encoding as E +import Data.Text.Encoding.Error (lenientDecode) import qualified Data.Vector as V +import Data.Word import GHC.Generics import Haskoin.Address.Bech32 import Network.HTTP.Simple @@ -199,7 +202,7 @@ instance FromJSON ZcashTx where aZ <- obj .: "amountZat" bh <- obj .: "blockheight" bt <- obj .: "blocktime" - c <- obj .: "change" + c <- obj .:? "change" conf <- obj .: "confirmations" m <- obj .:? "memo" pure $ @@ -209,11 +212,11 @@ instance FromJSON ZcashTx where aZ bh bt - c + (fromMaybe False c) conf (case m of Nothing -> "" - Just m' -> T.pack (filter (/= '\NUL') $ decodeHexText m')) + Just m' -> T.filter (/= '\NUL') $ decodeHexText m') instance ToJSON ZcashTx where toJSON (ZcashTx t a aZ bh bt c conf m) = @@ -288,12 +291,15 @@ instance FromJSON OpResult where pure $ OpResult s m t -- | Helper function to turn a hex-encoded memo strings to readable text -decodeHexText :: String -> String -decodeHexText hexText - | null chunk = "" - | otherwise = chr (read ("0x" <> chunk)) : decodeHexText (drop 2 hexText) +decodeHexText :: String -> T.Text +decodeHexText h = E.decodeUtf8With lenientDecode $ B.pack $ hexRead h where - chunk = take 2 hexText + hexRead hexText + | null chunk = [] + | otherwise = + fromIntegral (read ("0x" <> chunk)) : hexRead (drop 2 hexText) + where + chunk = take 2 hexText -- | Helper function to turn a string into a hex-encoded string encodeHexText :: String -> String @@ -375,7 +381,7 @@ listTxs user pwd zaddy = do makeZcashCall user pwd "z_listreceivedbyaddress" [String $ addy zaddy] let rpcResp = decode response :: Maybe (RpcResponse [ZcashTx]) case rpcResp of - Nothing -> fail "Couldn't parse node response" + Nothing -> fail "listTxs: Couldn't parse node response" Just res -> do return $ result res @@ -578,13 +584,13 @@ sendWithUri user pwd fromAddy uri = do Just amt -> do putStrLn $ " Valid ZEC amount: " ++ show amt let decodedMemo = B64.decodeLenient $ C.pack parsedEncodedMemo - putStrLn $ " Memo: " ++ show decodedMemo + putStrLn $ " Memo: " ++ C.unpack decodedMemo sendTx user pwd fromAddy (T.pack parsedAddress) amt - (show decodedMemo) + (C.unpack decodedMemo) else putStrLn " Invalid address" else putStrLn "URI is not compliant with ZIP-321" diff --git a/stack.yaml b/stack.yaml index fd6300b..1b94afe 100644 --- a/stack.yaml +++ b/stack.yaml @@ -42,7 +42,7 @@ packages: # commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a # # extra-deps: [] - +# # Override default flag values for local packages and extra-deps # flags: {} diff --git a/zenith.cabal b/zenith.cabal index e6d9ffc..8fe6b38 100644 --- a/zenith.cabal +++ b/zenith.cabal @@ -55,7 +55,7 @@ executable zenith Paths_zenith hs-source-dirs: app - ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall + ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall -Wunused-imports build-depends: base >=4.7 && <5 , bytestring