Compare commits

..

40 commits

Author SHA1 Message Date
e9e342e77f
Prepare for release 2024-07-11 08:38:20 -05:00
51cf375265
Merge branch 'milestone2' into rav001 2024-07-10 15:45:10 -05:00
2f88c89083
Version update 2024-06-21 12:58:31 -05:00
77a0890ac8
Merge pull request 'rvv041 - Change Zenith start parameter from CLI to TUI' (#88) from rvv041 into milestone2
Reviewed-on: #88
Reviewed-by: pitmutt <rene@vergara.network>
2024-06-12 17:18:39 +00:00
3a9c5a8430
Merge branch 'milestone2' into rvv041 2024-06-12 17:17:43 +00:00
f8bac14df3 rvv041 - Change Zenith start parameter from CLI to TUI 2024-06-11 19:34:40 -04:00
244bbf76a7
Merge pull request 'rvv041 - User Interface' (#87) from rvv041 into milestone2
Reviewed-on: #87
Reviewed-by: pitmutt <rene@vergara.network>
2024-06-11 19:14:00 +00:00
b63b0ff444
Merge branch 'milestone2' into rvv041 2024-06-11 19:13:43 +00:00
d1a5fdfa50 rvv041 - User Interface
some enhancements added
2024-06-07 20:53:32 -04:00
122d24a929
Merge pull request 'rvv041' (#82) from rvv041 into milestone2
Reviewed-on: #82
2024-06-07 20:03:05 +00:00
f89e9b72ca
Add debugging to prepareTx 2024-06-06 05:58:11 -05:00
84265de3e2 rvv041 - Merge branch 'milestone2' into rvv041
Some UI changes
2024-06-05 20:43:32 -04:00
3f33295bdc rvv041 - Code Optimization - Addreess Book
Address removed from Message windown in Copy Address Action result
2024-06-04 20:14:49 -04:00
8754c79079 rvv041 - Code Optimization
- Some comments removed
2024-06-03 22:10:30 -04:00
4f0fa9bc34 rvv041 - Code Optimization
- abText state variable removed
	 - AdrBookEntryDisplay refactored to use abAddresses state variable
2024-06-03 21:41:48 -04:00
c5b7714917 rvv041 - Bug - New address book entry not displaying when address buok
list  is empty
	       Fixed  -> RefreshAddressBook function reviwed and corrected
2024-06-03 18:17:50 -04:00
ddbd08d474 rvv041 - Code Optimizations
addressBookDescrip changed to addressBookAbdescrip
	 DB.hs and CLI.hs source files affected
2024-06-03 15:00:05 -04:00
772025e317 rvv041 - Code Optimizations
getABookRec function commented out from DB.hs
	 abaddresses state renamed to abAddresses
2024-06-03 14:48:01 -04:00
d57ac5db14 rvv041 - Code Optimizations
addressbook's column descrip renamed to abdescrip
	 _abText - variable used to hold AddressBook entry data for display
	 _abCurAdrs - variable used to hold unique key in CRUD operations
2024-06-03 14:28:39 -04:00
51116e8083 rvv041 - Code optimizations
ABList removed from focusRing
	 address_book's column address renamed to abaddress
2024-06-03 14:04:16 -04:00
1c88ea5f08 rvv041 - {-# LANGUAGE BlockArguments #-} removed 2024-06-03 12:53:24 -04:00
0b70bbb8de rvv041 - Improvement - Unused code removed 2024-06-02 09:02:12 -04:00
dbfc91d33a rvv041 - README.md updated 2024-06-01 20:20:38 -04:00
edb7422951 rvv001 - AddressBook completed - ready for tests 2024-06-01 20:04:18 -04:00
a33ae3b595 rvv041 - AddressBook -
Added a  window to show a address book entry
	 It is activated pressing Enter inside Address Book window
2024-06-01 18:02:43 -04:00
4cb4f401a3 rvv041 - AddressBook functionality
Delete addressbook entry in progress
2024-05-31 22:18:26 -04:00
bd1f4e3a5c rvv041 - AddressBook - Edit record working correctly.
DB.hs updated -
	   updateAdrsInAdrBook :: ConnectionPool -> T.Text -> T.Text -> T.Text -> IO ()
	 CLI.hs updated
2024-05-31 18:36:32 -04:00
28bbcb48f0 rvv041 - Address Book
Form to create a new Address Book entry
	Error control added to the form.
2024-05-30 17:27:59 -04:00
939a23f7ca rvv041 - Address Book functionality -
- Check added ::   value to send has to be > 0 and <= balance
2024-05-24 21:55:03 -04:00
16b5acabf2 rvv041 - Address Book updated
- Functionality to copy receiver address to Clipboard  added
	- Functionality to Send Zcash to selected AddresBook entry added
2024-05-24 21:23:06 -04:00
e946df43f8 rvv041 - Addresss Book Window working with static data
new attributes created for the box
	 At this stage, the Evenhandler is processing the exit command only
         to close the window and return to the main window.
2024-05-24 12:20:49 -04:00
2fb889b1a2 rvv041 - Main Menu updated -
Options for Address Book and Help windows added
2024-05-24 10:35:06 -04:00
8cb5211453 Merge branch 'milestone2' into rvv041 2024-05-23 13:59:49 -04:00
146e111586 Merge branch 'milestone2' into rvv041 2024-05-23 08:44:36 -04:00
83cc1905ad rvv041 - CRUD operations for AddressBook completed
delete record using AddressBookId
2024-05-14 18:17:21 -04:00
e9e56453c1 rvv041 - Insert and edit an address book entry functions created
address field in address book changed to T.Text
2024-05-13 16:26:07 -04:00
2fb6747bfb rvv041 - Address Book table added to database
getAdrBook function to get a list of all addresses
         recorded in AddressBook table
2024-05-12 20:39:48 -04:00
94b16f743f Commit zenith.db created 2024-05-10 22:11:23 -04:00
d6faa3e5e5 Merge branch 'master' into rvv041 2024-05-10 22:06:40 -04:00
3f4bfefe64 2024-05-10 - Initial commit from dev041 2024-05-10 21:07:19 -04:00
13 changed files with 580 additions and 162 deletions

4
.gitignore vendored
View file

@ -1,3 +1,7 @@
.stack-work/ .stack-work/
*~ *~
dist-newstyle/ dist-newstyle/
zenith.db
zenith.log
zenith.db-shm
zenith.db-wal

View file

@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [0.6.0.0-beta]
### Added ### Added
@ -25,12 +25,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Unconfirmed balance display on TUI and GUI - Unconfirmed balance display on TUI and GUI
- Tracking of unconfirmed notes - Tracking of unconfirmed notes
### Changed
- Upgraded to GHC 9.6.5
### Fixed ### Fixed
- Validation of input of amount for sending in TUI - Validation of input of amount for sending in TUI
### Removed
- Legacy interface to `zcashd`
## [0.5.3.1-beta]
### Added
- Docker image
## [0.5.3.0-beta] ## [0.5.3.0-beta]
### Added
- Address Book functionality. Allows users to store frequently used zcash addresses and
generate transactions using them.
### Changed ### Changed
- Improved formatting of sync progress - Improved formatting of sync progress

View file

@ -21,6 +21,7 @@ Zenith is a wallet for the [Zebra](https://zfnd.org/zebra/) Zcash node . It has
- Listing transactions for specific addresses, decoding memos for easy reading. - Listing transactions for specific addresses, decoding memos for easy reading.
- Copying addresses to the clipboard. - Copying addresses to the clipboard.
- Sending transactions with shielded memo support. - Sending transactions with shielded memo support.
- Address Book for storing frequently used zcash addresses
## Installation ## Installation

View file

@ -11,7 +11,8 @@ import Data.Sort
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.IO as TIO import qualified Data.Text.IO as TIO
import Data.Time.Clock.POSIX import Data.Time.Clock.POSIX
import System.Console.StructuredCLI
{-import System.Console.StructuredCLI-}
import System.Environment (getArgs) import System.Environment (getArgs)
import System.Exit import System.Exit
import System.IO import System.IO
@ -23,7 +24,7 @@ import Zenith.GUI (runZenithGUI)
import Zenith.Types (Config(..), ZcashAddress(..), ZcashPool(..), ZcashTx(..)) import Zenith.Types (Config(..), ZcashAddress(..), ZcashPool(..), ZcashTx(..))
import Zenith.Utils import Zenith.Utils
import Zenith.Zcashd import Zenith.Zcashd
{-
prompt :: String -> IO String prompt :: String -> IO String
prompt text = do prompt text = do
putStr text putStr text
@ -197,21 +198,22 @@ processUri user pwd =
_ -> False _ -> False
_ <- liftIO $ sendWithUri user pwd (addList !! (idx - 1)) u repTo _ <- liftIO $ sendWithUri user pwd (addList !! (idx - 1)) u repTo
return NoAction return NoAction
-}
main :: IO () main :: IO ()
main = do main = do
config <- load ["zenith.cfg"] config <- load ["zenith.cfg"]
args <- getArgs args <- getArgs
dbFilePath <- require config "dbFilePath" dbFilePath <- require config "dbFilePath"
nodeUser <- require config "nodeUser" {-nodeUser <- require config "nodeUser"-}
nodePwd <- require config "nodePwd" {-nodePwd <- require config "nodePwd"-}
zebraPort <- require config "zebraPort" zebraPort <- require config "zebraPort"
zebraHost <- require config "zebraHost" zebraHost <- require config "zebraHost"
let myConfig = Config dbFilePath zebraHost zebraPort let myConfig = Config dbFilePath zebraHost zebraPort
if not (null args) if not (null args)
then do then do
case head args of case head args
"legacy" -> do {-"legacy" -> do
checkServer nodeUser nodePwd checkServer nodeUser nodePwd
void $ void $
runCLI runCLI
@ -220,9 +222,10 @@ main = do
{ getBanner = { getBanner =
" ______ _ _ _ \n |___ / (_) | | | \n / / ___ _ __ _| |_| |__ \n / / / _ \\ '_ \\| | __| '_ \\ \n / /_| __/ | | | | |_| | | |\n /_____\\___|_| |_|_|\\__|_| |_|\n Zcash Full Node CLI v0.4.0" " ______ _ _ _ \n |___ / (_) | | | \n / / ___ _ __ _| |_| |__ \n / / / _ \\ '_ \\| | __| '_ \\ \n / /_| __/ | | | | |_| | | |\n /_____\\___|_| |_|_|\\__|_| |_|\n Zcash Full Node CLI v0.4.0"
} }
(root nodeUser nodePwd) (root nodeUser nodePwd) -}
"cli" -> runZenithCLI myConfig of
"gui" -> runZenithGUI myConfig "gui" -> runZenithGUI myConfig
"tui" -> runZenithTUI myConfig
"rescan" -> clearSync myConfig "rescan" -> clearSync myConfig
_ -> printUsage _ -> printUsage
else printUsage else printUsage
@ -231,6 +234,6 @@ printUsage :: IO ()
printUsage = do printUsage = do
putStrLn "zenith [command] [parameters]\n" putStrLn "zenith [command] [parameters]\n"
putStrLn "Available commands:" putStrLn "Available commands:"
putStrLn "legacy\tLegacy CLI for zcashd" {-putStrLn "legacy\tLegacy CLI for zcashd"-}
putStrLn "cli\tCLI for zebrad" putStrLn "tui\tTUI for zebrad"
putStrLn "rescan\tRescan the existing wallet(s)" putStrLn "rescan\tRescan the existing wallet(s)"

View file

@ -2,7 +2,7 @@ packages:
./*.cabal ./*.cabal
zcash-haskell/zcash-haskell.cabal zcash-haskell/zcash-haskell.cabal
with-compiler: ghc-9.4.8 with-compiler: ghc-9.6.5
source-repository-package source-repository-package
type: git type: git

View file

@ -1,12 +1,12 @@
active-repositories: hackage.haskell.org:merge active-repositories: hackage.haskell.org:merge
constraints: any.Cabal ==3.8.1.0, constraints: any.Cabal ==3.10.3.0,
any.Cabal-syntax ==3.8.1.0, any.Cabal-syntax ==3.10.3.0,
any.Clipboard ==2.3.2.0, any.Clipboard ==2.3.2.0,
any.HUnit ==1.6.2.0, any.HUnit ==1.6.2.0,
any.Hclip ==3.0.0.4, any.Hclip ==3.0.0.4,
any.JuicyPixels ==3.3.8, any.JuicyPixels ==3.3.9,
JuicyPixels -mmap, JuicyPixels -mmap,
any.OneTuple ==0.4.1.1, any.OneTuple ==0.4.2,
any.OpenGLRaw ==3.3.4.1, any.OpenGLRaw ==3.3.4.1,
OpenGLRaw -osandroid +usegles2 +useglxgetprocaddress +usenativewindowslibraries, OpenGLRaw -osandroid +usegles2 +useglxgetprocaddress +usenativewindowslibraries,
any.QuickCheck ==2.14.3, any.QuickCheck ==2.14.3,
@ -18,32 +18,32 @@ constraints: any.Cabal ==3.8.1.0,
any.X11 ==1.10.3, any.X11 ==1.10.3,
X11 -pedantic, X11 -pedantic,
any.adjunctions ==4.4.2, any.adjunctions ==4.4.2,
any.aeson ==2.2.1.0, any.aeson ==2.2.3.0,
aeson +ordered-keymap, aeson +ordered-keymap,
any.alex ==3.5.1.0, any.alex ==3.5.1.0,
any.ansi-terminal ==1.1, any.ansi-terminal ==1.1.1,
ansi-terminal -example, ansi-terminal -example,
any.ansi-terminal-types ==1.1, any.ansi-terminal-types ==1.1,
any.appar ==0.1.8, any.appar ==0.1.8,
any.array ==0.5.4.0, any.array ==0.5.6.0,
any.ascii-progress ==0.3.3.0, any.ascii-progress ==0.3.3.0,
ascii-progress -examples, ascii-progress -examples,
any.asn1-encoding ==0.9.6, any.asn1-encoding ==0.9.6,
any.asn1-parse ==0.9.5, any.asn1-parse ==0.9.5,
any.asn1-types ==0.3.4, any.asn1-types ==0.3.4,
any.assoc ==1.1, any.assoc ==1.1.1,
assoc +tagged, assoc -tagged,
any.async ==2.2.5, any.async ==2.2.5,
async -bench, async -bench,
any.attoparsec ==0.14.4, any.attoparsec ==0.14.4,
attoparsec -developer, attoparsec -developer,
any.attoparsec-aeson ==2.2.0.1, any.attoparsec-aeson ==2.2.2.0,
any.authenticate-oauth ==1.7, any.authenticate-oauth ==1.7,
any.auto-update ==0.1.6, any.auto-update ==0.2.1,
any.base ==4.17.2.1, any.base ==4.18.2.1,
any.base-compat ==0.13.1, any.base-compat ==0.14.0,
any.base-compat-batteries ==0.13.1, any.base-compat-batteries ==0.14.0,
any.base-orphans ==0.9.1, any.base-orphans ==0.9.2,
any.base16 ==1.0, any.base16 ==1.0,
any.base16-bytestring ==1.0.2.0, any.base16-bytestring ==1.0.2.0,
any.base58-bytestring ==0.1.0, any.base58-bytestring ==0.1.0,
@ -53,14 +53,14 @@ constraints: any.Cabal ==3.8.1.0,
bifunctors +tagged, bifunctors +tagged,
any.bimap ==0.5.0, any.bimap ==0.5.0,
any.binary ==0.8.9.1, any.binary ==0.8.9.1,
any.binary-orphans ==1.0.4.1, any.binary-orphans ==1.0.5,
any.bitvec ==1.1.5.0, any.bitvec ==1.1.5.0,
bitvec +simd, bitvec +simd,
any.blaze-builder ==0.4.2.3, any.blaze-builder ==0.4.2.3,
any.blaze-html ==0.9.2.0, any.blaze-html ==0.9.2.0,
any.blaze-markup ==0.8.3.0, any.blaze-markup ==0.8.3.0,
any.borsh ==0.3.0, any.borsh ==0.3.0,
any.brick ==2.3.1, any.brick ==2.4,
brick -demos, brick -demos,
any.byteorder ==1.0.4, any.byteorder ==1.0.4,
any.bytes ==0.17.3, any.bytes ==0.17.3,
@ -70,19 +70,20 @@ constraints: any.Cabal ==3.8.1.0,
any.bytestring-to-vector ==0.3.0.1, any.bytestring-to-vector ==0.3.0.1,
any.c2hs ==0.28.8, any.c2hs ==0.28.8,
c2hs +base3 -regression, c2hs +base3 -regression,
any.cabal-doctest ==1.0.9, any.cabal-doctest ==1.0.10,
any.call-stack ==0.4.0, any.call-stack ==0.4.0,
any.case-insensitive ==1.2.1.0, any.case-insensitive ==1.2.1.0,
any.cborg ==0.2.10.0, any.cborg ==0.2.10.0,
cborg +optimize-gmp, cborg +optimize-gmp,
any.cereal ==0.5.8.3, any.cereal ==0.5.8.3,
cereal -bytestring-builder, cereal -bytestring-builder,
any.character-ps ==0.1,
any.clock ==0.8.4, any.clock ==0.8.4,
clock -llvm, clock -llvm,
any.colour ==2.3.6, any.colour ==2.3.6,
any.comonad ==5.0.8, any.comonad ==5.0.8,
comonad +containers +distributive +indexed-traversable, comonad +containers +distributive +indexed-traversable,
any.concurrent-output ==1.10.20, any.concurrent-output ==1.10.21,
any.conduit ==1.3.5, any.conduit ==1.3.5,
any.conduit-extra ==1.3.6, any.conduit-extra ==1.3.6,
any.config-ini ==0.2.7.0, any.config-ini ==0.2.7.0,
@ -92,14 +93,14 @@ constraints: any.Cabal ==3.8.1.0,
any.containers ==0.6.7, any.containers ==0.6.7,
any.contravariant ==1.5.5, any.contravariant ==1.5.5,
contravariant +semigroups +statevar +tagged, contravariant +semigroups +statevar +tagged,
any.cookie ==0.4.6, any.cookie ==0.5.0,
any.crypto-api ==0.13.3, any.crypto-api ==0.13.3,
crypto-api -all_cpolys, crypto-api -all_cpolys,
any.crypto-pubkey-types ==0.4.3, any.crypto-pubkey-types ==0.4.3,
any.crypton ==0.34, any.crypton ==1.0.0,
crypton -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq +support_pclmuldq +support_rdrand -support_sse +use_target_attributes, crypton -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq +support_pclmuldq +support_rdrand -support_sse +use_target_attributes,
any.crypton-connection ==0.3.2, any.crypton-connection ==0.4.1,
any.crypton-x509 ==1.7.6, any.crypton-x509 ==1.7.7,
any.crypton-x509-store ==1.6.9, any.crypton-x509-store ==1.6.9,
any.crypton-x509-system ==1.6.7, any.crypton-x509-system ==1.6.7,
any.crypton-x509-validation ==1.6.12, any.crypton-x509-validation ==1.6.12,
@ -111,9 +112,9 @@ constraints: any.Cabal ==3.8.1.0,
any.data-default-instances-containers ==0.0.1, any.data-default-instances-containers ==0.0.1,
any.data-default-instances-dlist ==0.0.1, any.data-default-instances-dlist ==0.0.1,
any.data-default-instances-old-locale ==0.0.1, any.data-default-instances-old-locale ==0.0.1,
any.data-fix ==0.3.2, any.data-fix ==0.3.4,
any.deepseq ==1.4.8.0, any.deepseq ==1.4.8.1,
any.directory ==1.3.7.1, any.directory ==1.3.8.4,
any.distributive ==0.6.2.1, any.distributive ==0.6.2.1,
distributive +semigroups +tagged, distributive +semigroups +tagged,
any.dlist ==1.0, any.dlist ==1.0,
@ -125,13 +126,11 @@ constraints: any.Cabal ==3.8.1.0,
entropy -donotgetentropy, entropy -donotgetentropy,
any.envy ==2.1.3.0, any.envy ==2.1.3.0,
any.esqueleto ==3.5.11.2, any.esqueleto ==3.5.11.2,
any.exceptions ==0.10.5, any.exceptions ==0.10.7,
any.extra ==1.7.14, any.extra ==1.7.16,
any.fast-logger ==3.2.2, any.fast-logger ==3.2.3,
any.filepath ==1.4.2.2, any.filepath ==1.4.300.1,
any.fixed ==0.3, any.fixed ==0.3,
any.foldable1-classes-compat ==0.1,
foldable1-classes-compat +tagged,
any.foreign-rust ==0.1.0, any.foreign-rust ==0.1.0,
any.foreign-store ==0.2.1, any.foreign-store ==0.2.1,
any.formatting ==7.2.0, any.formatting ==7.2.0,
@ -141,30 +140,29 @@ constraints: any.Cabal ==3.8.1.0,
generic-deriving +base-4-9, generic-deriving +base-4-9,
any.generically ==0.1.1, any.generically ==0.1.1,
any.generics-sop ==0.5.1.4, any.generics-sop ==0.5.1.4,
any.ghc ==9.4.8, any.ghc ==9.6.5,
any.ghc-bignum ==1.3, any.ghc-bignum ==1.3,
any.ghc-boot ==9.4.8, any.ghc-boot ==9.6.5,
any.ghc-boot-th ==9.4.8, any.ghc-boot-th ==9.6.5,
any.ghc-heap ==9.4.8, any.ghc-heap ==9.6.5,
any.ghc-prim ==0.9.1, any.ghc-prim ==0.10.0,
any.ghci ==9.4.8, any.ghci ==9.6.5,
any.half ==0.3.1, any.half ==0.3.1,
any.happy ==1.20.1.1, any.happy ==1.20.1.1,
any.hashable ==1.4.4.0, any.hashable ==1.4.7.0,
hashable +integer-gmp -random-initial-seed, hashable -arch-native +integer-gmp -random-initial-seed,
any.haskeline ==0.8.2,
any.haskell-lexer ==1.1.1, any.haskell-lexer ==1.1.1,
any.haskoin-core ==1.1.0, any.haskoin-core ==1.1.0,
any.hexstring ==0.12.1.0, any.hexstring ==0.12.1.0,
any.hourglass ==0.2.12, any.hourglass ==0.2.12,
any.hpc ==0.6.1.0, any.hpc ==0.6.2.0,
any.hsc2hs ==0.68.10, any.hsc2hs ==0.68.10,
hsc2hs -in-ghc-tree, hsc2hs -in-ghc-tree,
any.hspec ==2.11.7, any.hspec ==2.11.9,
any.hspec-core ==2.11.7, any.hspec-core ==2.11.9,
any.hspec-discover ==2.11.7, any.hspec-discover ==2.11.9,
any.hspec-expectations ==0.8.4, any.hspec-expectations ==0.8.4,
any.http-api-data ==0.6, any.http-api-data ==0.6.1,
http-api-data -use-text-show, http-api-data -use-text-show,
any.http-client ==0.7.17, any.http-client ==0.7.17,
http-client +network-uri, http-client +network-uri,
@ -172,18 +170,18 @@ constraints: any.Cabal ==3.8.1.0,
any.http-conduit ==2.3.8.3, any.http-conduit ==2.3.8.3,
http-conduit +aeson, http-conduit +aeson,
any.http-types ==0.12.4, any.http-types ==0.12.4,
any.indexed-traversable ==0.1.3, any.indexed-traversable ==0.1.4,
any.indexed-traversable-instances ==0.1.1.2, any.indexed-traversable-instances ==0.1.2,
any.integer-conversion ==0.1.0.1, any.integer-conversion ==0.1.1,
any.integer-gmp ==1.1, any.integer-gmp ==1.1,
any.integer-logarithms ==1.0.3.1, any.integer-logarithms ==1.0.3.1,
integer-logarithms -check-bounds +integer-gmp, integer-logarithms -check-bounds +integer-gmp,
any.invariant ==0.6.3, any.invariant ==0.6.3,
any.iproute ==1.7.12, any.iproute ==1.7.12,
any.kan-extensions ==5.2.5, any.kan-extensions ==5.2.6,
any.language-c ==0.9.3, any.language-c ==0.9.3,
language-c -allwarnings +iecfpextension +usebytestrings, language-c -allwarnings +iecfpextension +usebytestrings,
any.lens ==5.2.3, any.lens ==5.3.2,
lens -benchmark-uniplate -dump-splices +inlining -j +test-hunit +test-properties +test-templates +trustworthy, lens -benchmark-uniplate -dump-splices +inlining -j +test-hunit +test-properties +test-templates +trustworthy,
any.lens-aeson ==1.2.3, any.lens-aeson ==1.2.3,
any.lift-type ==0.1.1.1, any.lift-type ==0.1.1.1,
@ -196,7 +194,7 @@ constraints: any.Cabal ==3.8.1.0,
memory +support_bytestring +support_deepseq, memory +support_bytestring +support_deepseq,
any.microlens ==0.4.13.1, any.microlens ==0.4.13.1,
any.microlens-mtl ==0.2.0.3, any.microlens-mtl ==0.2.0.3,
any.microlens-th ==0.4.3.14, any.microlens-th ==0.4.3.15,
any.mime-types ==0.1.2.0, any.mime-types ==0.1.2.0,
any.monad-control ==1.0.3.1, any.monad-control ==1.0.3.1,
any.monad-logger ==0.3.40, any.monad-logger ==0.3.40,
@ -206,16 +204,16 @@ constraints: any.Cabal ==3.8.1.0,
any.mono-traversable ==1.0.17.0, any.mono-traversable ==1.0.17.0,
any.monomer ==1.6.0.1, any.monomer ==1.6.0.1,
monomer -examples, monomer -examples,
any.mtl ==2.2.2, any.mtl ==2.3.1,
any.murmur3 ==1.0.5, any.murmur3 ==1.0.5,
any.nanovg ==0.8.1.0, any.nanovg ==0.8.1.0,
nanovg -examples -gl2 -gles3 -stb_truetype, nanovg -examples -gl2 -gles3 -stb_truetype,
any.network ==3.1.4.0, any.network ==3.2.1.0,
network -devel, network -devel,
any.network-uri ==2.6.4.2, any.network-uri ==2.6.4.2,
any.old-locale ==1.0.0.7, any.old-locale ==1.0.0.7,
any.old-time ==1.1.0.4, any.old-time ==1.1.0.4,
any.os-string ==2.0.2, any.os-string ==2.0.6,
any.parallel ==3.2.2.0, any.parallel ==3.2.2.0,
any.parsec ==3.1.16.1, any.parsec ==3.1.16.1,
any.parser-combinators ==1.3.0, any.parser-combinators ==1.3.0,
@ -228,7 +226,7 @@ constraints: any.Cabal ==3.8.1.0,
any.persistent-template ==2.12.0.0, any.persistent-template ==2.12.0.0,
any.pretty ==1.1.3.6, any.pretty ==1.1.3.6,
any.primitive ==0.9.0.0, any.primitive ==0.9.0.0,
any.process ==1.6.18.0, any.process ==1.6.19.0,
any.profunctors ==5.6.2, any.profunctors ==5.6.2,
any.psqueues ==0.2.8.0, any.psqueues ==0.2.8.0,
any.pureMD5 ==2.1.4, any.pureMD5 ==2.1.4,
@ -238,7 +236,7 @@ constraints: any.Cabal ==3.8.1.0,
any.quickcheck-io ==0.2.0, any.quickcheck-io ==0.2.0,
any.quickcheck-transformer ==0.3.1.2, any.quickcheck-transformer ==0.3.1.2,
any.random ==1.2.1.2, any.random ==1.2.1.2,
any.reflection ==2.1.7, any.reflection ==2.1.8,
reflection -slow +template-haskell, reflection -slow +template-haskell,
any.regex-base ==0.94.0.2, any.regex-base ==0.94.0.2,
any.regex-compat ==0.95.2.1, any.regex-compat ==0.95.2.1,
@ -249,14 +247,14 @@ constraints: any.Cabal ==3.8.1.0,
any.rts ==1.0.2, any.rts ==1.0.2,
any.safe ==0.3.21, any.safe ==0.3.21,
any.safe-exceptions ==0.1.7.4, any.safe-exceptions ==0.1.7.4,
any.scientific ==0.3.7.0, any.scientific ==0.3.8.0,
scientific -bytestring-builder -integer-simple, scientific -integer-simple,
any.sdl2 ==2.5.5.0, any.sdl2 ==2.5.5.0,
sdl2 -examples -no-linear -opengl-example +pkgconfig +recent-ish, sdl2 -examples -no-linear -opengl-example +pkgconfig +recent-ish,
any.secp256k1-haskell ==1.2.0, any.secp256k1-haskell ==1.2.0,
any.semialign ==1.3, any.semialign ==1.3.1,
semialign +semigroupoids, semialign +semigroupoids,
any.semigroupoids ==6.0.0.1, any.semigroupoids ==6.0.1,
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers, semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
any.semigroups ==0.20, any.semigroups ==0.20,
semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers, semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers,
@ -273,57 +271,53 @@ constraints: any.Cabal ==3.8.1.0,
any.stm-chans ==3.0.0.9, any.stm-chans ==3.0.0.9,
any.streaming-commons ==0.2.2.6, any.streaming-commons ==0.2.2.6,
streaming-commons -use-bytestring-builder, streaming-commons -use-bytestring-builder,
any.strict ==0.5, any.strict ==0.5.1,
any.string-conversions ==0.4.0.1, any.string-conversions ==0.4.0.1,
any.structured-cli ==2.7.0.1,
structured-cli -debug,
any.system-cxx-std-lib ==1.0, any.system-cxx-std-lib ==1.0,
any.tagged ==0.8.8, any.tagged ==0.8.8,
tagged +deepseq +transformers, tagged +deepseq +transformers,
any.template-haskell ==2.19.0.0, any.template-haskell ==2.20.0.0,
any.terminal-size ==0.3.4, any.terminal-size ==0.3.4,
any.terminfo ==0.4.1.5, any.terminfo ==0.4.1.6,
any.text ==2.0.2, any.text ==2.0.2,
any.text-iso8601 ==0.1, any.text-iso8601 ==0.1.1,
any.text-short ==0.1.5, any.text-short ==0.1.6,
text-short -asserts, text-short -asserts,
any.text-show ==3.10.4, any.text-show ==3.10.5,
text-show +base-4-9 +integer-gmp +new-functor-classes +template-haskell-2-11, text-show +base-4-9 +integer-gmp +new-functor-classes +template-haskell-2-11,
any.text-zipper ==0.13, any.text-zipper ==0.13,
any.tf-random ==0.5, any.tf-random ==0.5,
any.th-abstraction ==0.6.0.0, any.th-abstraction ==0.7.0.0,
any.th-compat ==0.1.5, any.th-compat ==0.1.5,
any.th-lift ==0.8.4, any.th-lift ==0.8.4,
any.th-lift-instances ==0.1.20, any.th-lift-instances ==0.1.20,
any.these ==1.2, any.these ==1.2.1,
any.time ==1.12.2, any.time ==1.12.2,
any.time-compat ==1.9.6.1, any.time-compat ==1.9.7,
time-compat -old-locale,
any.time-locale-compat ==0.1.1.5, any.time-locale-compat ==0.1.1.5,
time-locale-compat -old-locale, time-locale-compat -old-locale,
any.tls ==2.0.2, any.tls ==2.1.0,
tls -devel, tls -devel,
any.transformers ==0.5.6.2, any.transformers ==0.6.1.0,
any.transformers-base ==0.4.6, any.transformers-base ==0.4.6,
transformers-base +orphaninstances, transformers-base +orphaninstances,
any.transformers-compat ==0.7.2, any.transformers-compat ==0.7.2,
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two, transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
any.typed-process ==0.2.11.1, any.typed-process ==0.2.11.1,
any.unix ==2.7.3, any.unix ==2.8.4.0,
any.unix-compat ==0.7.1, any.unix-compat ==0.7.2,
unix-compat -old-time, any.unix-time ==0.4.15,
any.unix-time ==0.4.12,
any.unliftio ==0.2.25.0, any.unliftio ==0.2.25.0,
any.unliftio-core ==0.2.1.0, any.unliftio-core ==0.2.1.0,
any.unordered-containers ==0.2.20, any.unordered-containers ==0.2.20,
unordered-containers -debug, unordered-containers -debug,
any.utf8-string ==1.0.2, any.utf8-string ==1.0.2,
any.uuid-types ==1.0.5.1, any.uuid-types ==1.0.6,
any.vault ==0.3.1.5, any.vault ==0.3.1.5,
vault +useghc, vault +useghc,
any.vector ==0.13.1.0, any.vector ==0.13.1.0,
vector +boundschecks -internalchecks -unsafechecks -wall, vector +boundschecks -internalchecks -unsafechecks -wall,
any.vector-algorithms ==0.9.0.1, any.vector-algorithms ==0.9.0.2,
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks, vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
any.vector-stream ==0.1.0.1, any.vector-stream ==0.1.0.1,
any.void ==0.7.3, any.void ==0.7.3,
@ -333,10 +327,10 @@ constraints: any.Cabal ==3.8.1.0,
vty-crossplatform -demos, vty-crossplatform -demos,
any.vty-unix ==0.2.0.0, any.vty-unix ==0.2.0.0,
any.wide-word ==0.1.6.0, any.wide-word ==0.1.6.0,
any.witherable ==0.4.2, any.witherable ==0.5,
any.word-wrap ==0.5, any.word-wrap ==0.5,
any.wreq ==0.5.4.3, any.wreq ==0.5.4.3,
wreq -aws -developer +doctest -httpbin, wreq -aws -developer +doctest -httpbin,
any.zlib ==0.6.3.0, any.zlib ==0.7.1.0,
zlib -bundled-c-zlib +non-blocking-ffi +pkg-config zlib -bundled-c-zlib +non-blocking-ffi +pkg-config
index-state: hackage.haskell.org 2024-04-07T10:14:52Z index-state: hackage.haskell.org 2024-07-10T18:40:26Z

View file

@ -10,8 +10,10 @@ import qualified Brick.BChan as BC
import qualified Brick.Focus as F import qualified Brick.Focus as F
import Brick.Forms import Brick.Forms
( Form(..) ( Form(..)
, FormFieldState
, (@@=) , (@@=)
, allFieldsValid , allFieldsValid
, editShowableField
, editShowableFieldWithValidate , editShowableFieldWithValidate
, editTextField , editTextField
, focusedFormInputAttr , focusedFormInputAttr
@ -40,6 +42,9 @@ import Brick.Widgets.Core
, joinBorders , joinBorders
, padAll , padAll
, padBottom , padBottom
, padLeft
, padTop
, setAvailableSize
, str , str
, strWrap , strWrap
, strWrapWith , strWrapWith
@ -49,6 +54,7 @@ import Brick.Widgets.Core
, updateAttrMap , updateAttrMap
, vBox , vBox
, vLimit , vLimit
, viewport
, withAttr , withAttr
, withBorderStyle , withBorderStyle
) )
@ -116,6 +122,10 @@ data Name
| RecField | RecField
| AmtField | AmtField
| MemoField | MemoField
| ABViewport
| ABList
| DescripField
| AddressField
deriving (Eq, Show, Ord) deriving (Eq, Show, Ord)
data DialogInput = DialogInput data DialogInput = DialogInput
@ -132,6 +142,13 @@ data SendInput = SendInput
makeLenses ''SendInput makeLenses ''SendInput
data AdrBookEntry = AdrBookEntry
{ _descrip :: !T.Text
, _address :: !T.Text
} deriving (Show)
makeLenses ''AdrBookEntry
data DialogType data DialogType
= WName = WName
| AName | AName
@ -140,6 +157,10 @@ data DialogType
| ASelect | ASelect
| SendTx | SendTx
| Blank | Blank
| AdrBook
| AdrBookForm
| AdrBookUpdForm
| AdrBookDelForm
data DisplayType data DisplayType
= AddrDisplay = AddrDisplay
@ -149,6 +170,7 @@ data DisplayType
| TxIdDisplay | TxIdDisplay
| SyncDisplay | SyncDisplay
| SendDisplay | SendDisplay
| AdrBookEntryDisplay
| BlankDisplay | BlankDisplay
data Tick data Tick
@ -179,6 +201,9 @@ data State = State
, _eventDispatch :: !(BC.BChan Tick) , _eventDispatch :: !(BC.BChan Tick)
, _timer :: !Int , _timer :: !Int
, _txForm :: !(Form SendInput () Name) , _txForm :: !(Form SendInput () Name)
, _abAddresses :: !(L.List Name (Entity AddressBook))
, _abForm :: !(Form AdrBookEntry () Name)
, _abCurAdrs :: !T.Text -- used for address book CRUD operations
, _sentTx :: !(Maybe HexString) , _sentTx :: !(Maybe HexString)
, _unconfBalance :: !Integer , _unconfBalance :: !Integer
} }
@ -197,11 +222,12 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
(" Zenith - " <> (" Zenith - " <>
show (st ^. network) <> show (st ^. network) <>
" - " <> " - " <>
T.unpack (T.unpack
(maybe (maybe
"(None)" "(None)"
(\(_, w) -> zcashWalletName $ entityVal w) (\(_, w) -> zcashWalletName $ entityVal w)
(L.listSelectedElement (st ^. wallets))))) (L.listSelectedElement (st ^. wallets)))) ++
" "))
(C.hCenter (C.hCenter
(str (str
("Account: " ++ ("Account: " ++
@ -224,7 +250,8 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
else displayTaz (st ^. unconfBalance))) <=> else displayTaz (st ^. unconfBalance))) <=>
listAddressBox "Addresses" (st ^. addresses) <+> listAddressBox "Addresses" (st ^. addresses) <+>
B.vBorder <+> B.vBorder <+>
(C.hCenter (str ("Last block seen: " ++ show (st ^. syncBlock))) <=> (C.hCenter
(str ("Last block seen: " ++ show (st ^. syncBlock) ++ "\n")) <=>
listTxBox " Transactions " (st ^. network) (st ^. transactions))) <=> listTxBox " Transactions " (st ^. network) (st ^. transactions))) <=>
C.hCenter C.hCenter
(hBox (hBox
@ -232,7 +259,9 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
, capCommand "A" "ccounts" , capCommand "A" "ccounts"
, capCommand "V" "iew address" , capCommand "V" "iew address"
, capCommand "S" "end Tx" , capCommand "S" "end Tx"
, capCommand2 "Address " "B" "ook"
, capCommand "Q" "uit" , capCommand "Q" "uit"
, capCommand "?" " Help"
, str $ show (st ^. timer) , str $ show (st ^. timer)
]) ])
listBox :: Show e => String -> L.List Name e -> Widget Name listBox :: Show e => String -> L.List Name e -> Widget Name
@ -271,7 +300,7 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
(hBox (hBox
[ capCommand "↑↓ " "move" [ capCommand "↑↓ " "move"
, capCommand "" "select" , capCommand "" "select"
, capCommand "Tab " "->" , capCommand3 "" "Tab" " ->"
]) ])
] ]
listTxBox :: listTxBox ::
@ -287,7 +316,7 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
(hBox (hBox
[ capCommand "↑↓ " "move" [ capCommand "↑↓ " "move"
, capCommand "T" "x Display" , capCommand "T" "x Display"
, capCommand "Tab " "<-" , capCommand3 "" "Tab" " <-"
]) ])
] ]
helpDialog :: State -> Widget Name helpDialog :: State -> Widget Name
@ -299,7 +328,8 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
vBox ([str "Actions", B.hBorder] <> actionList)) vBox ([str "Actions", B.hBorder] <> actionList))
else emptyWidget else emptyWidget
where where
keyList = map (C.hCenter . str) ["?", "Esc", "w", "a", "v", "q"] keyList =
map (C.hCenter . str) ["?", "Esc", "w", "a", "v", "s", "b", "q"]
actionList = actionList =
map map
(hLimit 40 . str) (hLimit 40 . str)
@ -308,6 +338,8 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
, "Switch wallets" , "Switch wallets"
, "Switch accounts" , "Switch accounts"
, "View address" , "View address"
, "Send Tx"
, "Address Book"
, "Quit" , "Quit"
] ]
inputDialog :: State -> Widget Name inputDialog :: State -> Widget Name
@ -355,6 +387,58 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
C.hCenter C.hCenter
(hBox [capCommand "" "Send", capCommand "<esc> " "Cancel"])) (hBox [capCommand "" "Send", capCommand "<esc> " "Cancel"]))
Blank -> emptyWidget Blank -> emptyWidget
-- Address Book List
AdrBook ->
D.renderDialog
(D.dialog (Just $ str " Address Book ") Nothing 60)
(withAttr abDefAttr $
setAvailableSize (50, 20) $
viewport ABViewport BT.Vertical $
vLimit 20 $
hLimit 50 $
vBox
[ vLimit 16 $
hLimit 50 $
vBox $ [L.renderList listDrawAB True (s ^. abAddresses)]
, padTop Max $
vLimit 4 $
hLimit 50 $
withAttr abMBarAttr $
vBox $
[ C.hCenter $
(capCommand "N" "ew Address" <+>
capCommand "E" "dit Address" <+>
capCommand3 "" "C" "opy Address")
, C.hCenter $
(capCommand "D" "elete Address" <+>
capCommand "S" "end Zcash" <+> capCommand3 "E" "x" "it")
]
])
-- Address Book new entry form
AdrBookForm ->
D.renderDialog
(D.dialog (Just $ str " New Address Book Entry ") Nothing 50)
(renderForm (st ^. abForm) <=>
C.hCenter
(hBox [capCommand "" " Save", capCommand3 "" "<Esc>" " Cancel"]))
-- Address Book edit/update entry form
AdrBookUpdForm ->
D.renderDialog
(D.dialog (Just $ str " Edit Address Book Entry ") Nothing 50)
(renderForm (st ^. abForm) <=>
C.hCenter
(hBox [capCommand "" " Save", capCommand3 "" "<Esc>" " Cancel"]))
-- Address Book edit/update entry form
AdrBookDelForm ->
D.renderDialog
(D.dialog (Just $ str " Delete Address Book Entry ") Nothing 50)
(renderForm (st ^. abForm) <=>
C.hCenter
(hBox
[ capCommand "C" "onfirm delete"
, capCommand3 "" "<Esc>" " Cancel"
]))
--
splashDialog :: State -> Widget Name splashDialog :: State -> Widget Name
splashDialog st = splashDialog st =
if st ^. splashBox if st ^. splashBox
@ -366,9 +450,14 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
(str (str
" _____ _ _ _ \n|__ /___ _ __ (_) |_| |__\n / // _ \\ '_ \\| | __| '_ \\\n / /| __/ | | | | |_| | | |\n/____\\___|_| |_|_|\\__|_| |_|") <=> " _____ _ _ _ \n|__ /___ _ __ (_) |_| |__\n / // _ \\ '_ \\| | __| '_ \\\n / /| __/ | | | | |_| | | |\n/____\\___|_| |_|_|\\__|_| |_|") <=>
C.hCenter C.hCenter
(withAttr titleAttr (str "Zcash Wallet v0.5.3.0-beta")) <=> (withAttr titleAttr (str "Zcash Wallet v0.6.0.0-beta")) <=>
C.hCenter (withAttr blinkAttr $ str "Press any key...")) C.hCenter (withAttr blinkAttr $ str "Press any key..."))
else emptyWidget else emptyWidget
capCommand3 :: String -> String -> String -> Widget Name
capCommand3 l h e = hBox [str l, withAttr titleAttr (str h), str e]
capCommand2 :: String -> String -> String -> Widget Name
capCommand2 l h e =
hBox [str l, withAttr titleAttr (str h), str e, str " | "]
capCommand :: String -> String -> Widget Name capCommand :: String -> String -> Widget Name
capCommand k comm = hBox [withAttr titleAttr (str k), str comm, str " | "] capCommand k comm = hBox [withAttr titleAttr (str k), str comm, str " | "]
xCommand :: Widget Name xCommand :: Widget Name
@ -492,6 +581,22 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
(strWrapWith (strWrapWith
(WrapSettings False True NoFill FillAfterFirst) (WrapSettings False True NoFill FillAfterFirst)
(st ^. msg))) (st ^. msg)))
AdrBookEntryDisplay -> do
case L.listSelectedElement $ st ^. abAddresses of
Just (_, a) -> do
let abentry =
T.pack $
" Descr: " ++
T.unpack (addressBookAbdescrip (entityVal a)) ++
"\n Address: " ++
T.unpack (addressBookAbaddress (entityVal a))
withBorderStyle unicodeBold $
D.renderDialog
(D.dialog (Just $ txt " Address Book Entry ") Nothing 60)
(padAll 1 $
txtWrapWith (WrapSettings False True NoFill FillAfterFirst) $
abentry)
_ -> emptyWidget
BlankDisplay -> emptyWidget BlankDisplay -> emptyWidget
mkInputForm :: DialogInput -> Form DialogInput e Name mkInputForm :: DialogInput -> Form DialogInput e Name
@ -516,6 +621,16 @@ mkSendForm bal =
label s w = label s w =
padBottom (Pad 1) $ vLimit 1 (hLimit 15 $ str s <+> fill ' ') <+> w padBottom (Pad 1) $ vLimit 1 (hLimit 15 $ str s <+> fill ' ') <+> w
mkNewABForm :: AdrBookEntry -> Form AdrBookEntry e Name
mkNewABForm =
newForm
[ label "Descrip: " @@= editTextField descrip DescripField (Just 1)
, label "Address: " @@= editTextField address AddressField (Just 1)
]
where
label s w =
padBottom (Pad 1) $ vLimit 1 (hLimit 10 $ str s <+> fill ' ') <+> w
listDrawElement :: (Show a) => Bool -> a -> Widget Name listDrawElement :: (Show a) => Bool -> a -> Widget Name
listDrawElement sel a = listDrawElement sel a =
let selStr s = let selStr s =
@ -572,6 +687,14 @@ listDrawTx znet sel tx =
then withAttr customAttr (txt $ "> " <> s) then withAttr customAttr (txt $ "> " <> s)
else txt $ " " <> s else txt $ " " <> s
listDrawAB :: Bool -> Entity AddressBook -> Widget Name
listDrawAB sel ab =
let selStr s =
if sel
then withAttr abSelAttr (txt $ " " <> s)
else txt $ " " <> s
in selStr $ addressBookAbdescrip (entityVal ab)
customAttr :: A.AttrName customAttr :: A.AttrName
customAttr = L.listSelectedAttr <> A.attrName "custom" customAttr = L.listSelectedAttr <> A.attrName "custom"
@ -590,6 +713,15 @@ barDoneAttr = A.attrName "done"
barToDoAttr :: A.AttrName barToDoAttr :: A.AttrName
barToDoAttr = A.attrName "remaining" barToDoAttr = A.attrName "remaining"
abDefAttr :: A.AttrName
abDefAttr = A.attrName "abdefault"
abSelAttr :: A.AttrName
abSelAttr = A.attrName "abselected"
abMBarAttr :: A.AttrName
abMBarAttr = A.attrName "menubar"
scanZebra :: T.Text -> T.Text -> Int -> Int -> BC.BChan Tick -> IO () scanZebra :: T.Text -> T.Text -> Int -> Int -> BC.BChan Tick -> IO ()
scanZebra dbP zHost zPort b eChan = do scanZebra dbP zHost zPort b eChan = do
_ <- liftIO $ initDb dbP _ <- liftIO $ initDb dbP
@ -627,8 +759,7 @@ scanZebra dbP zHost zPort b eChan = do
"getblock" "getblock"
[Data.Aeson.String $ T.pack $ show bl, jsonNumber 1] [Data.Aeson.String $ T.pack $ show bl, jsonNumber 1]
case r of case r of
Left e1 -> do Left e1 -> liftIO $ BC.writeBChan eChan $ TickMsg e1
liftIO $ BC.writeBChan eChan $ TickMsg e1
Right blk -> do Right blk -> do
r2 <- r2 <-
liftIO $ liftIO $
@ -638,8 +769,7 @@ scanZebra dbP zHost zPort b eChan = do
"getblock" "getblock"
[Data.Aeson.String $ T.pack $ show bl, jsonNumber 0] [Data.Aeson.String $ T.pack $ show bl, jsonNumber 0]
case r2 of case r2 of
Left e2 -> do Left e2 -> liftIO $ BC.writeBChan eChan $ TickMsg e2
liftIO $ BC.writeBChan eChan $ TickMsg e2
Right hb -> do Right hb -> do
let blockTime = getBlockTime hb let blockTime = getBlockTime hb
mapM_ (runNoLoggingT . processTx zHost zPort blockTime pool) $ mapM_ (runNoLoggingT . processTx zHost zPort blockTime pool) $
@ -666,8 +796,8 @@ appEvent (BT.AppEvent t) = do
TxDisplay -> return () TxDisplay -> return ()
TxIdDisplay -> return () TxIdDisplay -> return ()
SyncDisplay -> return () SyncDisplay -> return ()
SendDisplay -> do SendDisplay -> BT.modify $ set msg m
BT.modify $ set msg m AdrBookEntryDisplay -> return ()
BlankDisplay -> return () BlankDisplay -> return ()
TickTx txid -> do TickTx txid -> do
BT.modify $ set sentTx (Just txid) BT.modify $ set sentTx (Just txid)
@ -680,6 +810,7 @@ appEvent (BT.AppEvent t) = do
TxDisplay -> return () TxDisplay -> return ()
TxIdDisplay -> return () TxIdDisplay -> return ()
SendDisplay -> return () SendDisplay -> return ()
AdrBookEntryDisplay -> return ()
SyncDisplay -> do SyncDisplay -> do
if s ^. barValue == 1.0 if s ^. barValue == 1.0
then do then do
@ -712,6 +843,10 @@ appEvent (BT.AppEvent t) = do
WSelect -> return () WSelect -> return ()
ASelect -> return () ASelect -> return ()
SendTx -> return () SendTx -> return ()
AdrBook -> return ()
AdrBookForm -> return ()
AdrBookUpdForm -> return ()
AdrBookDelForm -> return ()
Blank -> do Blank -> do
if s ^. timer == 90 if s ^. timer == 90
then do then do
@ -729,8 +864,7 @@ appEvent (BT.AppEvent t) = do
(s ^. eventDispatch) (s ^. eventDispatch)
BT.modify $ set timer 0 BT.modify $ set timer 0
return () return ()
else do else BT.modify $ set timer $ 1 + s ^. timer
BT.modify $ set timer $ 1 + s ^. timer
appEvent (BT.VtyEvent e) = do appEvent (BT.VtyEvent e) = do
r <- F.focusGetCurrent <$> use focusRing r <- F.focusGetCurrent <$> use focusRing
s <- BT.get s <- BT.get
@ -739,8 +873,7 @@ appEvent (BT.VtyEvent e) = do
else if s ^. helpBox else if s ^. helpBox
then do then do
case e of case e of
V.EvKey V.KEsc [] -> do V.EvKey V.KEsc [] -> BT.modify $ set helpBox False
BT.modify $ set helpBox False
_ev -> return () _ev -> return ()
else do else do
case s ^. displayBox of case s ^. displayBox of
@ -811,6 +944,7 @@ appEvent (BT.VtyEvent e) = do
_ev -> return () _ev -> return ()
SendDisplay -> BT.modify $ set displayBox BlankDisplay SendDisplay -> BT.modify $ set displayBox BlankDisplay
SyncDisplay -> BT.modify $ set displayBox BlankDisplay SyncDisplay -> BT.modify $ set displayBox BlankDisplay
AdrBookEntryDisplay -> BT.modify $ set displayBox BlankDisplay
BlankDisplay -> do BlankDisplay -> do
case s ^. dialogBox of case s ^. dialogBox of
WName -> do WName -> do
@ -951,7 +1085,7 @@ appEvent (BT.VtyEvent e) = do
BT.modify $ set msg "Invalid inputs" BT.modify $ set msg "Invalid inputs"
BT.modify $ set displayBox MsgDisplay BT.modify $ set displayBox MsgDisplay
BT.modify $ set dialogBox Blank BT.modify $ set dialogBox Blank
ev -> do ev ->
BT.zoom txForm $ do BT.zoom txForm $ do
handleFormEvent (BT.VtyEvent ev) handleFormEvent (BT.VtyEvent ev)
fs <- BT.gets formState fs <- BT.gets formState
@ -959,6 +1093,189 @@ appEvent (BT.VtyEvent e) = do
setFieldValid setFieldValid
(isRecipientValid (fs ^. sendTo)) (isRecipientValid (fs ^. sendTo))
RecField RecField
AdrBook -> do
case e of
V.EvKey (V.KChar 'x') [] ->
BT.modify $ set dialogBox Blank
V.EvKey (V.KChar 'c') []
-- Copy Address to Clipboard
-> do
case L.listSelectedElement $ s ^. abAddresses of
Just (_, a) -> do
liftIO $
setClipboard $
T.unpack $ addressBookAbaddress (entityVal a)
BT.modify $
set msg $
"Address copied to Clipboard from >>\n" ++
T.unpack (addressBookAbdescrip (entityVal a))
BT.modify $ set displayBox MsgDisplay
_ -> do
BT.modify $
set msg "Error while copying the address!!"
BT.modify $ set displayBox MsgDisplay
-- Send Zcash transaction
V.EvKey (V.KChar 's') [] -> do
case L.listSelectedElement $ s ^. abAddresses of
Just (_, a) -> do
BT.modify $
set txForm $
mkSendForm
(s ^. balance)
(SendInput
(addressBookAbaddress (entityVal a))
0.0
"")
BT.modify $ set dialogBox SendTx
_ -> do
BT.modify $
set msg "No receiver address available!!"
BT.modify $ set displayBox MsgDisplay
-- Edit an entry in Address Book
V.EvKey (V.KChar 'e') [] -> do
case L.listSelectedElement $ s ^. abAddresses of
Just (_, a) -> do
BT.modify $
set
abCurAdrs
(addressBookAbaddress (entityVal a))
BT.modify $
set abForm $
mkNewABForm
(AdrBookEntry
(addressBookAbdescrip (entityVal a))
(addressBookAbaddress (entityVal a)))
BT.modify $ set dialogBox AdrBookUpdForm
_ -> do
BT.modify $ set dialogBox Blank
-- Delete an entry from Address Book
V.EvKey (V.KChar 'd') [] -> do
case L.listSelectedElement $ s ^. abAddresses of
Just (_, a) -> do
BT.modify $
set
abCurAdrs
(addressBookAbaddress (entityVal a))
BT.modify $
set abForm $
mkNewABForm
(AdrBookEntry
(addressBookAbdescrip (entityVal a))
(addressBookAbaddress (entityVal a)))
BT.modify $ set dialogBox AdrBookDelForm
_ -> do
BT.modify $ set dialogBox Blank
-- Create a new entry in Address Book
V.EvKey (V.KChar 'n') [] -> do
BT.modify $
set abForm $ mkNewABForm (AdrBookEntry "" "")
BT.modify $ set dialogBox AdrBookForm
-- Show AddressBook entry data
V.EvKey V.KEnter [] -> do
BT.modify $ set displayBox AdrBookEntryDisplay
-- Process any other event
ev -> BT.zoom abAddresses $ L.handleListEvent ev
-- Process new address book entry
AdrBookForm -> do
case e of
V.EvKey V.KEsc [] -> BT.modify $ set dialogBox AdrBook
V.EvKey V.KEnter [] -> do
pool <- liftIO $ runNoLoggingT $ initPool $ s ^. dbPath
fs <- BT.zoom abForm $ BT.gets formState
let idescr = T.unpack $ T.strip (fs ^. descrip)
let iabadr = fs ^. address
if not (null idescr) && isRecipientValid iabadr
then do
res <-
liftIO $
saveAdrsInAdrBook pool $
AddressBook
(ZcashNetDB (s ^. network))
(fs ^. descrip)
(fs ^. address)
case res of
Nothing -> do
BT.modify $
set
msg
("AddressBook Entry already exists: " ++
T.unpack (fs ^. address))
BT.modify $ set displayBox MsgDisplay
Just _ -> do
BT.modify $
set
msg
("New AddressBook entry created!!\n" ++
T.unpack (fs ^. address))
BT.modify $ set displayBox MsgDisplay
-- case end
s' <- liftIO $ refreshAddressBook s
BT.put s'
BT.modify $ set dialogBox AdrBook
else do
BT.modify $ set msg "Invalid or missing data!!: "
BT.modify $ set displayBox MsgDisplay
BT.modify $ set dialogBox AdrBookForm
ev ->
BT.zoom abForm $ do
handleFormEvent (BT.VtyEvent ev)
fs <- BT.gets formState
BT.modify $
setFieldValid
(isRecipientValid (fs ^. address))
AddressField
AdrBookUpdForm -> do
case e of
V.EvKey V.KEsc [] -> BT.modify $ set dialogBox AdrBook
V.EvKey V.KEnter [] -> do
pool <- liftIO $ runNoLoggingT $ initPool $ s ^. dbPath
fs <- BT.zoom abForm $ BT.gets formState
let idescr = T.unpack $ T.strip (fs ^. descrip)
let iabadr = fs ^. address
if not (null idescr) && isRecipientValid iabadr
then do
res <-
liftIO $
updateAdrsInAdrBook
pool
(fs ^. descrip)
(fs ^. address)
(s ^. abCurAdrs)
BT.modify $
set
msg
("AddressBook entry modified!!\n" ++
T.unpack (fs ^. address))
BT.modify $ set displayBox MsgDisplay
-- case end
s' <- liftIO $ refreshAddressBook s
BT.put s'
BT.modify $ set dialogBox AdrBook
else do
BT.modify $ set msg "Invalid or missing data!!: "
BT.modify $ set displayBox MsgDisplay
BT.modify $ set dialogBox AdrBookForm
ev ->
BT.zoom abForm $ do
handleFormEvent (BT.VtyEvent ev)
fs <- BT.gets formState
BT.modify $
setFieldValid
(isRecipientValid (fs ^. address))
AddressField
-- Process delete AddresBook entry
AdrBookDelForm -> do
case e of
V.EvKey V.KEsc [] -> BT.modify $ set dialogBox AdrBook
V.EvKey (V.KChar 'c') [] -> do
pool <- liftIO $ runNoLoggingT $ initPool $ s ^. dbPath
fs <- BT.zoom abForm $ BT.gets formState
res <- liftIO $ deleteAdrsFromAB pool (fs ^. address)
s' <- liftIO $ refreshAddressBook s
BT.put s'
BT.modify $ set dialogBox AdrBook
ev -> BT.modify $ set dialogBox AdrBookDelForm
-- Process any other event
Blank -> do Blank -> do
case e of case e of
V.EvKey (V.KChar '\t') [] -> focusRing %= F.focusNext V.EvKey (V.KChar '\t') [] -> focusRing %= F.focusNext
@ -982,12 +1299,16 @@ appEvent (BT.VtyEvent e) = do
set txForm $ set txForm $
mkSendForm (s ^. balance) (SendInput "" 0.0 "") mkSendForm (s ^. balance) (SendInput "" 0.0 "")
BT.modify $ set dialogBox SendTx BT.modify $ set dialogBox SendTx
V.EvKey (V.KChar 'b') [] ->
BT.modify $ set dialogBox AdrBook
ev -> ev ->
case r of case r of
Just AList -> Just AList ->
BT.zoom addresses $ L.handleListEvent ev BT.zoom addresses $ L.handleListEvent ev
Just TList -> Just TList ->
BT.zoom transactions $ L.handleListEvent ev BT.zoom transactions $ L.handleListEvent ev
Just ABList ->
BT.zoom abAddresses $ L.handleListEvent ev
_anyName -> return () _anyName -> return ()
where where
printMsg :: String -> BT.EventM Name State () printMsg :: String -> BT.EventM Name State ()
@ -1007,11 +1328,14 @@ theMap =
, (blinkAttr, style V.blink) , (blinkAttr, style V.blink)
, (focusedFormInputAttr, V.white `on` V.blue) , (focusedFormInputAttr, V.white `on` V.blue)
, (invalidFormInputAttr, V.red `on` V.black) , (invalidFormInputAttr, V.red `on` V.black)
, (E.editAttr, V.white `on` V.blue) , (E.editAttr, V.white `on` V.black)
, (E.editFocusedAttr, V.blue `on` V.white) , (E.editFocusedAttr, V.black `on` V.white)
, (baseAttr, bg V.brightBlack) , (baseAttr, bg V.brightBlack)
, (barDoneAttr, V.white `on` V.blue) , (barDoneAttr, V.white `on` V.blue)
, (barToDoAttr, V.white `on` V.black) , (barToDoAttr, V.white `on` V.black)
, (abDefAttr, V.white `on` V.blue)
, (abSelAttr, V.black `on` V.white)
, (abMBarAttr, V.white `on` V.black)
] ]
theApp :: M.App State Tick Name theApp :: M.App State Tick Name
@ -1024,8 +1348,8 @@ theApp =
, M.appAttrMap = const theMap , M.appAttrMap = const theMap
} }
runZenithCLI :: Config -> IO () runZenithTUI :: Config -> IO ()
runZenithCLI config = do runZenithTUI config = do
let host = c_zebraHost config let host = c_zebraHost config
let port = c_zebraPort config let port = c_zebraPort config
let dbFilePath = c_dbPath config let dbFilePath = c_dbPath config
@ -1057,6 +1381,7 @@ runZenithCLI config = do
if not (null walList) if not (null walList)
then zcashWalletLastSync $ entityVal $ head walList then zcashWalletLastSync $ entityVal $ head walList
else 0 else 0
abookList <- getAdrBook pool $ zgb_net chainInfo
bal <- bal <-
if not (null accList) if not (null accList)
then getBalance pool $ entityKey $ head accList then getBalance pool $ entityKey $ head accList
@ -1101,6 +1426,9 @@ runZenithCLI config = do
eventChan eventChan
0 0
(mkSendForm 0 $ SendInput "" 0.0 "") (mkSendForm 0 $ SendInput "" 0.0 "")
(L.list ABList (Vec.fromList abookList) 1)
(mkNewABForm (AdrBookEntry "" ""))
""
Nothing Nothing
uBal uBal
Left e -> do Left e -> do
@ -1163,14 +1491,13 @@ addNewWallet n s = do
let netName = s ^. network let netName = s ^. network
r <- saveWallet pool $ ZcashWallet n (ZcashNetDB netName) (PhraseDB sP) bH 0 r <- saveWallet pool $ ZcashWallet n (ZcashNetDB netName) (PhraseDB sP) bH 0
case r of case r of
Nothing -> do Nothing -> return $ s & msg .~ ("Wallet already exists: " ++ T.unpack n)
return $ s & msg .~ ("Wallet already exists: " ++ T.unpack n)
Just _ -> do Just _ -> do
wL <- getWallets pool netName wL <- getWallets pool netName
let aL = let aL =
L.listFindBy (\x -> zcashWalletName (entityVal x) == n) $ L.listFindBy (\x -> zcashWalletName (entityVal x) == n) $
L.listReplace (Vec.fromList wL) (Just 0) (s ^. wallets) L.listReplace (Vec.fromList wL) (Just 0) (s ^. wallets)
return $ (s & wallets .~ aL) & msg .~ "Created new wallet: " ++ T.unpack n return $ s & wallets .~ aL & msg .~ "Created new wallet: " ++ T.unpack n
addNewAccount :: T.Text -> State -> IO State addNewAccount :: T.Text -> State -> IO State
addNewAccount n s = do addNewAccount n s = do
@ -1189,19 +1516,18 @@ addNewAccount n s = do
try $ createZcashAccount n (aL' + 1) selWallet :: IO try $ createZcashAccount n (aL' + 1) selWallet :: IO
(Either IOError ZcashAccount) (Either IOError ZcashAccount)
case zA of case zA of
Left e -> return $ s & msg .~ ("Error: " ++ show e) Left e -> return $ s & msg .~ "Error: " ++ show e
Right zA' -> do Right zA' -> do
r <- saveAccount pool zA' r <- saveAccount pool zA'
case r of case r of
Nothing -> Nothing -> return $ s & msg .~ "Account already exists: " ++ T.unpack n
return $ s & msg .~ ("Account already exists: " ++ T.unpack n)
Just x -> do Just x -> do
aL <- runNoLoggingT $ getAccounts pool (entityKey selWallet) aL <- runNoLoggingT $ getAccounts pool (entityKey selWallet)
let nL = let nL =
L.listMoveToElement x $ L.listMoveToElement x $
L.listReplace (Vec.fromList aL) (Just 0) (s ^. accounts) L.listReplace (Vec.fromList aL) (Just 0) (s ^. accounts)
return $ return $
(s & accounts .~ nL) & msg .~ "Created new account: " ++ T.unpack n s & accounts .~ nL & msg .~ "Created new account: " ++ T.unpack n
refreshAccount :: State -> IO State refreshAccount :: State -> IO State
refreshAccount s = do refreshAccount s = do
@ -1259,6 +1585,21 @@ refreshTxs s = do
let tL' = L.listReplace (Vec.fromList tList) (Just 0) (s ^. transactions) let tL' = L.listReplace (Vec.fromList tList) (Just 0) (s ^. transactions)
return $ s & transactions .~ tL' return $ s & transactions .~ tL'
refreshAddressBook :: State -> IO State
refreshAddressBook s = do
pool <- runNoLoggingT $ initPool $ s ^. dbPath
selAddress <-
do case L.listSelectedElement $ s ^. abAddresses of
Nothing -> do
let fAdd =
L.listSelectedElement $
L.listMoveToBeginning $ s ^. abAddresses
return fAdd
Just a2 -> return $ Just a2
abookList <- getAdrBook pool (s ^. network)
let tL' = L.listReplace (Vec.fromList abookList) (Just 0) (s ^. abAddresses)
return $ s & abAddresses .~ tL'
addNewAddress :: T.Text -> Scope -> State -> IO State addNewAddress :: T.Text -> Scope -> State -> IO State
addNewAddress n scope s = do addNewAddress n scope s = do
pool <- runNoLoggingT $ initPool $ s ^. dbPath pool <- runNoLoggingT $ initPool $ s ^. dbPath
@ -1276,19 +1617,18 @@ addNewAddress n scope s = do
try $ createWalletAddress n (maxAddr + 1) (s ^. network) scope selAccount :: IO try $ createWalletAddress n (maxAddr + 1) (s ^. network) scope selAccount :: IO
(Either IOError WalletAddress) (Either IOError WalletAddress)
case uA of case uA of
Left e -> return $ s & msg .~ ("Error: " ++ show e) Left e -> return $ s & msg .~ "Error: " ++ show e
Right uA' -> do Right uA' -> do
nAddr <- saveAddress pool uA' nAddr <- saveAddress pool uA'
case nAddr of case nAddr of
Nothing -> Nothing -> return $ s & msg .~ "Address already exists: " ++ T.unpack n
return $ s & msg .~ ("Address already exists: " ++ T.unpack n)
Just x -> do Just x -> do
addrL <- runNoLoggingT $ getAddresses pool (entityKey selAccount) addrL <- runNoLoggingT $ getAddresses pool (entityKey selAccount)
let nL = let nL =
L.listMoveToElement x $ L.listMoveToElement x $
L.listReplace (Vec.fromList addrL) (Just 0) (s ^. addresses) L.listReplace (Vec.fromList addrL) (Just 0) (s ^. addresses)
return $ return $
(s & addresses .~ nL) & msg .~ "Created new address: " ++ s & addresses .~ nL & msg .~ "Created new address: " ++
T.unpack n ++ T.unpack n ++
"(" ++ "(" ++
T.unpack (showAddress $ walletAddressUAddress $ entityVal x) ++ ")" T.unpack (showAddress $ walletAddressUAddress $ entityVal x) ++ ")"

View file

@ -24,7 +24,7 @@ import Data.Binary.Get hiding (getBytes)
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Lazy as LBS
import Data.Digest.Pure.MD5 import Data.Digest.Pure.MD5
import Data.HexString (HexString, hexString, toBytes) import Data.HexString (HexString, hexString, toBytes, toText)
import Data.List import Data.List
import Data.Maybe (fromJust) import Data.Maybe (fromJust)
import Data.Pool (Pool) import Data.Pool (Pool)
@ -574,6 +574,7 @@ prepareTx pool zebraHost zebraPort zn za bh amt ua memo = do
zn zn
(bh + 3) (bh + 3)
True True
logDebugN $ T.pack $ show tx
return tx return tx
where where
makeOutgoing :: makeOutgoing ::

View file

@ -254,6 +254,12 @@ share
name T.Text name T.Text
UniqueQr address version UniqueQr address version
deriving Show Eq deriving Show Eq
AddressBook
network ZcashNetDB
abdescrip T.Text
abaddress T.Text
UniqueABA abaddress
deriving Show Eq
|] |]
-- * Database functions -- * Database functions
@ -1666,5 +1672,55 @@ readUnifiedAddressDB :: WalletAddress -> Maybe UnifiedAddress
readUnifiedAddressDB = readUnifiedAddressDB =
isValidUnifiedAddress . TE.encodeUtf8 . getUA . walletAddressUAddress isValidUnifiedAddress . TE.encodeUtf8 . getUA . walletAddressUAddress
-- | Get list of external zcash addresses from database
getAdrBook :: ConnectionPool -> ZcashNet -> IO [Entity AddressBook]
getAdrBook pool n =
runNoLoggingT $
PS.retryOnBusy $
flip PS.runSqlPool pool $ do
select $ do
adrbook <- from $ table @AddressBook
where_ (adrbook ^. AddressBookNetwork ==. val (ZcashNetDB n))
pure adrbook
-- | Save a new address into AddressBook
saveAdrsInAdrBook ::
ConnectionPool -- ^ The database path to use
-> AddressBook -- ^ The address to add to the database
-> IO (Maybe (Entity AddressBook))
saveAdrsInAdrBook pool a =
runNoLoggingT $
PS.retryOnBusy $ flip PS.runSqlPool pool $ insertUniqueEntity a
-- | Update an existing address into AddressBook
updateAdrsInAdrBook :: ConnectionPool -> T.Text -> T.Text -> T.Text -> IO ()
updateAdrsInAdrBook pool d a ia = do
runNoLoggingT $
PS.retryOnBusy $
flip PS.runSqlPool pool $ do
update $ \ab -> do
set ab [AddressBookAbdescrip =. val d, AddressBookAbaddress =. val a]
where_ $ ab ^. AddressBookAbaddress ==. val ia
-- | Get one AddrssBook record using the Address as a key
-- getABookRec :: ConnectionPool -> T.Tex t -> IO (Maybe (Entity AddressBook))
-- getABookRec pool a = do
-- runNoLoggingT $
-- PS.retryOnBusy $
-- flip PS.runSqlPool pool $
-- select $ do
-- adrbook <- from $ table @AddressBook
-- where_ ((adrbook ^. AddressBookAbaddress) ==. val a)
-- return adrbook
-- | delete an existing address from AddressBook
deleteAdrsFromAB :: ConnectionPool -> T.Text -> IO ()
deleteAdrsFromAB pool ia = do
runNoLoggingT $
PS.retryOnBusy $
flip PS.runSqlPool pool $ do
delete $ do
ab <- from $ table @AddressBook
where_ (ab ^. AddressBookAbaddress ==. val ia)
rmdups :: Ord a => [a] -> [a] rmdups :: Ord a => [a] -> [a]
rmdups = map head . group . sort rmdups = map head . group . sort

View file

@ -1,6 +1,6 @@
cabal-version: 3.0 cabal-version: 3.0
name: zenith name: zenith
version: 0.5.3.0-beta version: 0.6.0.0-beta
license: MIT license: MIT
license-file: LICENSE license-file: LICENSE
author: Rene Vergara author: Rene Vergara
@ -53,7 +53,7 @@ library
, exceptions , exceptions
, monad-logger , monad-logger
, vty-crossplatform , vty-crossplatform
, secp256k1-haskell , secp256k1-haskell >= 1
, pureMD5 , pureMD5
, ghc , ghc
, haskoin-core , haskoin-core
@ -100,7 +100,7 @@ executable zenith
, configurator , configurator
, data-default , data-default
, sort , sort
, structured-cli --, structured-cli
, text , text
, time , time
, zenith , zenith

BIN
zenith_er.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 MiB

BIN
zenith_er.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB