Compare commits

...

115 commits

Author SHA1 Message Date
ff6168b45e rvv001 - Synchronize branch with recent changes 2025-01-04 13:53:14 -05:00
cc4ce8a280
Merge branch 'rvv001' of git.vergara.tech:Vergara_Tech/zenith into rvv001 2025-01-03 14:33:19 -06:00
332b7f5520 rvv001 - Issue 085 - [Zenith GUI] Read a payment URI
Processing Payment URI is working
		     Display of error messages added to process
2025-01-02 13:41:12 -05:00
6b3ea31882 rvv001 - Issue 085 - [Zenith GUI] Read a payment URI
Send TX windows working
         Closing the URI form is not working
2025-01-02 13:28:08 -05:00
02ec4716e9 rvv001 - Issue 085 - [Zenith GUI] Read a payment URI
Additional cases added to Test Suite
2024-12-31 09:18:39 -05:00
d476183a1d rvv001 - Issue 085 - [Zenith GUI] Read a payment URI
New type to support URI data structure created (Types.hs)
	 Function to parse an URI string created (in Utils.hs)
	 Test case added to Benchmark Suite
2024-12-30 21:00:57 -05:00
56bf19a6f6 rvv001 - Issue 084
- Form to capture input from the user implemented for TUI & GUI
           Outgoing Viewing Key display support removed from TUI & GUI
2024-12-26 18:19:43 -05:00
63aa5e5984 rvv001 - Issue 084
Form to capture input from the user implemented
         The inputs are :
            One numeric field for amount of ZEC
            One text field for memo (optional)
2024-12-26 13:53:26 -05:00
fe8fb1fa3c rvv001 - Viewing Key Display support added
Copy to Clipboard support added
2024-12-23 17:34:31 -05:00
cb927a0ab3 rvv001 - TUI - Viewing Keys Display
Submenu created
2024-12-22 21:33:25 -05:00
53eac75aa5 rvv001 - Shield / Deshield Forms
-  Shield form created
	 -  Deshield form created
	 Both forms have the 'Process' button de-activated. Must be linked
	 to the appropiate funciton
2024-10-14 19:42:09 -04:00
324ed663c3 rvv001 - Shield - Deshield process
DeShield form  -  Cancel button moved  to the right of process button
2024-10-11 21:01:50 -04:00
9acf18c503 rvv001 - Shield Zec form updated 2024-10-11 20:12:15 -04:00
54d9f20fdd rvv001 - Shield / De-Shield
GUI - Forms for Shielding and De-shielding created
	 TUI - Form to deshield  is not implemented
2024-10-09 21:02:35 -04:00
e02551c9ff rvv001 - Shield / Deshield form
Fields to display Total transparent funts and total Shielded Funds
	 added.
	 A funtion to update the latest total values has to be included
2024-10-07 19:47:28 -04:00
cf2f77e510 rvv001 -TUI - Form to process Shielding and De-Shielding zec has been implemented
The functionality to do the process is pending.
2024-10-04 21:01:13 -04:00
25b6a097c7 rvv001 - Address Validation for PrivacyPolicy = Low
Transparent, Sapling, Orchard -> Accepted
	    Exchange -> rejected
2024-10-02 20:29:51 -04:00
398f4f1dcf rvv001 - Privacy Policy control addedin TUI's send transaction form
This feature is similar to GUI's implementation.
2024-10-01 20:47:45 -04:00
b6b586f9bf
feat: add QR code table upgrade 2024-10-01 12:42:38 -05:00
adfaed6753
Merge branch 'rav001' into rvv001 2024-10-01 08:26:53 -05:00
28c05a66fe
feat: implement new PrivacyPolicy 2024-10-01 08:13:26 -05:00
0d5161cdb2 rvv001 - Privacy Policy check added to Send transaction window
Files affected: Zenith/GUI.hs
			, Zenith/CLI.hs
			, Zenith/Utils.hs
2024-09-30 20:16:09 -04:00
165977eecf rvv001 - Saving work in progress.... 2024-09-29 20:57:32 -04:00
5c8a611dfc rvv001 - Saving Work in progress... 2024-09-29 20:43:12 -04:00
6255ea3142 rvv001 - Merge with rav001 branch 2024-09-29 20:22:29 -04:00
01cdf9eb14 rvv001 - temporary commit 2024-09-29 18:18:46 -04:00
b95213ae5c
feat: refactor ZcashPool type 2024-09-29 17:11:06 -05:00
302cfb0b76
Add Logging to sync 2024-09-29 12:32:12 -05:00
6a4bbb587c
feat: set Orchard anchor depth to 5 blocks 2024-09-26 07:31:50 -05:00
95b89e28ed
tests: Add transaction preparation tests 2024-09-25 13:01:48 -05:00
93240325df
feat!: add re-org detection and rewind 2024-09-24 14:34:19 -05:00
abe30db2fe rvv001 - Zenith GUI - Privacy level radio buttons added to Send transaction form 2024-09-24 11:09:58 -04:00
d050c0c040 rvv001 - docker folder removed 2024-09-23 21:46:00 -04:00
212c1f2867 rvv001 - Add Privacy Policy to TUI 2024-09-23 21:30:05 -04:00
0e14228a0e
feat!: add block tracking to data model
Adds new `ZcashBlock` table to database to track block information and
creates a relationship between `ZcashTransaction` records and the block
they belong to.
Database getters and setters are updated to use the block record for
confirmations, height, time data.
2024-09-23 13:55:14 -05:00
7189ddcb2a
feat: update to use new createTransaction 2024-09-17 14:23:35 -05:00
4a874897cf
feat: draft new prepareTxV2 function 2024-09-16 11:52:57 -05:00
befc3e46cc
feat: add PrivacyPolicy type 2024-09-14 15:30:02 -05:00
eaa596fdac
docs: fix spec error 2024-09-14 09:10:01 -05:00
a2be940648
docs: correct sendmany parameters 2024-09-14 08:59:31 -05:00
f4f149d6a2
docs: fix typo in sendmany spec 2024-09-14 08:56:15 -05:00
4aad9cb57f
docs: update the sendmany spec 2024-09-14 08:54:12 -05:00
c9a42572d3
docs: correct sendmany schemas in OpenRPC 2024-09-14 06:54:00 -05:00
932d79ad57
docs: add examples for sendmany OpenRPC 2024-09-14 06:47:18 -05:00
a2743842dd
docs: update OpenRPC spec for sendmany 2024-09-13 17:20:31 -05:00
e46cd01f41
Add address book 2024-09-13 07:09:31 -05:00
322f2b8959
Merge branch 'milestone3' into rav001 2024-09-13 07:08:58 -05:00
bf4118b09d
Merge pull request 'Add base addressbook to GUI' (#102) from rvv041 into milestone3
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zenith/pulls/102
2024-09-13 11:39:57 +00:00
59d3ee4d37
Merge branch 'milestone3' into rvv041 2024-09-13 06:37:11 -05:00
a3a8bb1eaa rvv041 - AddressBook - empty Address book database case 2024-09-11 21:34:15 -04:00
06b2cd9222 rvv041 - Address Book - Edit Address Book Description working
- Delete Address Book Entry working
2024-09-08 17:21:17 -04:00
185738eccc rvv041 - Address Book - Edit Address Book entry description in progress
- "Delete entry" button added (functionality not implemented yet)
2024-09-07 17:09:33 -04:00
87feab284e rvv041 - Address Book - Copy ZEC Address to clipboard implemented
- Edit Adress Book entry in progress.
2024-09-06 19:50:50 -04:00
5ce0b5fa0f rvv0041 - Address Book - Show Address Book entry on mouse click completed 2024-09-06 17:16:22 -04:00
538216944d
feat: Update addressbook list after save 2024-09-06 08:42:17 -05:00
dee0a7e8e8 rvv041 - Address Book - New entry form working correctly
- Show entry zec address on row click
2024-09-05 22:19:41 -04:00
b3df16f217 rvv041 - Address Book - Entry form working partially 2024-09-05 13:50:52 -04:00
0142ea90ae rvv041 - Address Book - in progress.... 2024-09-05 11:31:51 -04:00
1931098ee9 rvv041 - AddressBook - reloading AddressBook List in progress... 2024-09-05 10:13:32 -04:00
35dce186fd
feat: getoperationstatus RPC method 2024-09-04 13:10:09 -05:00
bd3d9e8067
docs: fixed typo in OpenRPC 2024-09-04 11:11:01 -05:00
f780e996e0
docs: info for getoperationstatus 2024-09-04 11:08:00 -05:00
dcdf2e8304
Update to OpenRPC spec 2024-09-04 09:17:12 -05:00
f8fa5a005a rvv041 - AddressBook - Save new address book entry problem 2024-09-02 09:40:57 -04:00
70123a7261
Add examples to OpenRPC spec 2024-08-30 15:25:25 -05:00
1caa4efdb4
Implement getnewaddress RPC method 2024-08-30 15:14:48 -05:00
73ad2f0eb3 rvv041 - AddressBook - Record ID added to address book entries. 2024-08-29 14:42:58 -04:00
6503af6a98
Update spec for getnewaddress 2024-08-29 09:19:10 -05:00
67d334a60b rvv041 - AddressBook main window - address description list ready
New Address Entry form - Description and Address fields ready
2024-08-28 21:21:05 -04:00
fae0def6a8
Implement getnewaccount 2024-08-26 15:25:31 -05:00
35ab075703
Update getnewaccount on RPC 2024-08-26 13:49:00 -05:00
0b7bf1db99
Draft getnewaccount RPC 2024-08-24 08:59:26 -05:00
40fb9228a2
Add example to OpenRPC 2024-08-24 07:51:07 -05:00
4ee09238d8
Implement getnewwallet RPC method 2024-08-24 07:45:42 -05:00
6875917ec7
Fix button style 2024-08-20 16:46:01 -05:00
cdd28d2184 rvv041 - New AddressBook entry form - Check for valid address added. 2024-08-19 18:12:57 -04:00
934bff1454
Implement getbalance 2024-08-16 13:31:25 -05:00
9c7e808794
Add example for getbalance 2024-08-16 13:28:44 -05:00
9917356b40
Add result to OpenRPC 2024-08-15 14:41:10 -05:00
e1dfb66fae
Start work on getbalance 2024-08-15 11:46:05 -05:00
a3df217992
Remove tags for listreceived in OpenRPC 2024-08-15 11:41:03 -05:00
e94ca5e8c4
Add example to OpenRPC 2024-08-15 11:38:57 -05:00
66767da36a
Implement listreceived 2024-08-15 11:17:24 -05:00
b75ed16a3e
Implement note search by address ID 2024-08-12 15:35:00 -05:00
14cf97d473
Add schema change detection 2024-08-10 08:17:35 -05:00
c68c504b53
Refactor for new schema for ZcashTransaction 2024-08-10 07:52:45 -05:00
46b4969da5
Implement database migration 2024-08-10 07:04:40 -05:00
c9dea01644
Fix typos in OpenRPC 2024-08-08 10:11:10 -05:00
d4fd7c5044
Add placeholders for OpenRPC 2024-08-08 09:31:34 -05:00
473192e34b
Create type for Zcash note 2024-08-08 09:24:44 -05:00
d1789b634e
Fix typo in OpenRPC 2024-08-08 09:22:37 -05:00
2dfb11dc0f
Start work on listreceived 2024-08-08 09:20:35 -05:00
9cbeb5fbb0
Add getoperationstatus to OpenRPC spec 2024-08-07 12:10:44 -05:00
2cfaf5959d
Add placeholders to OpenRPC spec 2024-08-07 11:57:10 -05:00
b8980bd219
Implement listaddresses 2024-08-07 11:28:40 -05:00
339c93905f
Use TemplateHaskell for JSON instances 2024-08-06 16:08:51 -05:00
675ca9d5e3
Add draft of listaddresses 2024-08-06 16:08:26 -05:00
4553f964f3
Implement listaccounts 2024-08-06 13:38:00 -05:00
dbe352acac
Add method descriptions to RPC 2024-08-05 15:44:11 -05:00
606c25c2c3
Update RPC docs 2024-08-05 15:16:03 -05:00
a0b92ba468
Add example to OpenRPC for listwallets 2024-08-05 13:04:57 -05:00
f7efa85cdd
Implement listwallets 2024-08-05 12:54:02 -05:00
0d5ff79b96
Add Zenith server executable 2024-08-03 07:01:11 -05:00
abf02cf90d
Add OpenRPC spec 2024-08-03 07:00:12 -05:00
e3de5c7624 rvv041 - AddressBook GUI - version with display order problem 2024-07-31 17:23:49 -04:00
8ba1dfa7c7
Make RPC port configurable 2024-07-24 16:13:13 -05:00
cbcf7c9c8c
Implement basic auth on server 2024-07-24 16:03:49 -05:00
b66d0d9563
Add fields to config 2024-07-24 16:03:23 -05:00
a60534a5c2
Merge branch 'milestone3' into rav001 2024-07-23 13:59:49 -05:00
94bfca95ca
Start RPC server 2024-07-23 13:47:07 -05:00
662f9cd5ed rvv041 - Added "gui" option to usage message 2024-07-22 21:48:36 -04:00
d37269bf44 rvv041 - Zenith Utils -> GetZenithPaht added 2024-07-22 20:58:46 -04:00
c89d5a46d4 rvv041 - Zenith dbFilePath changed for dbFileName 2024-07-22 20:50:49 -04:00
01459544a5 rvv041 - Merge with Milestone2 2024-07-22 18:29:58 -04:00
3a5e593a65
Merge branch 'milestone2' into rav001 2024-07-16 09:11:48 -05:00
11 changed files with 656 additions and 151 deletions

4
.gitignore vendored
View file

@ -5,3 +5,7 @@ zenith.db
zenith.log zenith.log
zenith.db-shm zenith.db-shm
zenith.db-wal zenith.db-wal
test.db
test.db-shm
test.db-wal

View file

@ -213,7 +213,9 @@ main = do
currencyCode <- require config "currencyCode" currencyCode <- require config "currencyCode"
dbFP <- getZenithPath dbFP <- getZenithPath
let dbFilePath = T.pack $ dbFP ++ dbFileName let dbFilePath = T.pack $ dbFP ++ dbFileName
let myConfig = Config dbFilePath let myConfig =
Config
dbFilePath
zebraHost zebraHost
zebraPort zebraPort
nodeUser nodeUser

View file

@ -38,7 +38,15 @@ main = do
currencyCode <- require config "currencyCode" currencyCode <- require config "currencyCode"
dbFP <- getZenithPath dbFP <- getZenithPath
let dbFilePath = T.pack $ dbFP ++ dbFileName let dbFilePath = T.pack $ dbFP ++ dbFileName
let myConfig = Config dbFilePath zebraHost zebraPort nodeUser nodePwd nodePort currencyCode let myConfig =
Config
dbFilePath
zebraHost
zebraPort
nodeUser
nodePwd
nodePort
currencyCode
let ctx = authenticate myConfig :. EmptyContext let ctx = authenticate myConfig :. EmptyContext
w <- try $ checkZebra zebraHost zebraPort :: IO (Either IOError ZebraGetInfo) w <- try $ checkZebra zebraHost zebraPort :: IO (Either IOError ZebraGetInfo)
case w of case w of

View file

@ -89,7 +89,13 @@ import Lens.Micro.Mtl
import Lens.Micro.TH import Lens.Micro.TH
import System.Hclip import System.Hclip
import Text.Printf import Text.Printf
import Text.Wrap (FillScope(..), FillStrategy(..), WrapSettings(..)) import Text.Wrap
( FillScope(..)
, FillStrategy(..)
, WrapSettings(..)
, defaultWrapSettings
, wrapTextToLines
)
import ZcashHaskell.Keys (generateWalletSeedPhrase) import ZcashHaskell.Keys (generateWalletSeedPhrase)
import ZcashHaskell.Orchard import ZcashHaskell.Orchard
( getSaplingFromUA ( getSaplingFromUA
@ -121,12 +127,12 @@ import Zenith.Utils
( displayTaz ( displayTaz
, displayZec , displayZec
, getChainTip , getChainTip
, getZcashPrice
, isRecipientValid , isRecipientValid
, isRecipientValidGUI , isRecipientValidGUI
, jsonNumber , jsonNumber
, showAddress , showAddress
, validBarValue , validBarValue
, getZcashPrice
) )
data Name data Name
@ -182,6 +188,13 @@ newtype ShDshEntry = ShDshEntry
makeLenses ''ShDshEntry makeLenses ''ShDshEntry
data PaymentInput = PaymentInput
{ _pmtAmt :: !Scientific
, _pmtMemo :: !T.Text
} deriving (Show)
makeLenses ''PaymentInput
data DialogType data DialogType
= WName = WName
| AName | AName
@ -197,6 +210,9 @@ data DialogType
| DeshieldForm | DeshieldForm
| ShieldForm | ShieldForm
| ShowFIATBalance | ShowFIATBalance
| ViewingKeyMenu
| ViewingKeyShow
| PaymentURIShow
data DisplayType data DisplayType
= AddrDisplay = AddrDisplay
@ -250,6 +266,9 @@ data State = State
, _sBalance :: !Integer , _sBalance :: !Integer
, _currencyCode :: !T.Text , _currencyCode :: !T.Text
, _zprice :: !Double , _zprice :: !Double
, _vkName :: !T.Text
, _vkData :: !T.Text
, _pmtURIForm :: !(Form PaymentInput () Name)
} }
makeLenses ''State makeLenses ''State
@ -257,6 +276,21 @@ makeLenses ''State
zBalance :: State -> Double zBalance :: State -> Double
zBalance st = (fromIntegral (st ^. balance)) / 100000000 zBalance st = (fromIntegral (st ^. balance)) / 100000000
-- Function to split text into fixed-size chunks
splitText :: Int -> T.Text -> [T.Text]
splitText chunkSize text =
let strippedText = T.filter (/= '\n') text -- Remove newlines
in if T.null strippedText
then []
else T.take chunkSize strippedText :
splitText chunkSize (T.drop chunkSize strippedText)
-- Create a widget to display the long text
renderLongText :: Int -> T.Text -> Widget Name
renderLongText lineLength longText =
let linesOfText = splitText lineLength longText
in vBox $ map txt linesOfText
drawUI :: State -> [Widget Name] drawUI :: State -> [Widget Name]
drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s] drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
where where
@ -307,13 +341,18 @@ 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"
, capCommand3 "ba" "L" ("ance (" ++ ( T.unpack (st ^. currencyCode) )++ ")" ) , capCommand2 "Gen " "U" "RI"
, capCommand3
"ba"
"L"
("ance (" ++ (T.unpack (st ^. currencyCode)) ++ ")")
]) ])
, C.hCenter , C.hCenter
(hBox (hBox
[ capCommand2 "Address " "B" "ook" [ capCommand2 "Address " "B" "ook"
, capCommand2 "s" "H" "ield" , capCommand2 "s" "H" "ield"
, capCommand "D" "e-shield" , capCommand "D" "e-shield"
, capCommand2 "Viewing " "K" "eys"
, capCommand "Q" "uit" , capCommand "Q" "uit"
, capCommand "?" " Help" , capCommand "?" " Help"
, str $ show (st ^. timer) , str $ show (st ^. timer)
@ -384,7 +423,9 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
else emptyWidget else emptyWidget
where where
keyList = keyList =
map (C.hCenter . str) ["?", "Esc", "w", "a", "v", "s", "b", "d", "l", "q"] map
(C.hCenter . str)
["?", "Esc", "w", "a", "v", "s", "u", "b", "d", "k", "l", "q"]
actionList = actionList =
map map
(hLimit 40 . str) (hLimit 40 . str)
@ -394,8 +435,10 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
, "Switch accounts" , "Switch accounts"
, "View address" , "View address"
, "Send Tx" , "Send Tx"
, "Gen URI"
, "Address Book" , "Address Book"
, "Shield/De-Shield" , "Shield/De-Shield"
, "Viewing Keys"
, "Balance in Fiat" , "Balance in Fiat"
, "Quit" , "Quit"
] ]
@ -443,6 +486,13 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
(renderForm (st ^. txForm) <=> (renderForm (st ^. txForm) <=>
C.hCenter C.hCenter
(hBox [capCommand "" "Send", capCommand "<esc> " "Cancel"])) (hBox [capCommand "" "Send", capCommand "<esc> " "Cancel"]))
PaymentURIShow ->
D.renderDialog
(D.dialog (Just (str " Create Payment URI ")) Nothing 50)
(renderForm (st ^. pmtURIForm) <=>
C.hCenter
(hBox
[capCommand "P" "rocess", capCommand3 " " "<esc> " "Cancel"]))
DeshieldForm -> DeshieldForm ->
D.renderDialog D.renderDialog
(D.dialog (Just (str " De-Shield ZEC ")) Nothing 50) (D.dialog (Just (str " De-Shield ZEC ")) Nothing 50)
@ -462,7 +512,7 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
]) <=> ]) <=>
renderForm (st ^. deshieldForm) <=> renderForm (st ^. deshieldForm) <=>
C.hCenter C.hCenter
(hBox [capCommand "P" "roceed", capCommand "<esc> " "Cancel"])) (hBox [capCommand "P" "roceed", capCommand3 "" "<esc> " "Cancel"]))
ShieldForm -> ShieldForm ->
D.renderDialog D.renderDialog
(D.dialog (Just (str " Shield ZEC ")) Nothing 50) (D.dialog (Just (str " Shield ZEC ")) Nothing 50)
@ -473,7 +523,26 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
then displayZec (st ^. tBalance) then displayZec (st ^. tBalance)
else displayTaz (st ^. tBalance) ++ "?") <=> else displayTaz (st ^. tBalance) ++ "?") <=>
C.hCenter C.hCenter
(hBox [capCommand "P" "roceed", capCommand "<esc> " "Cancel"])) (hBox [capCommand "P" "roceed", capCommand3 "" "<esc> " "Cancel"]))
ViewingKeyShow ->
D.renderDialog
(D.dialog
(Just (str (" " ++ (T.unpack (st ^. vkName)) ++ " Viewing Key ")))
Nothing
50)
(padAll 1 (C.hCenter (renderLongText 45 (st ^. vkData))) <=>
C.hCenter
(hBox
[capCommand "C" "opy to Clipoard", capCommand3 "" "E" "xit"]))
ViewingKeyMenu ->
D.renderDialog
(D.dialog (Just (str " Viewing Keys ")) Nothing 50)
(C.hCenter
(hBox
[ capCommand "F" "ull"
, capCommand "I" "ncoming"
, capCommand3 "" "E" "xit"
]))
Blank -> emptyWidget Blank -> emptyWidget
-- Address Book List -- Address Book List
AdrBook -> AdrBook ->
@ -529,21 +598,36 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
-- Show Balance in FIAT form -- Show Balance in FIAT form
ShowFIATBalance -> ShowFIATBalance ->
D.renderDialog D.renderDialog
(D.dialog (Just $ str (" Account Balance (" ++ ( T.unpack (st ^. currencyCode)) ++ ") ") ) Nothing 60) (D.dialog
(Just $
str
(" Account Balance (" ++
(T.unpack (st ^. currencyCode)) ++ ") "))
Nothing
60)
(withAttr abDefAttr $ (withAttr abDefAttr $
setAvailableSize (50, 8) $ setAvailableSize (50, 8) $
viewport SFBViewPort BT.Vertical $ viewport SFBViewPort BT.Vertical $
vLimit 8 $ vLimit 8 $
hLimit 50 $ hLimit 50 $
vBox $ vBox $
[ [ vLimit 4 $
vLimit 4 $
hLimit 50 $ hLimit 50 $
vBox $ vBox $
[ C.hCenter (str $ " ") [ C.hCenter (str $ " ")
, C.hCenter (str $ "1 ZEC = " ++ ( printf "%.2f" ( s ^. zprice ) ) ++ " " ++ (T.unpack ( s ^. currencyCode) )) , C.hCenter
(str $
"1 ZEC = " ++
(printf "%.2f" (s ^. zprice)) ++
" " ++ (T.unpack (s ^. currencyCode)))
, C.hCenter (str $ " ") , C.hCenter (str $ " ")
, C.hCenter ( str $ " Balance: " ++ ( printf "%.8f" $ zBalance s ) ++ " ZEC ==> " ++ ( printf "%.2f" (( s ^. zprice ) * (zBalance s) ) ++ " " ++ (T.unpack ( s ^. currencyCode) )) ) , C.hCenter
(str $
" Balance: " ++
(printf "%.8f" $ zBalance s) ++
" ZEC ==> " ++
(printf "%.2f" ((s ^. zprice) * (zBalance s)) ++
" " ++ (T.unpack (s ^. currencyCode))))
] ]
, padTop Max $ , padTop Max $
vLimit 4 $ vLimit 4 $
@ -567,7 +651,7 @@ 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.7.0.0-beta")) <=> (withAttr titleAttr (str "Zcash Wallet v0.7.1.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 :: String -> String -> String -> Widget Name
@ -746,6 +830,19 @@ 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
mkPaymentURIForm :: Integer -> PaymentInput -> Form PaymentInput e Name
mkPaymentURIForm bal =
newForm
[ label "Amount: " @@=
editShowableFieldWithValidate pmtAmt AmtField (isAmountValid bal)
, label "Memo: " @@= editTextField pmtMemo MemoField (Just 1)
]
where
isAmountValid :: Integer -> Scientific -> Bool
isAmountValid b i = fromIntegral b >= (i * scientific 1 8)
label s w =
padBottom (Pad 1) $ vLimit 1 (hLimit 15 $ str s <+> fill ' ') <+> w
mkDeshieldForm :: Integer -> ShDshEntry -> Form ShDshEntry e Name mkDeshieldForm :: Integer -> ShDshEntry -> Form ShDshEntry e Name
mkDeshieldForm tbal = mkDeshieldForm tbal =
newForm newForm
@ -757,7 +854,19 @@ mkDeshieldForm tbal =
isAmountValid b i = fromIntegral b >= (i * scientific 1 8) isAmountValid b i = fromIntegral b >= (i * scientific 1 8)
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
{--
mkShieldForm :: Integer -> ShDshEntry -> Form ShDshEntry e Name
mkShieldForm bal =
newForm
[ label "Amount to Shield: " @@=
editShowableFieldWithValidate shAmt AmtField (isAmountValid bal)
]
where
isAmountValid :: Integer -> Scientific -> Bool
isAmountValid b i = (fromIntegral b / 100000000.0) >= i
label s w =
padBottom (Pad 1) $ vLimit 1 (hLimit 15 $ str s <+> fill ' ') <+> w
--}
mkNewABForm :: AdrBookEntry -> Form AdrBookEntry e Name mkNewABForm :: AdrBookEntry -> Form AdrBookEntry e Name
mkNewABForm = mkNewABForm =
newForm newForm
@ -1035,7 +1144,10 @@ appEvent (BT.AppEvent t) = do
AdrBookDelForm -> return () AdrBookDelForm -> return ()
DeshieldForm -> return () DeshieldForm -> return ()
ShieldForm -> return () ShieldForm -> return ()
ViewingKeyShow -> return ()
ViewingKeyMenu -> return ()
ShowFIATBalance -> return () ShowFIATBalance -> return ()
PaymentURIShow -> return ()
Blank -> do Blank -> do
if s ^. timer == 90 if s ^. timer == 90
then do then do
@ -1626,12 +1738,58 @@ appEvent (BT.VtyEvent e) = do
BT.modify $ set zprice p BT.modify $ set zprice p
BT.modify $ set dialogBox ShowFIATBalance BT.modify $ set dialogBox ShowFIATBalance
Nothing -> do Nothing -> do
BT.modify $ set msg ("CoinGecko is not responding!!!") BT.modify $
set msg ("CoinGecko is not responding!!!")
BT.modify $ set displayBox MsgDisplay BT.modify $ set displayBox MsgDisplay
-- Process any other event -- Process any other event
ev -> BT.zoom abAddresses $ L.handleListEvent ev ev -> BT.zoom abAddresses $ L.handleListEvent ev
-- --
-- Viewing Key Display Support
--
ViewingKeyShow -> do
case e of
V.EvKey (V.KChar 'c') [] -> do
liftIO $ setClipboard $ T.unpack $ s ^. vkData
BT.modify $
set msg $
(T.unpack (s ^. vkName)) ++
" viewing key copied to Clipboard!!"
BT.modify $ set displayBox MsgDisplay
V.EvKey (V.KChar 'e') [] -> do
BT.modify $ set vkName ""
BT.modify $ set vkData ""
BT.modify $ set dialogBox ViewingKeyMenu
ev -> return ()
--
ViewingKeyMenu -> do
case e of
V.EvKey (V.KChar 'f') [] -> do
BT.modify $ set vkName "Full"
BT.modify $
set
vkData
"VKFull->ztestsapling1tgjr4zppwk4ne8xy6gdq4z2gwq7dmf5jq8z2ctpn8nlmtse0a74fa5z0m8z383gmpgqz6q6duu4"
BT.modify $ set dialogBox ViewingKeyShow
V.EvKey (V.KChar 'i') [] -> do
BT.modify $ set vkName "Incomming"
BT.modify $
set
vkData
"VKIncoming->ztestsapling1tgjr4zppwk4ne8xy6gdq4z2gwq7dmf5jq8z2ctpn8nlmtse0a74fa5z0m8z383gmpgqz6q6duu4"
BT.modify $ set dialogBox ViewingKeyShow
V.EvKey (V.KChar 'e') [] ->
BT.modify $ set dialogBox Blank
ev -> return ()
--
-- Payment URI Form Events
--
PaymentURIShow -> do
case e of
V.EvKey V.KEsc [] -> BT.modify $ set dialogBox Blank
ev -> return ()
--
-- Process any other event -- 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
@ -1655,9 +1813,13 @@ appEvent (BT.VtyEvent e) = do
set txForm $ set txForm $
mkSendForm (s ^. balance) (SendInput "" 0.0 "" Full) mkSendForm (s ^. balance) (SendInput "" 0.0 "" Full)
BT.modify $ set dialogBox SendTx BT.modify $ set dialogBox SendTx
V.EvKey (V.KChar 'u') [] -> do
BT.modify $
set pmtURIForm $
mkPaymentURIForm (s ^. balance) (PaymentInput 0.0 "")
BT.modify $ set dialogBox PaymentURIShow
V.EvKey (V.KChar 'b') [] -> V.EvKey (V.KChar 'b') [] ->
BT.modify $ set dialogBox AdrBook BT.modify $ set dialogBox AdrBook
-- >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
V.EvKey (V.KChar 'l') [] -> do V.EvKey (V.KChar 'l') [] -> do
if s ^. network == MainNet if s ^. network == MainNet
then do then do
@ -1667,12 +1829,18 @@ appEvent (BT.VtyEvent e) = do
BT.modify $ set zprice p BT.modify $ set zprice p
BT.modify $ set dialogBox ShowFIATBalance BT.modify $ set dialogBox ShowFIATBalance
Nothing -> do Nothing -> do
BT.modify $ set msg ("Currency not supported (" ++ T.unpack (s ^. currencyCode ) ++ ")!!!") BT.modify $
set
msg
("Currency not supported (" ++
T.unpack (s ^. currencyCode) ++ ")!!!")
BT.modify $ set displayBox MsgDisplay BT.modify $ set displayBox MsgDisplay
else do else do
BT.modify $ set msg "Balance conversion not available for TestNet" BT.modify $
set
msg
"Balance conversion not available for TestNet"
BT.modify $ set displayBox MsgDisplay BT.modify $ set displayBox MsgDisplay
-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
V.EvKey (V.KChar 'd') [] -> do V.EvKey (V.KChar 'd') [] -> do
pool <- liftIO $ runNoLoggingT $ initPool $ s ^. dbPath pool <- liftIO $ runNoLoggingT $ initPool $ s ^. dbPath
selAcc <- selAcc <-
@ -1724,7 +1892,8 @@ appEvent (BT.VtyEvent e) = do
msg msg
"Not enough transparent funds in this account" "Not enough transparent funds in this account"
BT.modify $ set displayBox MsgDisplay BT.modify $ set displayBox MsgDisplay
V.EvKey (V.KChar 'k') [] -> do
BT.modify $ set dialogBox ViewingKeyMenu
ev -> ev ->
case r of case r of
Just AList -> Just AList ->
@ -1879,6 +2048,9 @@ runZenithTUI config = do
sBal sBal
currencyCode currencyCode
0 0
""
""
(mkPaymentURIForm 0 $ PaymentInput 0.0 "")
Left _e -> do Left _e -> do
print $ print $
"No Zebra node available on port " <> "No Zebra node available on port " <>

View file

@ -69,21 +69,21 @@ import Zenith.Types hiding (ZcashAddress(..))
import Zenith.Utils import Zenith.Utils
( displayAmount ( displayAmount
, getChainTip , getChainTip
, getZcashPrice
, isRecipientValidGUI , isRecipientValidGUI
, isValidString , isValidString
, isZecAddressValid , isZecAddressValid
, jsonNumber , jsonNumber
, padWithZero , padWithZero
, parseZcashPayment
, showAddress , showAddress
, validBarValue , validBarValue
, getZcashPrice
) )
data VkTypeDef data VkTypeDef
= VkNone = VkNone
| VkFull | VkFull
| VkIncoming | VkIncoming
| VkOutgoing
deriving (Eq, Show) deriving (Eq, Show)
data AppEvent data AppEvent
@ -163,6 +163,11 @@ data AppEvent
| ShowViewingKey !VkTypeDef !T.Text | ShowViewingKey !VkTypeDef !T.Text
| CopyViewingKey !T.Text !T.Text | CopyViewingKey !T.Text !T.Text
| CloseShowVK | CloseShowVK
| DisplayPaymentURI
| ClosePaymentURI
| DisplayPayUsingURI
| ClosePayUsingURI
| ProcIfValidURI
deriving (Eq, Show) deriving (Eq, Show)
data AppModel = AppModel data AppModel = AppModel
@ -229,6 +234,9 @@ data AppModel = AppModel
, _viewingKeyDisplay :: !Bool , _viewingKeyDisplay :: !Bool
, _vkTypeName :: !T.Text , _vkTypeName :: !T.Text
, _vkData :: !T.Text , _vkData :: !T.Text
, _paymentURIDisplay :: !Bool
, _usepmtURIOverlay :: !Bool
, _uriString :: !T.Text
} deriving (Eq, Show) } deriving (Eq, Show)
makeLenses ''AppModel makeLenses ''AppModel
@ -280,6 +288,8 @@ buildUI wenv model = widgetTree
model ^. model ^.
updateABAddress updateABAddress
, showVKOverlay `nodeVisible` model ^. viewingKeyDisplay , showVKOverlay `nodeVisible` model ^. viewingKeyDisplay
, paymentURIOverlay `nodeVisible` model ^. paymentURIDisplay
, pmtUsingURIOverlay `nodeVisible` model ^. usepmtURIOverlay
, shieldOverlay `nodeVisible` model ^. shieldZec , shieldOverlay `nodeVisible` model ^. shieldZec
, deShieldOverlay `nodeVisible` model ^. deShieldZec , deShieldOverlay `nodeVisible` model ^. deShieldZec
, msgAdrBookOverlay `nodeVisible` isJust (model ^. msgAB) , msgAdrBookOverlay `nodeVisible` isJust (model ^. msgAB)
@ -364,10 +374,21 @@ buildUI wenv model = widgetTree
, widgetIf (model ^. viewingKeyPopup) $ , widgetIf (model ^. viewingKeyPopup) $
remixIcon remixMenuFoldFill remixIcon remixMenuFoldFill
]) ])
, widgetIf (model ^. viewingKeyPopup) $ animSlideIn viewingKeysBox , widgetIf (model ^. viewingKeyPopup) $
animSlideIn viewingKeysBox
]) `styleBasic` ]) `styleBasic`
[bgColor white, borderB 1 gray, padding 3] [bgColor white, borderB 1 gray, padding 3]
, box_ [alignLeft, onClick ShowFIATBalance] ( label ("Balance in " <> T.toUpper (c_currencyCode (model ^. configuration) ) ) ) `styleBasic` , box_
[alignLeft, onClick ShowFIATBalance]
(label
("Balance in " <>
T.toUpper (c_currencyCode (model ^. configuration)))) `styleBasic`
[bgColor white, borderB 1 gray, padding 3]
, box_ [alignLeft, onClick DisplayPaymentURI] (label "Create URI") `styleBasic`
[bgColor white, borderB 1 gray, padding 3]
, box_
[alignLeft, onClick DisplayPayUsingURI]
(label "Pay using URI") `styleBasic`
[bgColor white, borderB 1 gray, padding 3] [bgColor white, borderB 1 gray, padding 3]
]) `styleBasic` ]) `styleBasic`
[bgColor btnColor, padding 3] [bgColor btnColor, padding 3]
@ -393,17 +414,23 @@ buildUI wenv model = widgetTree
[alignMiddle] [alignMiddle]
(vstack (vstack
[ box_ [ box_
[alignLeft, onClick (ShowViewingKey VkFull "VKFull->ztestsapling1tgjr4zppwk4ne8xy6gdq4z2gwq7dmf5jq8z2ctpn8nlmtse0a74fa5z0m8z383gmpgqz6q6duu4")] [ alignLeft
, onClick
(ShowViewingKey
VkFull
"VKFull->ztestsapling1tgjr4zppwk4ne8xy6gdq4z2gwq7dmf5jq8z2ctpn8nlmtse0a74fa5z0m8z383gmpgqz6q6duu4")
]
(hstack [label "Full VK", filler]) `styleBasic` (hstack [label "Full VK", filler]) `styleBasic`
[bgColor white, borderB 1 gray, padding 3] [bgColor white, borderB 1 gray, padding 3]
, box_ , box_
[alignLeft, onClick $ (ShowViewingKey VkIncoming "VKIncoming->ztestsapling1tgjr4zppwk4ne8xy6gdq4z2gwq7dmf5jq8z2ctpn8nlmtse0a74fa5z0m8z383gmpgqz6q6duu4")] [ alignLeft
, onClick $
(ShowViewingKey
VkIncoming
"VKIncoming->ztestsapling1tgjr4zppwk4ne8xy6gdq4z2gwq7dmf5jq8z2ctpn8nlmtse0a74fa5z0m8z383gmpgqz6q6duu4")
]
(hstack [label "Incoming VK", filler]) `styleBasic` (hstack [label "Incoming VK", filler]) `styleBasic`
[bgColor white, borderB 1 gray, padding 3] [bgColor white, borderB 1 gray, padding 3]
, box_
[alignLeft, onClick $ (ShowViewingKey VkOutgoing "VKOutgoing->ztestsapling1tgjr4zppwk4ne8xy6gdq4z2gwq7dmf5jq8z2ctpn8nlmtse0a74fa5z0m8z383gmpgqz6q6duu4")]
(hstack [label "Outgoing VK", filler]) `styleBasic`
[bgColor white, borderB 1 gray, padding 3]
]) ])
walletButton = walletButton =
hstack hstack
@ -1056,13 +1083,24 @@ buildUI wenv model = widgetTree
vstack vstack
[ box_ [ box_
[] []
(label ("Account Balance in " <> (T.toUpper (c_currencyCode (model ^. configuration))) ) `styleBasic` (label
("Account Balance in " <>
(T.toUpper (c_currencyCode (model ^. configuration)))) `styleBasic`
[textFont "Bold", textSize 12, textColor white]) `styleBasic` [textFont "Bold", textSize 12, textColor white]) `styleBasic`
[bgColor btnColor, radius 2, padding 3] [bgColor btnColor, radius 2, padding 3]
, filler , filler
, (label ("1 ZEC = " <> ( T.pack (printf "%.2f" ( model ^. zPrice ))) <> " " <> (T.toUpper (c_currencyCode (model ^. configuration))) ) ) `styleBasic` [] , (label
("1 ZEC = " <>
(T.pack (printf "%.2f" (model ^. zPrice))) <>
" " <> (T.toUpper (c_currencyCode (model ^. configuration))))) `styleBasic`
[]
, filler , filler
, (label ( ( T.pack (printf "%.8f" (model ^. aBal) ) <> " ZEC = " <> ( T.pack (printf "%.2f" (( model ^. zPrice )*( model ^. aBal ) ) ) ) <> " " <> (T.toUpper (c_currencyCode (model ^. configuration))) ) ) ) `styleBasic` [] , (label
((T.pack (printf "%.8f" (model ^. aBal)) <>
" ZEC = " <>
(T.pack (printf "%.2f" ((model ^. zPrice) * (model ^. aBal)))) <>
" " <> (T.toUpper (c_currencyCode (model ^. configuration)))))) `styleBasic`
[]
] ]
showVKOverlay = showVKOverlay =
alert CloseShowVK $ alert CloseShowVK $
@ -1073,11 +1111,13 @@ buildUI wenv model = widgetTree
[textFont "Bold", textColor white, textSize 12, padding 3]) `styleBasic` [textFont "Bold", textColor white, textSize 12, padding 3]) `styleBasic`
[bgColor btnColor, radius 2, padding 3] [bgColor btnColor, radius 2, padding 3]
, spacer , spacer
, hstack [filler, label_ (txtWrapN (model ^. vkData) 64) [multiline], filler] , hstack
[filler, label_ (txtWrapN (model ^. vkData) 64) [multiline], filler]
, spacer , spacer
, hstack , hstack
[ filler [ filler
, button "Copy to Clipboard" $ CopyViewingKey (model ^. vkTypeName) (model ^. vkData) , button "Copy to Clipboard" $
CopyViewingKey (model ^. vkTypeName) (model ^. vkData)
, filler , filler
] ]
] ]
@ -1196,8 +1236,106 @@ buildUI wenv model = widgetTree
, filler , filler
]) `styleBasic` ]) `styleBasic`
[bgColor (white & L.a .~ 0.5)] [bgColor (white & L.a .~ 0.5)]
paymentURIOverlay =
notImplemented = NotImplemented box
(vstack
[ filler
, hstack
[ filler
, box_
[]
(vstack
[ box_
[alignMiddle]
(label "Create URI" `styleBasic`
[textColor white, textFont "Bold", textSize 12]) `styleBasic`
[bgColor btnColor]
, separatorLine `styleBasic` [fgColor btnColor]
, spacer
, hstack
[ label "Amount:" `styleBasic`
[width 50, textFont "Bold"]
, spacer
, numericField_
sendAmount
[ decimals 8
, minValue 0.0
, maxValue
(fromIntegral (model ^. balance) / 100000000.0)
, validInput amountValid
, onChange CheckAmount
] `styleBasic`
[ width 150
, styleIf
(not $ model ^. amountValid)
(textColor red)
]
]
, hstack
[ label "Memo:" `styleBasic`
[width 50, textFont "Bold"]
, spacer
, textArea sendMemo `styleBasic`
[width 150, height 40]
]
, spacer
, box_
[alignMiddle]
(hstack
[ spacer
, mainButton "Create URI" NotImplemented `nodeEnabled`
True
, spacer
, button "Cancel" ClosePaymentURI
, spacer
])
]) `styleBasic`
[radius 4, border 2 btnColor, bgColor white, padding 4]
, filler
]
, filler
]) `styleBasic`
[bgColor (white & L.a .~ 0.5)]
pmtUsingURIOverlay =
box
(vstack
[ filler
, hstack
[ filler
, box_
[]
(vstack
[ box_
[alignMiddle]
(label "Pay using URI" `styleBasic`
[textColor white, textFont "Bold", textSize 12]) `styleBasic`
[bgColor btnColor]
, separatorLine `styleBasic` [fgColor btnColor]
, spacer
, hstack
[ label "URI :" `styleBasic`
[width 30, textFont "Bold"]
, spacer
, textArea uriString `styleBasic`
[width 170, height 30]
]
, spacer
, box_
[alignMiddle]
(hstack
[ spacer
, button "Cancel" ClosePayUsingURI
, spacer
, mainButton "Process" ProcIfValidURI
, spacer
])
]) `styleBasic`
[radius 4, border 2 btnColor, bgColor white, padding 4]
, filler
]
, filler
]) `styleBasic`
[bgColor (white & L.a .~ 0.5)]
generateQRCodes :: Config -> IO () generateQRCodes :: Config -> IO ()
generateQRCodes config = do generateQRCodes config = do
@ -1320,11 +1458,13 @@ handleEvent wenv node model evt =
False False
] ]
ConfirmCancel -> [Model $ model & confirmTitle .~ Nothing & mainInput .~ ""] ConfirmCancel -> [Model $ model & confirmTitle .~ Nothing & mainInput .~ ""]
ViewingKeysClicked -> [Model $ model & viewingKeyPopup .~ not (model ^. viewingKeyPopup)] ViewingKeysClicked ->
[Model $ model & viewingKeyPopup .~ not (model ^. viewingKeyPopup)]
NewAddress vk -> NewAddress vk ->
[ Model $ [ Model $
model & confirmTitle ?~ "New Address" & model & confirmTitle ?~ "New Address" & confirmCancel .~ "Cancel" &
confirmCancel .~ "Cancel" & menuPopup .~ False menuPopup .~
False
] ]
ShowSeed -> [Model $ model & showSeed .~ True & menuPopup .~ False] ShowSeed -> [Model $ model & showSeed .~ True & menuPopup .~ False]
ShowSend -> ShowSend ->
@ -1606,17 +1746,22 @@ handleEvent wenv node model evt =
model & msgAB ?~ "Function not implemented..." & menuPopup .~ False model & msgAB ?~ "Function not implemented..." & menuPopup .~ False
] ]
CloseMsgAB -> [Model $ model & msgAB .~ Nothing & inError .~ False] CloseMsgAB -> [Model $ model & msgAB .~ Nothing & inError .~ False]
CloseShowVK -> [Model $ model & vkTypeName .~ "" & vkData .~ "" & viewingKeyDisplay .~ False] CloseShowVK ->
[ Model $
model & vkTypeName .~ "" & vkData .~ "" & viewingKeyDisplay .~ False
]
-- --
-- Show Balance in FIAT -- Show Balance in FIAT
-- --
DisplayFIATBalance zpr abal -> DisplayFIATBalance zpr abal ->
[ Model $ model & zPrice .~ zpr & aBal .~ abal & displayFIATBalance .~ True & menuPopup .~ False [ Model $
model & zPrice .~ zpr & aBal .~ abal & displayFIATBalance .~ True &
menuPopup .~
False
] ]
ShowFIATBalance -> ShowFIATBalance ->
if model ^. network == MainNet if model ^. network == MainNet
then [ Task $ sfBalance (model ^. configuration) then [Task $ sfBalance (model ^. configuration)]
]
else [ Model $ model & zPrice .~ 0.0 & aBal .~ 0.0 else [ Model $ model & zPrice .~ 0.0 & aBal .~ 0.0
, Event $ ShowError "Balance conversion not available for TestNet" , Event $ ShowError "Balance conversion not available for TestNet"
] ]
@ -1626,9 +1771,68 @@ handleEvent wenv node model evt =
-- --
ShowViewingKey vkType vkText -> ShowViewingKey vkType vkText ->
case vkType of case vkType of
VkFull -> [ Model $ model & vkTypeName .~ "Full" & vkData .~ vkText & viewingKeyDisplay .~ True & menuPopup .~ False] VkFull ->
VkIncoming -> [ Model $ model & vkTypeName .~ "Incoming" & vkData .~ vkText & viewingKeyDisplay .~ True & menuPopup .~ False] [ Model $
VkOutgoing -> [ Model $ model & vkTypeName .~ "Outgoing" & vkData .~ vkText & viewingKeyDisplay .~ True & menuPopup .~ False] model & vkTypeName .~ "Full" & vkData .~ vkText & viewingKeyDisplay .~
True &
menuPopup .~
False
]
VkIncoming ->
[ Model $
model & vkTypeName .~ "Incoming" & vkData .~ vkText &
viewingKeyDisplay .~
True &
menuPopup .~
False
]
--
-- Display PaymentURI Form
--
DisplayPaymentURI ->
[ Model $
model & paymentURIDisplay .~ True & uriString .~ "" & menuPopup .~ False
]
ClosePaymentURI -> [Model $ model & paymentURIDisplay .~ False]
--
-- Display Pay using URI Form
--
DisplayPayUsingURI ->
[Model $ model & usepmtURIOverlay .~ True & menuPopup .~ False]
ClosePayUsingURI -> [Model $ model & usepmtURIOverlay .~ False]
ProcIfValidURI -> do
let zp = parseZcashPayment $ T.unpack (model ^. uriString)
case zp of
Right p -> do
case uriAmount p of
Just a ->
[ Model $
model & usepmtURIOverlay .~ False & openSend .~ True &
privacyChoice .~
Full &
recipientValid .~
False &
sendRecipient .~
T.pack (uriAddress p) &
sendAmount .~
realToFrac a &
sendMemo .~
(uriMemo p)
, Event $ ClosePaymentURI
]
Nothing ->
[ Model $
model & usepmtURIOverlay .~ False & openSend .~ False &
uriString .~
""
, Event $ ShowError "Invalid URI"
]
Left e ->
[ Model $
model & usepmtURIOverlay .~ False & openSend .~ False & uriString .~
""
, Event $ ShowError "Invalid URI"
]
-- --
-- --
ShowShield -> ShowShield ->
@ -1643,7 +1847,8 @@ handleEvent wenv node model evt =
[ Task $ updAddrBookDescrip (model ^. configuration) d a [ Task $ updAddrBookDescrip (model ^. configuration) d a
, Model $ , Model $
model & abdescrip .~ "" & abaddress .~ "" & updateABAddress .~ False & model & abdescrip .~ "" & abaddress .~ "" & updateABAddress .~ False &
showABAddress .~ False showABAddress .~
False
, Task $ do , Task $ do
dbPool <- runNoLoggingT $ initPool $ c_dbPath $ model ^. configuration dbPool <- runNoLoggingT $ initPool $ c_dbPath $ model ^. configuration
abList <- getAdrBook dbPool $ model ^. network abList <- getAdrBook dbPool $ model ^. network
@ -1798,7 +2003,14 @@ handleEvent wenv node model evt =
Just zp -> do Just zp -> do
let zbal = (dbal (model ^. balance)) / 100000000 let zbal = (dbal (model ^. balance)) / 100000000
return $ DisplayFIATBalance zp zbal return $ DisplayFIATBalance zp zbal
Nothing -> return $ ShowMessage ( "Currency not supported [" <> c_currencyCode config <> "]") Nothing ->
return $
ShowMessage
("Currency not supported [" <> c_currencyCode config <> "]")
--
procIfValidURI :: T.Text -> IO AppEvent
procIfValidURI ustr = do
return $ ShowSend
scanZebra :: scanZebra ::
T.Text T.Text
@ -2163,6 +2375,9 @@ runZenithGUI config = do
False False
"" ""
"" ""
False
False
""
startApp model handleEvent buildUI (params hD) startApp model handleEvent buildUI (params hD)
Left _e -> print "Zebra not available" Left _e -> print "Zebra not available"
where where

View file

@ -10,6 +10,7 @@ import Control.Monad.Logger
( NoLoggingT ( NoLoggingT
, logErrorN , logErrorN
, logInfoN , logInfoN
, runFileLoggingT
, runNoLoggingT , runNoLoggingT
, runStderrLoggingT , runStderrLoggingT
) )
@ -58,6 +59,7 @@ import Zenith.Types
, ZcashNetDB(..) , ZcashNetDB(..)
, ZenithStatus(..) , ZenithStatus(..)
) )
import Zenith.Types (Config(..), HexStringDB(..), ZcashNetDB(..))
import Zenith.Utils (jsonNumber) import Zenith.Utils (jsonNumber)
-- | Function to scan the Zcash blockchain through the Zebra node and populate the Zenith database -- | Function to scan the Zcash blockchain through the Zebra node and populate the Zenith database

View file

@ -508,3 +508,12 @@ encodeHexText' t =
if T.length t > 0 if T.length t > 0
then C.unpack . B64.encode $ E.encodeUtf8 t then C.unpack . B64.encode $ E.encodeUtf8 t
else C.unpack . B64.encode $ E.encodeUtf8 "Sent from Zenith" else C.unpack . B64.encode $ E.encodeUtf8 "Sent from Zenith"
-- | Define a data structure for the parsed components
data ZcashPaymentURI = ZcashPaymentURI
{ uriAddress :: String
, uriAmount :: Maybe Double
, uriMemo :: T.Text
, uriLabel :: Maybe String
, uriMessage :: Maybe String
} deriving (Show, Eq)

View file

@ -2,25 +2,31 @@
module Zenith.Utils where module Zenith.Utils where
import Control.Exception (SomeException, try)
import Control.Monad (when)
import Data.Aeson import Data.Aeson
import Data.Aeson.Types (parseMaybe)
import qualified Data.Aeson.Key as K import qualified Data.Aeson.Key as K
import qualified Data.Aeson.KeyMap as KM import qualified Data.Aeson.KeyMap as KM
import Data.Aeson.Types (parseMaybe)
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Char8 as BC
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.Char8 as BL
import Data.Char (isAlphaNum, isSpace) import Data.Char (isAlphaNum, isSpace)
import Data.Functor (void) import Data.Functor (void)
import Data.Maybe import Data.Maybe
import Data.Ord (clamp) import Data.Ord (clamp)
import Data.Scientific (Scientific(..), scientific) import Data.Scientific (Scientific(..), scientific)
import Data.Scientific (Scientific, toRealFloat)
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
import Control.Exception (try, SomeException) import qualified Data.Text.Encoding as TE
import Control.Monad (when) import Network.HTTP.Simple
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.Char8 as BL
import System.Directory import System.Directory
import System.Process (createProcess_, shell) import System.Process (createProcess_, shell)
import Text.Regex.Posix
import Text.Printf (printf) import Text.Printf (printf)
import Text.Read (readMaybe)
import Text.Regex.Posix
import ZcashHaskell.Orchard import ZcashHaskell.Orchard
( encodeUnifiedAddress ( encodeUnifiedAddress
, isValidUnifiedAddress , isValidUnifiedAddress
@ -33,10 +39,12 @@ import ZcashHaskell.Transparent
) )
import ZcashHaskell.Types import ZcashHaskell.Types
( ExchangeAddress(..) ( ExchangeAddress(..)
, ExchangeAddress(..)
, SaplingAddress(..) , SaplingAddress(..)
, TransparentAddress(..) , TransparentAddress(..)
, UnifiedAddress(..) , UnifiedAddress(..)
, ValidAddress(..) , ValidAddress(..)
, ValidAddress(..)
, ZcashNet(..) , ZcashNet(..)
) )
import ZcashHaskell.Utils (makeZebraCall) import ZcashHaskell.Utils (makeZebraCall)
@ -45,11 +53,9 @@ import Zenith.Types
, PrivacyPolicy(..) , PrivacyPolicy(..)
, UnifiedAddressDB(..) , UnifiedAddressDB(..)
, ZcashAddress(..) , ZcashAddress(..)
, ZcashPaymentURI(..)
, ZcashPool(..) , ZcashPool(..)
) )
import Network.HTTP.Simple
import Data.Scientific (Scientific, toRealFloat)
-- | Helper function to convert numbers into JSON -- | Helper function to convert numbers into JSON
jsonNumber :: Int -> Value jsonNumber :: Int -> Value
@ -263,17 +269,68 @@ getChainTip zHost zPort = do
-- Function to fetch Zcash price from CoinGecko -- Function to fetch Zcash price from CoinGecko
getZcashPrice :: T.Text -> IO (Maybe Double) getZcashPrice :: T.Text -> IO (Maybe Double)
getZcashPrice currency = do getZcashPrice currency = do
let url = "https://api.coingecko.com/api/v3/simple/price?ids=zcash&vs_currencies=" <> T.unpack currency let url =
"https://api.coingecko.com/api/v3/simple/price?ids=zcash&vs_currencies=" <>
T.unpack currency
response <- httpJSONEither (parseRequest_ url) response <- httpJSONEither (parseRequest_ url)
case getResponseBody response of case getResponseBody response of
Right (Object obj) -> do Right (Object obj)
-- Extract "zcash" object -- Extract "zcash" object
-> do
case KM.lookup "zcash" obj of case KM.lookup "zcash" obj of
Just (Object zcashObj) -> Just (Object zcashObj)
-- Extract the currency price -- Extract the currency price
->
case KM.lookup (K.fromText (T.toLower currency)) zcashObj of case KM.lookup (K.fromText (T.toLower currency)) zcashObj of
Just (Number price) -> return (Just (toRealFloat price)) Just (Number price) -> return (Just (toRealFloat price))
_ -> return Nothing _ -> return Nothing
_ -> return Nothing _ -> return Nothing
_ -> return Nothing _ -> return Nothing
-- Parse memo result to convert it to a ByteString
processEither :: Either String BC.ByteString -> BC.ByteString
processEither (Right bs) = bs
processEither (Left e) = BC.pack e -- Returns the error message
-- Parse the query string into key-value pairs
parseQuery :: String -> [(String, String)]
parseQuery query = map (breakOn '=') (splitOn '&' query)
where
splitOn :: Char -> String -> [String]
splitOn _ [] = [""]
splitOn delim (c:cs)
| c == delim = "" : rest
| otherwise = (c : head rest) : tail rest
where
rest = splitOn delim cs
breakOn :: Char -> String -> (String, String)
breakOn delim str = (key, drop 1 value)
where
(key, value) = span (/= delim) str
-- Parse a ZIP-321 encoded string into a ZcashPayment structure
parseZcashPayment :: String -> Either String ZcashPaymentURI
parseZcashPayment input
| not (T.isPrefixOf "zcash:" (T.pack input)) = Left "Invalid scheme: must start with 'zcash:'"
| otherwise =
let (addrPart, queryPart) = break (== '?') (drop 6 input)
queryParams = parseQuery (drop 1 queryPart)
in Right ZcashPaymentURI
{ uriAddress = addrPart
, uriAmount = lookup "amount" queryParams >>= readMaybe
, uriMemo = case lookup "memo" queryParams of
Just m -> T.pack ( BC.unpack (processEither $ decodeBase64Unpadded (BC.pack m) ) )
_ -> ""
, uriLabel = lookup "label" queryParams
, uriMessage = lookup "message" queryParams
}
-- Function to pad a base64 string if it's not a multiple of 4
padBase64 :: BC.ByteString -> BC.ByteString
padBase64 bs = bs <> BC.replicate paddingLength '='
where
paddingLength = (4 - BC.length bs `mod` 4) `mod` 4
-- Function to decode a base64 un-padded string
decodeBase64Unpadded :: BC.ByteString -> Either String BC.ByteString
decodeBase64Unpadded = B64.decode . padBase64

View file

@ -58,7 +58,16 @@ main = do
zebraPort <- require config "zebraPort" zebraPort <- require config "zebraPort"
zebraHost <- require config "zebraHost" zebraHost <- require config "zebraHost"
nodePort <- require config "nodePort" nodePort <- require config "nodePort"
let myConfig = Config dbFilePath zebraHost zebraPort nodeUser nodePwd nodePort currencyCode <- require config "currencyCode"
let myConfig =
Config
dbFilePath
zebraHost
zebraPort
nodeUser
nodePwd
nodePort
currencyCode
hspec $ do hspec $ do
describe "RPC methods" $ do describe "RPC methods" $ do
beforeAll_ (startAPI myConfig) $ do beforeAll_ (startAPI myConfig) $ do

View file

@ -645,8 +645,7 @@ main = do
case ix of case ix of
Nothing -> assertFailure "couldn't find index at block" Nothing -> assertFailure "couldn't find index at block"
Just i -> do Just i -> do
updatedTree <- updatedTree <- runNoLoggingT $ truncateTree oTree i
runNoLoggingT $ truncateTree oTree i
let finalAnchor = let finalAnchor =
getOrchardTreeAnchor $ getOrchardTreeAnchor $
OrchardCommitmentTree $ ztiOrchard zebraTreesIn OrchardCommitmentTree $ ztiOrchard zebraTreesIn
@ -1111,3 +1110,31 @@ main = do
case price of case price of
Just p -> p `shouldNotBe` 0.0 Just p -> p `shouldNotBe` 0.0
Nothing -> assertFailure "Failed to get ZEC price" Nothing -> assertFailure "Failed to get ZEC price"
describe "Parse an URI payment string (all fields filled) " $ do
it ("Parsing URI -> " ++ "zcash:ztestsapling10yy2ex5....") $ do
let zcashURI2 =
"zcash:ztestsapling10yy2ex5dcqkclhc7z7yrnjq2z6feyjad56ptwlfgmy77dmaqqrl9gyhprdx59qgmsnyfska2kez?amount=100&memo=SGVsbG8sIFdvcmxkIQ==&message=Test"
case parseZcashPayment zcashURI2 of
Right p -> do
print p
(uriAmount p) `shouldBe` Just 100.0
Left e -> assertFailure $ "Error: " ++ e
describe
"Parse an URI payment string (just address and amount fields provided) " $ do
it ("Parsing URI -> " ++ "zcash:ztestsapling10yy2ex5....") $ do
let zcashURI3 =
"zcash:ztestsapling10yy2ex5dcqkclhc7z7yrnjq2z6feyjad56ptwlfgmy77dmaqqrl9gyhprdx59qgmsnyfska2kez?amount=100"
case parseZcashPayment zcashURI3 of
Right p -> do
print p
(uriAmount p) `shouldBe` Just 100.0
Left e -> assertFailure $ "Error: " ++ e
describe "Parse an URI payment string (invalid URI provided) " $ do
it ("Parsing URI -> " ++ "zcash:ztestsapling10yy2ex5....") $ do
let zcashURI3 =
"z:ztestsapling10yy2ex5dcqkclhc7z7yrnjq2z6feyjad56ptwlfgmy77dmaqqrl9gyhprdx59qgmsnyfska2kez?amount=100"
case parseZcashPayment zcashURI3 of
Right p -> do
print p
(uriAmount p) `shouldBe` Just 100.0
Left e -> assertFailure $ "Error: " ++ e

@ -1 +1 @@
Subproject commit 7d3ae36d2b48b8ed91a70e40a77fb7efe57765a0 Subproject commit cfa862ec9495e810e7296fa6fe724b46dbe0ee52