Compare commits
No commits in common. "master" and "0.7.0.0-beta" have entirely different histories.
master
...
0.7.0.0-be
26 changed files with 782 additions and 4228 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -5,7 +5,3 @@ 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
|
|
||||||
|
|
||||||
|
|
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -1,4 +1,4 @@
|
||||||
[submodule "zcash-haskell"]
|
[submodule "zcash-haskell"]
|
||||||
path = zcash-haskell
|
path = zcash-haskell
|
||||||
url = https://code.vergara.tech/Vergara_Tech/zcash-haskell
|
url = https://git.vergara.tech/Vergara_Tech/zcash-haskell.git
|
||||||
branch = master
|
branch = master
|
||||||
|
|
60
CHANGELOG.md
60
CHANGELOG.md
|
@ -5,66 +5,6 @@ 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).
|
||||||
|
|
||||||
## [0.9.1.0-beta]
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- RPC imports
|
|
||||||
|
|
||||||
## [0.9.0.0-beta]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- RPC
|
|
||||||
- `importvk`
|
|
||||||
- TUI
|
|
||||||
- Import viewing keys
|
|
||||||
- Import seed phrase
|
|
||||||
- GUI
|
|
||||||
- Import viewing keys
|
|
||||||
- Import seed phrase
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Database schema for wallets and accounts
|
|
||||||
- RPC:
|
|
||||||
- New field in wallet schema
|
|
||||||
- New field in account schema
|
|
||||||
|
|
||||||
## [0.8.0.0-beta]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- TUI:
|
|
||||||
- Generate payment URI
|
|
||||||
- Read a payment URI
|
|
||||||
- Generate a Full Viewing Key
|
|
||||||
- Generate an Incoming Viewing Key
|
|
||||||
|
|
||||||
- GUI:
|
|
||||||
- Generate payment URI and QR code
|
|
||||||
- Read a payment URI and QR code
|
|
||||||
- Generate a Full Viewing Key
|
|
||||||
- Generate an Incoming Viewing Key
|
|
||||||
|
|
||||||
- RPC methods:
|
|
||||||
- `shieldnotes`
|
|
||||||
- `deshieldfunds`
|
|
||||||
- `getfullvk`
|
|
||||||
- `getincomingvk`
|
|
||||||
|
|
||||||
## [0.7.2.0-beta]
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Creation of change addresses during account creation in GUI ([#111](https://code.vergara.tech/Vergara_Tech/zenith/issues/111))
|
|
||||||
|
|
||||||
## [0.7.1.0-beta]
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Removed workaround to obtain block time
|
|
||||||
|
|
||||||
## [0.7.0.0-beta]
|
## [0.7.0.0-beta]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
11
app/Main.hs
11
app/Main.hs
|
@ -210,18 +210,9 @@ 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"
|
||||||
currencyCode <- require config "currencyCode"
|
|
||||||
dbFP <- getZenithPath
|
dbFP <- getZenithPath
|
||||||
let dbFilePath = T.pack $ dbFP ++ dbFileName
|
let dbFilePath = T.pack $ dbFP ++ dbFileName
|
||||||
let myConfig =
|
let myConfig = Config dbFilePath zebraHost zebraPort nodeUser nodePwd nodePort
|
||||||
Config
|
|
||||||
dbFilePath
|
|
||||||
zebraHost
|
|
||||||
zebraPort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
nodePort
|
|
||||||
currencyCode
|
|
||||||
if not (null args)
|
if not (null args)
|
||||||
then do
|
then do
|
||||||
case head args
|
case head args
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Server where
|
||||||
import Control.Concurrent (forkIO, threadDelay)
|
import Control.Concurrent (forkIO, threadDelay)
|
||||||
import Control.Exception (throwIO, throwTo, try)
|
import Control.Exception (throwIO, throwTo, try)
|
||||||
import Control.Monad (forever, when)
|
import Control.Monad (forever, when)
|
||||||
import Control.Monad.Logger (runNoLoggingT, runStderrLoggingT)
|
import Control.Monad.Logger (runNoLoggingT)
|
||||||
import Data.Configurator
|
import Data.Configurator
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Network.Wai.Handler.Warp (run)
|
import Network.Wai.Handler.Warp (run)
|
||||||
|
@ -14,7 +14,7 @@ import System.Exit
|
||||||
import System.Posix.Signals
|
import System.Posix.Signals
|
||||||
import ZcashHaskell.Types (ZebraGetBlockChainInfo(..), ZebraGetInfo(..))
|
import ZcashHaskell.Types (ZebraGetBlockChainInfo(..), ZebraGetInfo(..))
|
||||||
import Zenith.Core (checkBlockChain, checkZebra)
|
import Zenith.Core (checkBlockChain, checkZebra)
|
||||||
import Zenith.DB (getWallets, initDb, initPool, upgradeAccountTable)
|
import Zenith.DB (getWallets, initDb, initPool)
|
||||||
import Zenith.RPC
|
import Zenith.RPC
|
||||||
( State(..)
|
( State(..)
|
||||||
, ZenithRPC(..)
|
, ZenithRPC(..)
|
||||||
|
@ -35,18 +35,9 @@ 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"
|
||||||
currencyCode <- require config "currencyCode"
|
|
||||||
dbFP <- getZenithPath
|
dbFP <- getZenithPath
|
||||||
let dbFilePath = T.pack $ dbFP ++ dbFileName
|
let dbFilePath = T.pack $ dbFP ++ dbFileName
|
||||||
let myConfig =
|
let myConfig = Config dbFilePath zebraHost zebraPort nodeUser nodePwd nodePort
|
||||||
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
|
||||||
|
@ -57,13 +48,12 @@ main = do
|
||||||
case bc of
|
case bc of
|
||||||
Left e1 -> throwIO e1
|
Left e1 -> throwIO e1
|
||||||
Right chainInfo -> do
|
Right chainInfo -> do
|
||||||
x <- runNoLoggingT $ initDb dbFilePath
|
x <- initDb dbFilePath
|
||||||
case x of
|
case x of
|
||||||
Left e2 -> throwIO $ userError e2
|
Left e2 -> throwIO $ userError e2
|
||||||
Right x' -> do
|
Right x' -> do
|
||||||
when x' $ rescanZebra zebraHost zebraPort dbFilePath
|
when x' $ rescanZebra zebraHost zebraPort dbFilePath
|
||||||
pool <- runNoLoggingT $ initPool dbFilePath
|
pool <- runNoLoggingT $ initPool dbFilePath
|
||||||
_ <- runNoLoggingT $ upgradeAccountTable pool
|
|
||||||
walList <- getWallets pool $ zgb_net chainInfo
|
walList <- getWallets pool $ zgb_net chainInfo
|
||||||
if not (null walList)
|
if not (null walList)
|
||||||
then do
|
then do
|
||||||
|
@ -77,7 +67,7 @@ main = do
|
||||||
zebraPort
|
zebraPort
|
||||||
(zgb_net chainInfo)
|
(zgb_net chainInfo)
|
||||||
threadDelay 90000000
|
threadDelay 90000000
|
||||||
putStrLn "Zenith RPC Server 0.9.1.0-beta"
|
putStrLn "Zenith RPC Server 0.7.0.0-beta"
|
||||||
putStrLn "------------------------------"
|
putStrLn "------------------------------"
|
||||||
putStrLn $
|
putStrLn $
|
||||||
"Connected to " ++
|
"Connected to " ++
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 33 KiB |
|
@ -6,15 +6,10 @@ with-compiler: ghc-9.6.5
|
||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://code.vergara.tech/Vergara_Tech/haskell-hexstring.git
|
location: https://git.vergara.tech/Vergara_Tech/haskell-hexstring.git
|
||||||
tag: 39d8da7b11a80269454c2f134a5c834e0f3cb9a7
|
tag: 39d8da7b11a80269454c2f134a5c834e0f3cb9a7
|
||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://code.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
|
location: https://git.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
|
||||||
tag: 335e804454cd30da2c526457be37e477f71e4665
|
tag: 335e804454cd30da2c526457be37e477f71e4665
|
||||||
|
|
||||||
source-repository-package
|
|
||||||
type: git
|
|
||||||
location: https://code.vergara.tech/Vergara_Tech/persistent-sqlite.git
|
|
||||||
tag: 85093ef51cb2bd245ac9a85925770fdb55afce9e
|
|
||||||
|
|
|
@ -9,18 +9,19 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
any.OneTuple ==0.4.2,
|
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.15.0.1,
|
any.QuickCheck ==2.14.3,
|
||||||
QuickCheck -old-random +templatehaskell,
|
QuickCheck -old-random +templatehaskell,
|
||||||
any.RSA ==2.4.1,
|
any.RSA ==2.4.1,
|
||||||
any.SHA ==1.6.4.4,
|
any.SHA ==1.6.4.4,
|
||||||
SHA -exe,
|
SHA -exe,
|
||||||
any.StateVar ==1.2.2,
|
any.StateVar ==1.2.2,
|
||||||
any.X11 ==1.9.2,
|
any.X11 ==1.10.3,
|
||||||
|
X11 -pedantic,
|
||||||
any.adjunctions ==4.4.2,
|
any.adjunctions ==4.4.2,
|
||||||
any.aeson ==2.2.3.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.2,
|
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,
|
||||||
|
@ -38,11 +39,11 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
attoparsec -developer,
|
attoparsec -developer,
|
||||||
any.attoparsec-aeson ==2.2.2.0,
|
any.attoparsec-aeson ==2.2.2.0,
|
||||||
any.authenticate-oauth ==1.7,
|
any.authenticate-oauth ==1.7,
|
||||||
any.auto-update ==0.2.4,
|
any.auto-update ==0.2.1,
|
||||||
any.base ==4.18.2.1,
|
any.base ==4.18.2.1,
|
||||||
any.base-compat ==0.14.1,
|
any.base-compat ==0.13.1,
|
||||||
any.base-compat-batteries ==0.14.1,
|
any.base-compat-batteries ==0.13.1,
|
||||||
any.base-orphans ==0.9.3,
|
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,
|
||||||
|
@ -61,16 +62,18 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
any.boring ==0.2.2,
|
any.boring ==0.2.2,
|
||||||
boring +tagged,
|
boring +tagged,
|
||||||
any.borsh ==0.3.0,
|
any.borsh ==0.3.0,
|
||||||
any.brick ==2.6,
|
any.brick ==2.4,
|
||||||
brick -demos,
|
brick -demos,
|
||||||
any.bsb-http-chunked ==0.0.0.4,
|
any.bsb-http-chunked ==0.0.0.4,
|
||||||
any.byteorder ==1.0.4,
|
any.byteorder ==1.0.4,
|
||||||
any.bytes ==0.17.4,
|
any.bytes ==0.17.3,
|
||||||
any.bytestring ==0.11.5.3,
|
any.bytestring ==0.11.5.3,
|
||||||
|
any.bytestring-builder ==0.10.8.2.0,
|
||||||
|
bytestring-builder +bytestring_has_builder,
|
||||||
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.11,
|
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,
|
||||||
|
@ -81,10 +84,10 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
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.9,
|
any.comonad ==5.0.8,
|
||||||
comonad +containers +distributive +indexed-traversable,
|
comonad +containers +distributive +indexed-traversable,
|
||||||
any.concurrent-output ==1.10.21,
|
any.concurrent-output ==1.10.21,
|
||||||
any.conduit ==1.3.6,
|
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,
|
||||||
config-ini -enable-doctests,
|
config-ini -enable-doctests,
|
||||||
|
@ -98,20 +101,21 @@ constraints: any.Cabal ==3.10.3.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.cryptohash-md5 ==0.11.101.0,
|
any.crypton ==1.0.0,
|
||||||
any.cryptohash-sha1 ==0.11.101.0,
|
|
||||||
any.crypton ==1.0.1,
|
|
||||||
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.4.3,
|
any.crypton-connection ==0.4.1,
|
||||||
any.crypton-x509 ==1.7.7,
|
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.13,
|
any.crypton-x509-validation ==1.6.12,
|
||||||
any.cryptonite ==0.30,
|
any.cryptonite ==0.30,
|
||||||
cryptonite -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq -support_pclmuldq +support_rdrand -support_sse +use_target_attributes,
|
cryptonite -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq -support_pclmuldq +support_rdrand -support_sse +use_target_attributes,
|
||||||
any.data-clist ==0.2,
|
any.data-clist ==0.2,
|
||||||
any.data-default ==0.8.0.0,
|
any.data-default ==0.7.1.1,
|
||||||
any.data-default-class ==0.2.0.0,
|
any.data-default-class ==0.1.2.0,
|
||||||
|
any.data-default-instances-containers ==0.0.1,
|
||||||
|
any.data-default-instances-dlist ==0.0.1,
|
||||||
|
any.data-default-instances-old-locale ==0.0.1,
|
||||||
any.data-fix ==0.3.4,
|
any.data-fix ==0.3.4,
|
||||||
any.dec ==0.0.6,
|
any.dec ==0.0.6,
|
||||||
any.deepseq ==1.4.8.1,
|
any.deepseq ==1.4.8.1,
|
||||||
|
@ -125,11 +129,11 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
any.easy-file ==0.2.5,
|
any.easy-file ==0.2.5,
|
||||||
any.entropy ==0.4.1.10,
|
any.entropy ==0.4.1.10,
|
||||||
entropy -donotgetentropy,
|
entropy -donotgetentropy,
|
||||||
any.envy ==2.1.4.0,
|
any.envy ==2.1.3.0,
|
||||||
any.esqueleto ==3.5.13.1,
|
any.esqueleto ==3.5.11.2,
|
||||||
any.exceptions ==0.10.7,
|
any.exceptions ==0.10.7,
|
||||||
any.extra ==1.8,
|
any.extra ==1.7.16,
|
||||||
any.fast-logger ==3.2.5,
|
any.fast-logger ==3.2.3,
|
||||||
any.file-embed ==0.0.16.0,
|
any.file-embed ==0.0.16.0,
|
||||||
any.filepath ==1.4.300.1,
|
any.filepath ==1.4.300.1,
|
||||||
any.fixed ==0.3,
|
any.fixed ==0.3,
|
||||||
|
@ -138,6 +142,8 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
any.formatting ==7.2.0,
|
any.formatting ==7.2.0,
|
||||||
formatting -no-double-conversion,
|
formatting -no-double-conversion,
|
||||||
any.free ==5.2,
|
any.free ==5.2,
|
||||||
|
any.generic-deriving ==1.14.5,
|
||||||
|
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.6.5,
|
any.ghc ==9.6.5,
|
||||||
|
@ -147,34 +153,33 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
any.ghc-heap ==9.6.5,
|
any.ghc-heap ==9.6.5,
|
||||||
any.ghc-prim ==0.10.0,
|
any.ghc-prim ==0.10.0,
|
||||||
any.ghci ==9.6.5,
|
any.ghci ==9.6.5,
|
||||||
any.half ==0.3.2,
|
any.half ==0.3.1,
|
||||||
any.happy ==2.1.3,
|
any.happy ==1.20.1.1,
|
||||||
any.happy-lib ==2.1.3,
|
|
||||||
any.hashable ==1.4.7.0,
|
any.hashable ==1.4.7.0,
|
||||||
hashable -arch-native +integer-gmp -random-initial-seed,
|
hashable -arch-native +integer-gmp -random-initial-seed,
|
||||||
any.haskell-lexer ==1.1.2,
|
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.2.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.10,
|
any.hspec ==2.11.9,
|
||||||
any.hspec-core ==2.11.10,
|
any.hspec-core ==2.11.9,
|
||||||
any.hspec-discover ==2.11.10,
|
any.hspec-discover ==2.11.9,
|
||||||
any.hspec-expectations ==0.8.4,
|
any.hspec-expectations ==0.8.4,
|
||||||
any.http-api-data ==0.6.1,
|
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,
|
||||||
any.http-client-tls ==0.3.6.4,
|
any.http-client-tls ==0.3.6.3,
|
||||||
any.http-conduit ==2.3.9.1,
|
any.http-conduit ==2.3.8.3,
|
||||||
http-conduit +aeson,
|
http-conduit +aeson,
|
||||||
any.http-date ==0.0.11,
|
any.http-date ==0.0.11,
|
||||||
any.http-media ==0.8.1.1,
|
any.http-media ==0.8.1.1,
|
||||||
any.http-semantics ==0.3.0,
|
any.http-semantics ==0.1.2,
|
||||||
any.http-types ==0.12.4,
|
any.http-types ==0.12.4,
|
||||||
any.http2 ==5.3.9,
|
any.http2 ==5.2.6,
|
||||||
http2 -devel -h2spec,
|
http2 -devel -h2spec,
|
||||||
any.indexed-traversable ==0.1.4,
|
any.indexed-traversable ==0.1.4,
|
||||||
any.indexed-traversable-instances ==0.1.2,
|
any.indexed-traversable-instances ==0.1.2,
|
||||||
|
@ -182,19 +187,19 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
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.4,
|
any.invariant ==0.6.3,
|
||||||
any.iproute ==1.7.15,
|
any.iproute ==1.7.12,
|
||||||
any.kan-extensions ==5.2.6,
|
any.kan-extensions ==5.2.6,
|
||||||
any.language-c ==0.10.0,
|
any.language-c ==0.9.3,
|
||||||
language-c +iecfpextension +usebytestrings,
|
language-c -allwarnings +iecfpextension +usebytestrings,
|
||||||
any.lens ==5.3.2,
|
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.2.0,
|
any.lift-type ==0.1.1.1,
|
||||||
any.lifted-base ==0.2.3.12,
|
any.lifted-base ==0.2.3.12,
|
||||||
any.linear ==1.22,
|
any.linear ==1.22,
|
||||||
linear -herbie +template-haskell,
|
linear -herbie +template-haskell,
|
||||||
any.megaparsec ==9.7.0,
|
any.megaparsec ==9.6.1,
|
||||||
megaparsec -dev,
|
megaparsec -dev,
|
||||||
any.memory ==0.18.0,
|
any.memory ==0.18.0,
|
||||||
memory +support_bytestring +support_deepseq,
|
memory +support_bytestring +support_deepseq,
|
||||||
|
@ -208,31 +213,30 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
monad-logger +template_haskell,
|
monad-logger +template_haskell,
|
||||||
any.monad-loops ==0.4.3,
|
any.monad-loops ==0.4.3,
|
||||||
monad-loops +base4,
|
monad-loops +base4,
|
||||||
any.mono-traversable ==1.0.21.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.3.1,
|
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.2.7.0,
|
any.network ==3.2.1.0,
|
||||||
network -devel,
|
network -devel,
|
||||||
any.network-byte-order ==0.1.7,
|
any.network-byte-order ==0.1.7,
|
||||||
any.network-control ==0.1.3,
|
any.network-control ==0.1.1,
|
||||||
any.network-info ==0.2.1,
|
|
||||||
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.optparse-applicative ==0.18.1.0,
|
any.optparse-applicative ==0.18.1.0,
|
||||||
optparse-applicative +process,
|
optparse-applicative +process,
|
||||||
any.os-string ==2.0.7,
|
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,
|
||||||
parser-combinators -dev,
|
parser-combinators -dev,
|
||||||
any.path-pieces ==0.2.1,
|
any.path-pieces ==0.2.1,
|
||||||
any.pem ==0.2.4,
|
any.pem ==0.2.4,
|
||||||
any.persistent ==2.14.6.3,
|
any.persistent ==2.14.6.1,
|
||||||
any.persistent-sqlite ==2.13.3.0,
|
any.persistent-sqlite ==2.13.3.0,
|
||||||
persistent-sqlite -build-sanity-exe +full-text-search +have-usleep +json1 -systemlib +uri-filenames -use-pkgconfig -use-stat3 +use-stat4,
|
persistent-sqlite -build-sanity-exe +full-text-search +have-usleep +json1 -systemlib +uri-filenames -use-pkgconfig -use-stat3 +use-stat4,
|
||||||
any.persistent-template ==2.12.0.0,
|
any.persistent-template ==2.12.0.0,
|
||||||
|
@ -246,13 +250,13 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
any.psqueues ==0.2.8.0,
|
any.psqueues ==0.2.8.0,
|
||||||
any.pureMD5 ==2.1.4,
|
any.pureMD5 ==2.1.4,
|
||||||
pureMD5 -test,
|
pureMD5 -test,
|
||||||
any.qrcode-core ==0.9.10,
|
any.qrcode-core ==0.9.9,
|
||||||
any.qrcode-juicypixels ==0.8.6,
|
any.qrcode-juicypixels ==0.8.5,
|
||||||
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.recv ==0.1.0,
|
any.recv ==0.1.0,
|
||||||
any.reflection ==2.1.9,
|
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,
|
||||||
|
@ -267,7 +271,7 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
scientific -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.4.2,
|
any.secp256k1-haskell ==1.2.0,
|
||||||
any.semialign ==1.3.1,
|
any.semialign ==1.3.1,
|
||||||
semialign +semigroupoids,
|
semialign +semigroupoids,
|
||||||
any.semigroupoids ==6.0.1,
|
any.semigroupoids ==6.0.1,
|
||||||
|
@ -276,9 +280,9 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
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,
|
||||||
any.serialise ==0.2.6.1,
|
any.serialise ==0.2.6.1,
|
||||||
serialise +newtime15,
|
serialise +newtime15,
|
||||||
any.servant ==0.20.2,
|
any.servant ==0.20.1,
|
||||||
any.servant-server ==0.20.2,
|
any.servant-server ==0.20,
|
||||||
any.silently ==1.2.5.4,
|
any.silently ==1.2.5.3,
|
||||||
any.simple-sendfile ==0.2.32,
|
any.simple-sendfile ==0.2.32,
|
||||||
simple-sendfile +allow-bsd -fallback,
|
simple-sendfile +allow-bsd -fallback,
|
||||||
any.singleton-bool ==0.1.8,
|
any.singleton-bool ==0.1.8,
|
||||||
|
@ -297,10 +301,8 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
any.strict ==0.5.1,
|
any.strict ==0.5.1,
|
||||||
any.string-conversions ==0.4.0.1,
|
any.string-conversions ==0.4.0.1,
|
||||||
any.system-cxx-std-lib ==1.0,
|
any.system-cxx-std-lib ==1.0,
|
||||||
any.tagged ==0.8.9,
|
any.tagged ==0.8.8,
|
||||||
tagged +deepseq +transformers,
|
tagged +deepseq +transformers,
|
||||||
any.tasty ==1.5.2,
|
|
||||||
tasty +unix,
|
|
||||||
any.template-haskell ==2.20.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.6,
|
any.terminfo ==0.4.1.6,
|
||||||
|
@ -308,43 +310,42 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
any.text-iso8601 ==0.1.1,
|
any.text-iso8601 ==0.1.1,
|
||||||
any.text-short ==0.1.6,
|
any.text-short ==0.1.6,
|
||||||
text-short -asserts,
|
text-short -asserts,
|
||||||
any.text-show ==3.11,
|
any.text-show ==3.10.5,
|
||||||
text-show +integer-gmp,
|
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.7.1.0,
|
any.th-abstraction ==0.7.0.0,
|
||||||
any.th-compat ==0.1.6,
|
any.th-compat ==0.1.5,
|
||||||
any.th-lift ==0.8.6,
|
any.th-lift ==0.8.4,
|
||||||
any.th-lift-instances ==0.1.20,
|
any.th-lift-instances ==0.1.20,
|
||||||
any.these ==1.2.1,
|
any.these ==1.2.1,
|
||||||
any.time ==1.12.2,
|
any.time ==1.12.2,
|
||||||
any.time-compat ==1.9.7,
|
any.time-compat ==1.9.7,
|
||||||
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.time-manager ==0.2.1,
|
any.time-manager ==0.1.0,
|
||||||
any.tls ==2.1.5,
|
any.tls ==2.1.0,
|
||||||
tls -devel,
|
tls -devel,
|
||||||
any.transformers ==0.6.1.0,
|
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.12.0,
|
any.typed-process ==0.2.11.1,
|
||||||
any.unix ==2.8.4.0,
|
any.unix ==2.8.4.0,
|
||||||
any.unix-compat ==0.7.3,
|
any.unix-compat ==0.7.2,
|
||||||
any.unix-time ==0.4.16,
|
any.unix-time ==0.4.15,
|
||||||
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 ==1.3.16,
|
|
||||||
any.uuid-types ==1.0.6,
|
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.2.0,
|
any.vector ==0.13.1.0,
|
||||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||||
any.vector-algorithms ==0.9.0.3,
|
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,
|
||||||
|
@ -356,10 +357,10 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
any.wai ==3.2.4,
|
any.wai ==3.2.4,
|
||||||
any.wai-app-static ==3.1.9,
|
any.wai-app-static ==3.1.9,
|
||||||
wai-app-static +crypton -print,
|
wai-app-static +crypton -print,
|
||||||
any.wai-extra ==3.1.17,
|
any.wai-extra ==3.1.15,
|
||||||
wai-extra -build-example,
|
wai-extra -build-example,
|
||||||
any.wai-logger ==2.5.0,
|
any.wai-logger ==2.4.0,
|
||||||
any.warp ==3.4.7,
|
any.warp ==3.4.1,
|
||||||
warp +allow-sendfilefd -network-bytestring -warp-debug +x509,
|
warp +allow-sendfilefd -network-bytestring -warp-debug +x509,
|
||||||
any.wide-word ==0.1.6.0,
|
any.wide-word ==0.1.6.0,
|
||||||
any.witherable ==0.5,
|
any.witherable ==0.5,
|
||||||
|
@ -369,4 +370,4 @@ constraints: any.Cabal ==3.10.3.0,
|
||||||
wreq -aws -developer +doctest -httpbin,
|
wreq -aws -developer +doctest -httpbin,
|
||||||
any.zlib ==0.7.1.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-12-14T09:52:48Z
|
index-state: hackage.haskell.org 2024-07-10T18:40:26Z
|
||||||
|
|
BIN
sapling-output.params
Normal file
BIN
sapling-output.params
Normal file
Binary file not shown.
BIN
sapling-spend.params
Normal file
BIN
sapling-spend.params
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,6 @@
|
||||||
-- | Core wallet functionality for Zenith
|
-- | Core wallet functionality for Zenith
|
||||||
module Zenith.Core where
|
module Zenith.Core where
|
||||||
|
|
||||||
import Control.Concurrent (forkIO)
|
|
||||||
import Control.Exception (throwIO, try)
|
import Control.Exception (throwIO, try)
|
||||||
import Control.Monad (forM, unless, when)
|
import Control.Monad (forM, unless, when)
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
|
@ -21,13 +20,11 @@ import qualified Data.ByteString as BS
|
||||||
import Data.HexString (HexString, hexBytes, hexString, toBytes, toText)
|
import Data.HexString (HexString, hexBytes, hexString, toBytes, toText)
|
||||||
import Data.Int (Int32, Int64)
|
import Data.Int (Int32, Int64)
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.Maybe (catMaybes, fromJust, fromMaybe, isJust, isNothing)
|
import Data.Maybe (fromJust, fromMaybe)
|
||||||
import Data.Scientific (Scientific, scientific, toBoundedInteger)
|
import Data.Scientific (Scientific, scientific, toBoundedInteger)
|
||||||
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 Data.Time
|
import Data.Time
|
||||||
import qualified Data.UUID as U
|
|
||||||
import Data.UUID.V4 (nextRandom)
|
|
||||||
import qualified Database.Esqueleto.Experimental as ESQ
|
import qualified Database.Esqueleto.Experimental as ESQ
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
import Database.Persist.Sqlite
|
import Database.Persist.Sqlite
|
||||||
|
@ -35,39 +32,33 @@ import Haskoin.Crypto.Keys (XPrvKey(..))
|
||||||
import Lens.Micro ((&), (.~), (^.), set)
|
import Lens.Micro ((&), (.~), (^.), set)
|
||||||
import ZcashHaskell.Keys
|
import ZcashHaskell.Keys
|
||||||
import ZcashHaskell.Orchard
|
import ZcashHaskell.Orchard
|
||||||
( decodeUfvk
|
( decryptOrchardActionSK
|
||||||
, decodeUivk
|
|
||||||
, decryptOrchardActionFvk
|
|
||||||
, decryptOrchardActionIvk
|
|
||||||
, decryptOrchardActionSK
|
|
||||||
, encodeUnifiedAddress
|
, encodeUnifiedAddress
|
||||||
, genOrchardReceiver
|
, genOrchardReceiver
|
||||||
, genOrchardReceiverFvk
|
|
||||||
, genOrchardReceiverIvk
|
|
||||||
, genOrchardSpendingKey
|
, genOrchardSpendingKey
|
||||||
|
, getOrchardFrontier
|
||||||
|
, getOrchardNotePosition
|
||||||
, getOrchardTreeParts
|
, getOrchardTreeParts
|
||||||
|
, getOrchardWitness
|
||||||
, isValidUnifiedAddress
|
, isValidUnifiedAddress
|
||||||
, parseAddress
|
, updateOrchardCommitmentTree
|
||||||
, updateOrchardWitness
|
, updateOrchardWitness
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Sapling
|
import ZcashHaskell.Sapling
|
||||||
( decodeSaplingOutputEsk
|
( decodeSaplingOutputEsk
|
||||||
, decodeSaplingOutputFvk
|
|
||||||
, decodeSaplingOutputIvk
|
|
||||||
, genSaplingInternalAddress
|
, genSaplingInternalAddress
|
||||||
, genSaplingInternalAddressFvk
|
|
||||||
, genSaplingPaymentAddress
|
, genSaplingPaymentAddress
|
||||||
, genSaplingReceiverFvk
|
|
||||||
, genSaplingReceiverIvk
|
|
||||||
, genSaplingSpendingKey
|
, genSaplingSpendingKey
|
||||||
|
, getSaplingFrontier
|
||||||
|
, getSaplingNotePosition
|
||||||
, getSaplingTreeParts
|
, getSaplingTreeParts
|
||||||
|
, getSaplingWitness
|
||||||
|
, updateSaplingCommitmentTree
|
||||||
, updateSaplingWitness
|
, updateSaplingWitness
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Transparent
|
import ZcashHaskell.Transparent
|
||||||
( genTransparentPrvKey
|
( genTransparentPrvKey
|
||||||
, genTransparentReceiver
|
, genTransparentReceiver
|
||||||
, genTransparentReceiverFvk
|
|
||||||
, genTransparentReceiverIvk
|
|
||||||
, genTransparentSecretKey
|
, genTransparentSecretKey
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
|
@ -75,8 +66,7 @@ import ZcashHaskell.Utils
|
||||||
import Zenith.DB
|
import Zenith.DB
|
||||||
import Zenith.Tree
|
import Zenith.Tree
|
||||||
import Zenith.Types
|
import Zenith.Types
|
||||||
( AccountType(..)
|
( Config(..)
|
||||||
, Config(..)
|
|
||||||
, HexStringDB(..)
|
, HexStringDB(..)
|
||||||
, OrchardSpendingKeyDB(..)
|
, OrchardSpendingKeyDB(..)
|
||||||
, PhraseDB(..)
|
, PhraseDB(..)
|
||||||
|
@ -87,15 +77,10 @@ import Zenith.Types
|
||||||
, ScopeDB(..)
|
, ScopeDB(..)
|
||||||
, TransparentSpendingKeyDB(..)
|
, TransparentSpendingKeyDB(..)
|
||||||
, UnifiedAddressDB(..)
|
, UnifiedAddressDB(..)
|
||||||
, UnifiedFvkDB(..)
|
|
||||||
, UnifiedIvkDB(..)
|
|
||||||
, ValidAddressAPI(..)
|
, ValidAddressAPI(..)
|
||||||
, ZcashNetDB(..)
|
, ZcashNetDB(..)
|
||||||
, ZebraTreeInfo(..)
|
, ZebraTreeInfo(..)
|
||||||
, ZenithStatus(..)
|
|
||||||
, ZenithUuid(..)
|
|
||||||
)
|
)
|
||||||
import Zenith.Utils (getTransparentFromUA)
|
|
||||||
|
|
||||||
-- * Zebra Node interaction
|
-- * Zebra Node interaction
|
||||||
-- | Checks the status of the `zebrad` node
|
-- | Checks the status of the `zebrad` node
|
||||||
|
@ -205,26 +190,20 @@ createTransparentSpendingKey zw i = do
|
||||||
createZcashAccount ::
|
createZcashAccount ::
|
||||||
T.Text -- ^ The account's name
|
T.Text -- ^ The account's name
|
||||||
-> Int -- ^ The account's index
|
-> Int -- ^ The account's index
|
||||||
-> ZcashNet -- ^ The network
|
|
||||||
-> Entity ZcashWallet -- ^ The Zcash wallet that this account will be attached to
|
-> Entity ZcashWallet -- ^ The Zcash wallet that this account will be attached to
|
||||||
-> IO ZcashAccount
|
-> IO ZcashAccount
|
||||||
createZcashAccount n i znet zw = do
|
createZcashAccount n i zw = do
|
||||||
orSk <- createOrchardSpendingKey (entityVal zw) i
|
orSk <- createOrchardSpendingKey (entityVal zw) i
|
||||||
sapSk <- createSaplingSpendingKey (entityVal zw) i
|
sapSk <- createSaplingSpendingKey (entityVal zw) i
|
||||||
tSk <- createTransparentSpendingKey (entityVal zw) i
|
tSk <- createTransparentSpendingKey (entityVal zw) i
|
||||||
FullVk fvk <- deriveUfvk znet (Just orSk) (Just sapSk) (Just tSk)
|
|
||||||
IncomingVk ivk <- deriveUivk znet (Just orSk) (Just sapSk) (Just tSk)
|
|
||||||
return $
|
return $
|
||||||
ZcashAccount
|
ZcashAccount
|
||||||
i
|
i
|
||||||
(entityKey zw)
|
(entityKey zw)
|
||||||
n
|
n
|
||||||
(Just $ OrchardSpendingKeyDB orSk)
|
(OrchardSpendingKeyDB orSk)
|
||||||
(Just $ SaplingSpendingKeyDB sapSk)
|
(SaplingSpendingKeyDB sapSk)
|
||||||
(Just $ TransparentSpendingKeyDB tSk)
|
(TransparentSpendingKeyDB tSk)
|
||||||
(Just $ UnifiedFvkDB fvk)
|
|
||||||
(Just $ UnifiedIvkDB ivk)
|
|
||||||
Local
|
|
||||||
|
|
||||||
-- * Addresses
|
-- * Addresses
|
||||||
-- | Create an external unified address for the given account and index
|
-- | Create an external unified address for the given account and index
|
||||||
|
@ -236,70 +215,27 @@ createWalletAddress ::
|
||||||
-> Entity ZcashAccount -- ^ The Zcash account that the address will be attached to
|
-> Entity ZcashAccount -- ^ The Zcash account that the address will be attached to
|
||||||
-> IO WalletAddress
|
-> IO WalletAddress
|
||||||
createWalletAddress n i zNet scope za = do
|
createWalletAddress n i zNet scope za = do
|
||||||
case zcashAccountType (entityVal za) of
|
|
||||||
Local -> do
|
|
||||||
let oRec =
|
let oRec =
|
||||||
genOrchardReceiver i scope . getOrchSK =<<
|
genOrchardReceiver i scope $
|
||||||
zcashAccountOrchSpendKey (entityVal za)
|
getOrchSK $ zcashAccountOrchSpendKey $ entityVal za
|
||||||
let sRec =
|
let sRec =
|
||||||
case scope of
|
case scope of
|
||||||
External ->
|
External ->
|
||||||
genSaplingPaymentAddress i . getSapSK =<<
|
genSaplingPaymentAddress i $
|
||||||
zcashAccountSapSpendKey (entityVal za)
|
getSapSK $ zcashAccountSapSpendKey $ entityVal za
|
||||||
Internal ->
|
Internal ->
|
||||||
genSaplingInternalAddress . getSapSK =<<
|
genSaplingInternalAddress $
|
||||||
zcashAccountSapSpendKey (entityVal za)
|
getSapSK $ zcashAccountSapSpendKey $ entityVal za
|
||||||
let tKey = getTranSK <$> zcashAccountTPrivateKey (entityVal za)
|
|
||||||
tRec <-
|
tRec <-
|
||||||
case tKey of
|
genTransparentReceiver i scope $
|
||||||
Nothing -> return Nothing
|
getTranSK $ zcashAccountTPrivateKey $ entityVal za
|
||||||
Just k -> do
|
|
||||||
x <- genTransparentReceiver i scope k
|
|
||||||
return $ Just x
|
|
||||||
return $
|
return $
|
||||||
WalletAddress
|
WalletAddress
|
||||||
i
|
i
|
||||||
(entityKey za)
|
(entityKey za)
|
||||||
n
|
n
|
||||||
(UnifiedAddressDB $
|
(UnifiedAddressDB $
|
||||||
encodeUnifiedAddress $ UnifiedAddress zNet oRec sRec tRec)
|
encodeUnifiedAddress $ UnifiedAddress zNet oRec sRec (Just tRec))
|
||||||
(ScopeDB scope)
|
|
||||||
FullViewKey -> do
|
|
||||||
let fvk = zcashAccountFvk (entityVal za)
|
|
||||||
let oRec = genOrchardReceiverFvk i scope . o_key . getFvk =<< fvk
|
|
||||||
let sRec =
|
|
||||||
case scope of
|
|
||||||
External -> genSaplingReceiverFvk i . s_key . getFvk =<< fvk
|
|
||||||
Internal -> genSaplingInternalAddressFvk . s_key . getFvk =<< fvk
|
|
||||||
let tKey = t_key . getFvk <$> fvk
|
|
||||||
tRec <-
|
|
||||||
case tKey of
|
|
||||||
Nothing -> return Nothing
|
|
||||||
Just k -> genTransparentReceiverFvk i scope k
|
|
||||||
return $
|
|
||||||
WalletAddress
|
|
||||||
i
|
|
||||||
(entityKey za)
|
|
||||||
n
|
|
||||||
(UnifiedAddressDB $
|
|
||||||
encodeUnifiedAddress $ UnifiedAddress zNet oRec sRec tRec)
|
|
||||||
(ScopeDB scope)
|
|
||||||
IncomingViewKey -> do
|
|
||||||
let ivk = zcashAccountIvk (entityVal za)
|
|
||||||
let oRec = genOrchardReceiverIvk i . i_o_key . getIvk =<< ivk
|
|
||||||
let sRec = genSaplingReceiverIvk i . i_s_key . getIvk =<< ivk
|
|
||||||
let tKey = i_t_key . getIvk <$> ivk
|
|
||||||
tRec <-
|
|
||||||
case tKey of
|
|
||||||
Nothing -> return Nothing
|
|
||||||
Just k -> genTransparentReceiverIvk i k
|
|
||||||
return $
|
|
||||||
WalletAddress
|
|
||||||
i
|
|
||||||
(entityKey za)
|
|
||||||
n
|
|
||||||
(UnifiedAddressDB $
|
|
||||||
encodeUnifiedAddress $ UnifiedAddress zNet oRec sRec tRec)
|
|
||||||
(ScopeDB scope)
|
(ScopeDB scope)
|
||||||
|
|
||||||
-- | Create an external unified address for the given account and index with custom receivers
|
-- | Create an external unified address for the given account and index with custom receivers
|
||||||
|
@ -314,26 +250,26 @@ createCustomWalletAddress ::
|
||||||
-> IO WalletAddress
|
-> IO WalletAddress
|
||||||
createCustomWalletAddress n i zNet scope za exSap exTr = do
|
createCustomWalletAddress n i zNet scope za exSap exTr = do
|
||||||
let oRec =
|
let oRec =
|
||||||
genOrchardReceiver i scope . getOrchSK =<<
|
genOrchardReceiver i scope $
|
||||||
zcashAccountOrchSpendKey (entityVal za)
|
getOrchSK $ zcashAccountOrchSpendKey $ entityVal za
|
||||||
let sRec =
|
let sRec =
|
||||||
if exSap
|
if exSap
|
||||||
then Nothing
|
then Nothing
|
||||||
else case scope of
|
else case scope of
|
||||||
External ->
|
External ->
|
||||||
genSaplingPaymentAddress i . getSapSK =<<
|
genSaplingPaymentAddress i $
|
||||||
zcashAccountSapSpendKey (entityVal za)
|
getSapSK $ zcashAccountSapSpendKey $ entityVal za
|
||||||
Internal ->
|
Internal ->
|
||||||
genSaplingInternalAddress . getSapSK =<<
|
genSaplingInternalAddress $
|
||||||
zcashAccountSapSpendKey (entityVal za)
|
getSapSK $ zcashAccountSapSpendKey $ entityVal za
|
||||||
tRec <-
|
tRec <-
|
||||||
if exTr
|
if exTr
|
||||||
then return Nothing
|
then return Nothing
|
||||||
else do
|
else Just <$>
|
||||||
let tKey = getTranSK <$> zcashAccountTPrivateKey (entityVal za)
|
genTransparentReceiver
|
||||||
case tKey of
|
i
|
||||||
Nothing -> return Nothing
|
scope
|
||||||
Just k -> Just <$> genTransparentReceiver i scope k
|
(getTranSK $ zcashAccountTPrivateKey $ entityVal za)
|
||||||
return $
|
return $
|
||||||
WalletAddress
|
WalletAddress
|
||||||
i
|
i
|
||||||
|
@ -343,133 +279,6 @@ createCustomWalletAddress n i zNet scope za exSap exTr = do
|
||||||
encodeUnifiedAddress $ UnifiedAddress zNet oRec sRec tRec)
|
encodeUnifiedAddress $ UnifiedAddress zNet oRec sRec tRec)
|
||||||
(ScopeDB scope)
|
(ScopeDB scope)
|
||||||
|
|
||||||
importViewingKey ::
|
|
||||||
ConnectionPool -- ^ database connection to use
|
|
||||||
-> T.Text -- ^ name to use
|
|
||||||
-> ZcashNet -- ^ the network the wallet is on
|
|
||||||
-> ValidVk -- ^ viewing key
|
|
||||||
-> Int -- ^ birthday height
|
|
||||||
-> IO (Either T.Text Int64)
|
|
||||||
importViewingKey pool name znet vk bh = do
|
|
||||||
minBh <- getMinBirthdayHeight pool $ ZcashNetDB znet
|
|
||||||
let checkNet =
|
|
||||||
case znet of
|
|
||||||
MainNet ->
|
|
||||||
case vk of
|
|
||||||
FullVk fvk -> net fvk == 1
|
|
||||||
IncomingVk ivk -> i_net ivk == 1
|
|
||||||
TestNet ->
|
|
||||||
case vk of
|
|
||||||
FullVk fvk -> net fvk == 2
|
|
||||||
IncomingVk ivk -> i_net ivk == 2
|
|
||||||
RegTestNet -> False
|
|
||||||
if checkNet
|
|
||||||
then do
|
|
||||||
when (bh < minBh) $ do
|
|
||||||
clearWalletTransactions pool
|
|
||||||
clearWalletData pool
|
|
||||||
vkWallet <- getVkWallet pool
|
|
||||||
wal <-
|
|
||||||
case vkWallet of
|
|
||||||
Nothing -> do
|
|
||||||
x <- saveVkWallet pool znet bh
|
|
||||||
case x of
|
|
||||||
Nothing -> fail "Couldn't create VK wallet"
|
|
||||||
Just w -> return w
|
|
||||||
Just w -> return w
|
|
||||||
maxIx <- getMaxAccount pool $ entityKey wal
|
|
||||||
case vk of
|
|
||||||
FullVk fvk -> do
|
|
||||||
acc <-
|
|
||||||
saveAccount pool $
|
|
||||||
ZcashAccount
|
|
||||||
(maxIx + 1)
|
|
||||||
(entityKey wal)
|
|
||||||
name
|
|
||||||
Nothing
|
|
||||||
Nothing
|
|
||||||
Nothing
|
|
||||||
(Just $ UnifiedFvkDB fvk)
|
|
||||||
Nothing
|
|
||||||
FullViewKey
|
|
||||||
case acc of
|
|
||||||
Nothing -> return $ Left "Failed to save VK account"
|
|
||||||
Just acc' -> do
|
|
||||||
defAddr <- createWalletAddress "Default" 0 znet External acc'
|
|
||||||
chgAddr <- createWalletAddress "Change" 0 znet Internal acc'
|
|
||||||
_ <- saveAddress pool defAddr
|
|
||||||
_ <- saveAddress pool chgAddr
|
|
||||||
return $ Right $ fromSqlKey (entityKey acc')
|
|
||||||
IncomingVk ivk -> do
|
|
||||||
acc1 <-
|
|
||||||
saveAccount pool $
|
|
||||||
ZcashAccount
|
|
||||||
(maxIx + 1)
|
|
||||||
(entityKey wal)
|
|
||||||
name
|
|
||||||
Nothing
|
|
||||||
Nothing
|
|
||||||
Nothing
|
|
||||||
Nothing
|
|
||||||
(Just $ UnifiedIvkDB ivk)
|
|
||||||
IncomingViewKey
|
|
||||||
case acc1 of
|
|
||||||
Nothing -> return $ Left "Failed to save VK account"
|
|
||||||
Just acc1' -> do
|
|
||||||
defAddr <- createWalletAddress "Default" 0 znet External acc1'
|
|
||||||
chgAddr <- createWalletAddress "Change" 0 znet Internal acc1'
|
|
||||||
_ <- saveAddress pool defAddr
|
|
||||||
_ <- saveAddress pool chgAddr
|
|
||||||
return $ Right $ fromSqlKey $ entityKey acc1'
|
|
||||||
else return $ Left "Viewing key is not for the current network"
|
|
||||||
|
|
||||||
parseVK :: T.Text -> Maybe ValidVk
|
|
||||||
parseVK input =
|
|
||||||
case decodeUfvk (E.encodeUtf8 input) of
|
|
||||||
Just fvk -> Just $ FullVk fvk
|
|
||||||
Nothing ->
|
|
||||||
case decodeUivk (E.encodeUtf8 input) of
|
|
||||||
Just ivk -> Just $ IncomingVk ivk
|
|
||||||
Nothing -> Nothing
|
|
||||||
|
|
||||||
importSeedPhrase ::
|
|
||||||
ConnectionPool -- ^ database connection to use
|
|
||||||
-> T.Text -- ^ name to use
|
|
||||||
-> ZcashNet -- ^ the network the wallet is on
|
|
||||||
-> Phrase -- ^ seed phrase
|
|
||||||
-> Int -- ^ birthday height
|
|
||||||
-> IO (Either T.Text Int64)
|
|
||||||
importSeedPhrase pool name znet ph bh = do
|
|
||||||
minBh <- getMinBirthdayHeight pool $ ZcashNetDB znet
|
|
||||||
when (bh < minBh) $ do
|
|
||||||
clearWalletTransactions pool
|
|
||||||
clearWalletData pool
|
|
||||||
case getWalletSeed ph of
|
|
||||||
Nothing -> return $ Left "Invalid seed phrase"
|
|
||||||
Just _ -> do
|
|
||||||
nw <-
|
|
||||||
saveWallet pool $
|
|
||||||
ZcashWallet name (ZcashNetDB znet) (PhraseDB ph) bh 0 True
|
|
||||||
case nw of
|
|
||||||
Nothing -> return $ Left "Wallet with that name already exists"
|
|
||||||
Just nw' -> do
|
|
||||||
aIx <- getMaxAccount pool (entityKey nw')
|
|
||||||
na <-
|
|
||||||
try $ createZcashAccount "Default" (aIx + 1) znet nw' :: IO
|
|
||||||
(Either IOError ZcashAccount)
|
|
||||||
case na of
|
|
||||||
Left e -> return $ Left $ T.pack $ show e
|
|
||||||
Right na' -> do
|
|
||||||
acc <- saveAccount pool na'
|
|
||||||
case acc of
|
|
||||||
Nothing -> return $ Left "Failed to save VK account"
|
|
||||||
Just acc' -> do
|
|
||||||
defAddr <- createWalletAddress "Default" 0 znet External acc'
|
|
||||||
chgAddr <- createWalletAddress "Change" 0 znet Internal acc'
|
|
||||||
_ <- saveAddress pool defAddr
|
|
||||||
_ <- saveAddress pool chgAddr
|
|
||||||
return $ Right $ fromSqlKey (entityKey acc')
|
|
||||||
|
|
||||||
-- * Wallet
|
-- * Wallet
|
||||||
-- | Find the Sapling notes that match the given spending key
|
-- | Find the Sapling notes that match the given spending key
|
||||||
findSaplingOutputs ::
|
findSaplingOutputs ::
|
||||||
|
@ -480,6 +289,8 @@ findSaplingOutputs ::
|
||||||
-> NoLoggingT IO ()
|
-> NoLoggingT IO ()
|
||||||
findSaplingOutputs config b znet za = do
|
findSaplingOutputs config b znet za = do
|
||||||
let dbPath = c_dbPath config
|
let dbPath = c_dbPath config
|
||||||
|
let zebraHost = c_zebraHost config
|
||||||
|
let zebraPort = c_zebraPort config
|
||||||
let zn = getNet znet
|
let zn = getNet znet
|
||||||
pool <- liftIO $ runNoLoggingT $ initPool dbPath
|
pool <- liftIO $ runNoLoggingT $ initPool dbPath
|
||||||
tList <- liftIO $ getShieldedOutputs pool b znet
|
tList <- liftIO $ getShieldedOutputs pool b znet
|
||||||
|
@ -489,45 +300,29 @@ findSaplingOutputs config b znet za = do
|
||||||
liftIO $ throwIO $ userError "Failed to read Sapling commitment tree"
|
liftIO $ throwIO $ userError "Failed to read Sapling commitment tree"
|
||||||
Just (sT', treeSync) -> do
|
Just (sT', treeSync) -> do
|
||||||
logDebugN "Sapling tree valid"
|
logDebugN "Sapling tree valid"
|
||||||
let acType = zcashAccountType $ entityVal za
|
mapM_ (decryptNotes sT' zn pool) tList
|
||||||
mapM_ (decryptNotes sT' zn pool acType) tList
|
|
||||||
sapNotes <- liftIO $ getWalletSapNotes pool (entityKey za)
|
sapNotes <- liftIO $ getWalletSapNotes pool (entityKey za)
|
||||||
liftIO $ findSapSpends pool (entityKey za) sapNotes
|
liftIO $ findSapSpends pool (entityKey za) sapNotes
|
||||||
where
|
where
|
||||||
sk :: Maybe SaplingSpendingKeyDB
|
sk :: SaplingSpendingKeyDB
|
||||||
sk = zcashAccountSapSpendKey $ entityVal za
|
sk = zcashAccountSapSpendKey $ entityVal za
|
||||||
fvk :: Maybe UnifiedFvkDB
|
|
||||||
fvk = zcashAccountFvk $ entityVal za
|
|
||||||
ivk :: Maybe UnifiedIvkDB
|
|
||||||
ivk = zcashAccountIvk $ entityVal za
|
|
||||||
decryptNotes ::
|
decryptNotes ::
|
||||||
Tree SaplingNode
|
Tree SaplingNode
|
||||||
-> ZcashNet
|
-> ZcashNet
|
||||||
-> ConnectionPool
|
-> ConnectionPool
|
||||||
-> AccountType
|
|
||||||
-> (Entity ZcashTransaction, Entity ShieldOutput)
|
-> (Entity ZcashTransaction, Entity ShieldOutput)
|
||||||
-> NoLoggingT IO ()
|
-> NoLoggingT IO ()
|
||||||
decryptNotes st n pool act (zt, o) = do
|
decryptNotes st n pool (zt, o) = do
|
||||||
case getNotePosition st $ fromSqlKey $ entityKey o of
|
case getNotePosition st $ fromSqlKey $ entityKey o of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
logErrorN "Couldn't find sapling note in commitment tree"
|
logErrorN "Couldn't find sapling note in commitment tree"
|
||||||
return ()
|
return ()
|
||||||
Just nP -> do
|
Just nP -> do
|
||||||
let externalDecode =
|
|
||||||
case act of
|
|
||||||
Local -> decodeShOut External n nP o
|
|
||||||
FullViewKey -> decodeShOutFvk External o $ fromIntegral nP
|
|
||||||
IncomingViewKey -> decodeShOutIvk o
|
|
||||||
let internalDecode =
|
|
||||||
case act of
|
|
||||||
Local -> decodeShOut Internal n nP o
|
|
||||||
FullViewKey -> decodeShOutFvk Internal o $ fromIntegral nP
|
|
||||||
IncomingViewKey -> Nothing
|
|
||||||
logDebugN "got position"
|
logDebugN "got position"
|
||||||
case externalDecode of
|
case decodeShOut External n nP o of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
logDebugN "couldn't decode external"
|
logDebugN "couldn't decode external"
|
||||||
case internalDecode of
|
case decodeShOut Internal n nP o of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
logDebugN "couldn't decode internal"
|
logDebugN "couldn't decode internal"
|
||||||
Just dn1 -> do
|
Just dn1 -> do
|
||||||
|
@ -554,12 +349,9 @@ findSaplingOutputs config b znet za = do
|
||||||
dn0
|
dn0
|
||||||
decodeShOut ::
|
decodeShOut ::
|
||||||
Scope -> ZcashNet -> Int32 -> Entity ShieldOutput -> Maybe DecodedNote
|
Scope -> ZcashNet -> Int32 -> Entity ShieldOutput -> Maybe DecodedNote
|
||||||
decodeShOut scope n pos s =
|
decodeShOut scope n pos s = do
|
||||||
case sk of
|
|
||||||
Nothing -> Nothing
|
|
||||||
Just sk' -> do
|
|
||||||
decodeSaplingOutputEsk
|
decodeSaplingOutputEsk
|
||||||
(getSapSK sk')
|
(getSapSK sk)
|
||||||
(ShieldedOutput
|
(ShieldedOutput
|
||||||
(getHex $ shieldOutputCv $ entityVal s)
|
(getHex $ shieldOutputCv $ entityVal s)
|
||||||
(getHex $ shieldOutputCmu $ entityVal s)
|
(getHex $ shieldOutputCmu $ entityVal s)
|
||||||
|
@ -570,36 +362,6 @@ findSaplingOutputs config b znet za = do
|
||||||
n
|
n
|
||||||
scope
|
scope
|
||||||
(fromIntegral pos)
|
(fromIntegral pos)
|
||||||
decodeShOutFvk :: Scope -> Entity ShieldOutput -> Int64 -> Maybe DecodedNote
|
|
||||||
decodeShOutFvk scope s pos =
|
|
||||||
case fvk of
|
|
||||||
Nothing -> Nothing
|
|
||||||
Just sk' -> do
|
|
||||||
decodeSaplingOutputFvk
|
|
||||||
(s_key $ getFvk sk')
|
|
||||||
(ShieldedOutput
|
|
||||||
(getHex $ shieldOutputCv $ entityVal s)
|
|
||||||
(getHex $ shieldOutputCmu $ entityVal s)
|
|
||||||
(getHex $ shieldOutputEphKey $ entityVal s)
|
|
||||||
(getHex $ shieldOutputEncCipher $ entityVal s)
|
|
||||||
(getHex $ shieldOutputOutCipher $ entityVal s)
|
|
||||||
(getHex $ shieldOutputProof $ entityVal s))
|
|
||||||
scope
|
|
||||||
pos
|
|
||||||
decodeShOutIvk :: Entity ShieldOutput -> Maybe DecodedNote
|
|
||||||
decodeShOutIvk s =
|
|
||||||
case ivk of
|
|
||||||
Nothing -> Nothing
|
|
||||||
Just sk' -> do
|
|
||||||
decodeSaplingOutputIvk
|
|
||||||
(i_s_key $ getIvk sk')
|
|
||||||
(ShieldedOutput
|
|
||||||
(getHex $ shieldOutputCv $ entityVal s)
|
|
||||||
(getHex $ shieldOutputCmu $ entityVal s)
|
|
||||||
(getHex $ shieldOutputEphKey $ entityVal s)
|
|
||||||
(getHex $ shieldOutputEncCipher $ entityVal s)
|
|
||||||
(getHex $ shieldOutputOutCipher $ entityVal s)
|
|
||||||
(getHex $ shieldOutputProof $ entityVal s))
|
|
||||||
|
|
||||||
-- | Get Orchard actions
|
-- | Get Orchard actions
|
||||||
findOrchardActions ::
|
findOrchardActions ::
|
||||||
|
@ -610,6 +372,8 @@ findOrchardActions ::
|
||||||
-> IO ()
|
-> IO ()
|
||||||
findOrchardActions config b znet za = do
|
findOrchardActions config b znet za = do
|
||||||
let dbPath = c_dbPath config
|
let dbPath = c_dbPath config
|
||||||
|
let zebraHost = c_zebraHost config
|
||||||
|
let zebraPort = c_zebraPort config
|
||||||
let zn = getNet znet
|
let zn = getNet znet
|
||||||
pool <- runNoLoggingT $ initPool dbPath
|
pool <- runNoLoggingT $ initPool dbPath
|
||||||
tList <- getOrchardActions pool b znet
|
tList <- getOrchardActions pool b znet
|
||||||
|
@ -617,33 +381,24 @@ findOrchardActions config b znet za = do
|
||||||
case sT of
|
case sT of
|
||||||
Nothing -> throwIO $ userError "Failed to read Orchard commitment tree"
|
Nothing -> throwIO $ userError "Failed to read Orchard commitment tree"
|
||||||
Just (sT', treeSync) -> do
|
Just (sT', treeSync) -> do
|
||||||
mapM_ (decryptNotes sT' pool) tList
|
mapM_ (decryptNotes sT' zn pool) tList
|
||||||
orchNotes <- getWalletOrchNotes pool (entityKey za)
|
orchNotes <- getWalletOrchNotes pool (entityKey za)
|
||||||
findOrchSpends pool (entityKey za) orchNotes
|
findOrchSpends pool (entityKey za) orchNotes
|
||||||
where
|
where
|
||||||
decryptNotes ::
|
decryptNotes ::
|
||||||
Tree OrchardNode
|
Tree OrchardNode
|
||||||
|
-> ZcashNet
|
||||||
-> ConnectionPool
|
-> ConnectionPool
|
||||||
-> (Entity ZcashTransaction, Entity OrchAction)
|
-> (Entity ZcashTransaction, Entity OrchAction)
|
||||||
-> IO ()
|
-> IO ()
|
||||||
decryptNotes ot pool (zt, o) = do
|
decryptNotes ot n pool (zt, o) = do
|
||||||
case getNotePosition ot (fromSqlKey $ entityKey o) of
|
case getNotePosition ot (fromSqlKey $ entityKey o) of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
return ()
|
return ()
|
||||||
Just nP -> do
|
Just nP ->
|
||||||
let externalDecode =
|
case decodeOrchAction External nP o of
|
||||||
case zcashAccountType (entityVal za) of
|
|
||||||
Local -> decodeOrchAction External o
|
|
||||||
FullViewKey -> decodeOrchActionFvk External o
|
|
||||||
IncomingViewKey -> decodeOrchActionIvk o
|
|
||||||
let internalDecode =
|
|
||||||
case zcashAccountType (entityVal za) of
|
|
||||||
Local -> decodeOrchAction Internal o
|
|
||||||
FullViewKey -> decodeOrchActionFvk Internal o
|
|
||||||
IncomingViewKey -> Nothing
|
|
||||||
case externalDecode of
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
case internalDecode of
|
case decodeOrchAction Internal nP o of
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
Just dn1 -> do
|
Just dn1 -> do
|
||||||
wId <- saveWalletTransaction pool (entityKey za) zt
|
wId <- saveWalletTransaction pool (entityKey za) zt
|
||||||
|
@ -665,48 +420,11 @@ findOrchardActions config b znet za = do
|
||||||
(entityKey za)
|
(entityKey za)
|
||||||
(entityKey o)
|
(entityKey o)
|
||||||
dn
|
dn
|
||||||
sk :: Maybe OrchardSpendingKeyDB
|
sk :: OrchardSpendingKeyDB
|
||||||
sk = zcashAccountOrchSpendKey $ entityVal za
|
sk = zcashAccountOrchSpendKey $ entityVal za
|
||||||
fvk :: Maybe UnifiedFvkDB
|
decodeOrchAction :: Scope -> Int32 -> Entity OrchAction -> Maybe DecodedNote
|
||||||
fvk = zcashAccountFvk $ entityVal za
|
decodeOrchAction scope pos o =
|
||||||
ivk :: Maybe UnifiedIvkDB
|
decryptOrchardActionSK (getOrchSK sk) scope $
|
||||||
ivk = zcashAccountIvk $ entityVal za
|
|
||||||
decodeOrchAction :: Scope -> Entity OrchAction -> Maybe DecodedNote
|
|
||||||
decodeOrchAction scope o =
|
|
||||||
case sk of
|
|
||||||
Nothing -> Nothing
|
|
||||||
Just sk' -> do
|
|
||||||
decryptOrchardActionSK (getOrchSK sk') scope $
|
|
||||||
OrchardAction
|
|
||||||
(getHex $ orchActionNf $ entityVal o)
|
|
||||||
(getHex $ orchActionRk $ entityVal o)
|
|
||||||
(getHex $ orchActionCmx $ entityVal o)
|
|
||||||
(getHex $ orchActionEphKey $ entityVal o)
|
|
||||||
(getHex $ orchActionEncCipher $ entityVal o)
|
|
||||||
(getHex $ orchActionOutCipher $ entityVal o)
|
|
||||||
(getHex $ orchActionCv $ entityVal o)
|
|
||||||
(getHex $ orchActionAuth $ entityVal o)
|
|
||||||
decodeOrchActionFvk :: Scope -> Entity OrchAction -> Maybe DecodedNote
|
|
||||||
decodeOrchActionFvk scope o =
|
|
||||||
case fvk of
|
|
||||||
Nothing -> Nothing
|
|
||||||
Just sk' -> do
|
|
||||||
decryptOrchardActionFvk (getFvk sk') scope $
|
|
||||||
OrchardAction
|
|
||||||
(getHex $ orchActionNf $ entityVal o)
|
|
||||||
(getHex $ orchActionRk $ entityVal o)
|
|
||||||
(getHex $ orchActionCmx $ entityVal o)
|
|
||||||
(getHex $ orchActionEphKey $ entityVal o)
|
|
||||||
(getHex $ orchActionEncCipher $ entityVal o)
|
|
||||||
(getHex $ orchActionOutCipher $ entityVal o)
|
|
||||||
(getHex $ orchActionCv $ entityVal o)
|
|
||||||
(getHex $ orchActionAuth $ entityVal o)
|
|
||||||
decodeOrchActionIvk :: Entity OrchAction -> Maybe DecodedNote
|
|
||||||
decodeOrchActionIvk o =
|
|
||||||
case ivk of
|
|
||||||
Nothing -> Nothing
|
|
||||||
Just sk' -> do
|
|
||||||
decryptOrchardActionIvk (getIvk sk') $
|
|
||||||
OrchardAction
|
OrchardAction
|
||||||
(getHex $ orchActionNf $ entityVal o)
|
(getHex $ orchActionNf $ entityVal o)
|
||||||
(getHex $ orchActionRk $ entityVal o)
|
(getHex $ orchActionRk $ entityVal o)
|
||||||
|
@ -1028,37 +746,14 @@ deshieldNotes ::
|
||||||
-> ZcashNet
|
-> ZcashNet
|
||||||
-> ZcashAccountId
|
-> ZcashAccountId
|
||||||
-> Int
|
-> Int
|
||||||
-> Scientific
|
-> ProposedNote
|
||||||
-> NoLoggingT IO (Either TxError HexString)
|
-> NoLoggingT IO (Either TxError HexString)
|
||||||
deshieldNotes pool zebraHost zebraPort znet za bh pnote = do
|
deshieldNotes pool zebraHost zebraPort znet za bh pnote = do
|
||||||
bal <- liftIO $ getShieldedBalance pool za
|
bal <- liftIO $ getShieldedBalance pool za
|
||||||
addrs <- getAddresses pool za
|
let zats = pn_amt pnote * scientific 1 8
|
||||||
let defAddr =
|
|
||||||
parseAddress $
|
|
||||||
E.encodeUtf8 $ getUA $ walletAddressUAddress $ entityVal $ head addrs
|
|
||||||
case defAddr of
|
|
||||||
Nothing -> return $ Left ZHError
|
|
||||||
Just (Unified x) -> do
|
|
||||||
case getTransparentFromUA x of
|
|
||||||
Nothing -> return $ Left ZHError
|
|
||||||
Just ta -> do
|
|
||||||
let zats = pnote * scientific 1 8
|
|
||||||
if fromInteger bal > (scientific 2 4 + zats)
|
if fromInteger bal > (scientific 2 4 + zats)
|
||||||
then prepareTxV2
|
then prepareTxV2 pool zebraHost zebraPort znet za bh [pnote] Low
|
||||||
pool
|
|
||||||
zebraHost
|
|
||||||
zebraPort
|
|
||||||
znet
|
|
||||||
za
|
|
||||||
bh
|
|
||||||
[ ProposedNote
|
|
||||||
(ValidAddressAPI $ Transparent ta)
|
|
||||||
pnote
|
|
||||||
Nothing
|
|
||||||
]
|
|
||||||
Low
|
|
||||||
else return $ Left InsufficientFunds
|
else return $ Left InsufficientFunds
|
||||||
_anyOther -> return $ Left ZHError
|
|
||||||
|
|
||||||
shieldTransparentNotes ::
|
shieldTransparentNotes ::
|
||||||
ConnectionPool
|
ConnectionPool
|
||||||
|
@ -1067,8 +762,8 @@ shieldTransparentNotes ::
|
||||||
-> ZcashNet
|
-> ZcashNet
|
||||||
-> ZcashAccountId
|
-> ZcashAccountId
|
||||||
-> Int
|
-> Int
|
||||||
-> NoLoggingT IO [Either TxError U.UUID]
|
-> NoLoggingT IO [Either TxError HexString]
|
||||||
shieldTransparentNotes pool zHost zPort znet za bh = do
|
shieldTransparentNotes pool zebraHost zebraPort znet za bh = do
|
||||||
accRead <- liftIO $ getAccountById pool za
|
accRead <- liftIO $ getAccountById pool za
|
||||||
logDebugN $ T.pack $ "Target block: " ++ show bh
|
logDebugN $ T.pack $ "Target block: " ++ show bh
|
||||||
case accRead of
|
case accRead of
|
||||||
|
@ -1077,36 +772,22 @@ shieldTransparentNotes pool zHost zPort znet za bh = do
|
||||||
return [Left ZHError]
|
return [Left ZHError]
|
||||||
Just acc -> do
|
Just acc -> do
|
||||||
trNotes' <- liftIO $ getWalletUnspentTrNotes pool za
|
trNotes' <- liftIO $ getWalletUnspentTrNotes pool za
|
||||||
if null trNotes'
|
|
||||||
then return [Left InsufficientFunds]
|
|
||||||
else do
|
|
||||||
dRecvs <- liftIO $ getReceivers pool trNotes'
|
dRecvs <- liftIO $ getReceivers pool trNotes'
|
||||||
let fNotes =
|
let fNotes =
|
||||||
map
|
map
|
||||||
(\x ->
|
(\x ->
|
||||||
filter
|
filter (\y -> walletTrNoteAddress (entityVal y) == x) trNotes')
|
||||||
(\y -> walletTrNoteAddress (entityVal y) == x)
|
|
||||||
trNotes')
|
|
||||||
dRecvs
|
dRecvs
|
||||||
sTree <- liftIO $ getSaplingTree pool
|
sTree <- liftIO $ getSaplingTree pool
|
||||||
oTree <- liftIO $ getOrchardTree pool
|
oTree <- liftIO $ getOrchardTree pool
|
||||||
forM fNotes $ \trNotes -> do
|
forM fNotes $ \trNotes -> do
|
||||||
opid <- liftIO nextRandom
|
|
||||||
startTime <- liftIO getCurrentTime
|
|
||||||
opkey <-
|
|
||||||
liftIO $
|
|
||||||
saveOperation pool $
|
|
||||||
Operation (ZenithUuid opid) startTime Nothing Processing Nothing
|
|
||||||
case opkey of
|
|
||||||
Nothing -> return $ Left ZHError
|
|
||||||
Just opkey' -> do
|
|
||||||
let noteTotal = getTotalAmount (trNotes, [], [])
|
let noteTotal = getTotalAmount (trNotes, [], [])
|
||||||
tSpends <-
|
tSpends <-
|
||||||
liftIO $
|
liftIO $
|
||||||
prepTSpends
|
prepTSpends
|
||||||
(getTranSK <$> zcashAccountTPrivateKey (entityVal acc))
|
(getTranSK $ zcashAccountTPrivateKey $ entityVal acc)
|
||||||
trNotes
|
trNotes
|
||||||
chgAddr <- liftIO $ getInternalAddresses pool $ entityKey acc
|
chgAddr <- getInternalAddresses pool $ entityKey acc
|
||||||
let internalUA =
|
let internalUA =
|
||||||
getUA $ walletAddressUAddress $ entityVal $ head chgAddr
|
getUA $ walletAddressUAddress $ entityVal $ head chgAddr
|
||||||
let oRcvr =
|
let oRcvr =
|
||||||
|
@ -1115,39 +796,25 @@ shieldTransparentNotes pool zHost zPort znet za bh = do
|
||||||
let dummy =
|
let dummy =
|
||||||
OutgoingNote
|
OutgoingNote
|
||||||
4
|
4
|
||||||
"deadbeef"
|
(getBytes $ getOrchSK $ zcashAccountOrchSpendKey $ entityVal acc)
|
||||||
(getBytes oRcvr)
|
(getBytes oRcvr)
|
||||||
(fromIntegral $ noteTotal - 500)
|
(fromIntegral $ noteTotal - 500)
|
||||||
""
|
""
|
||||||
True
|
True
|
||||||
let feeAmt = calculateTxFee (trNotes, [], []) [dummy]
|
let feeAmt = calculateTxFee (trNotes, [], []) [dummy]
|
||||||
let osk' =
|
|
||||||
getOrchSK <$> zcashAccountOrchSpendKey (entityVal acc)
|
|
||||||
case osk' of
|
|
||||||
Nothing -> return $ Left ZHError
|
|
||||||
Just osk -> do
|
|
||||||
let snote =
|
let snote =
|
||||||
OutgoingNote
|
OutgoingNote
|
||||||
4
|
4
|
||||||
(getBytes osk)
|
(getBytes $ getOrchSK $ zcashAccountOrchSpendKey $ entityVal acc)
|
||||||
(getBytes oRcvr)
|
(getBytes oRcvr)
|
||||||
(fromIntegral $ noteTotal - fromIntegral feeAmt)
|
(fromIntegral $ noteTotal - fromIntegral feeAmt)
|
||||||
""
|
""
|
||||||
True
|
True
|
||||||
_ <-
|
|
||||||
liftIO $
|
|
||||||
forkIO $ do
|
|
||||||
tx <-
|
tx <-
|
||||||
liftIO $
|
liftIO $
|
||||||
createTransaction
|
createTransaction
|
||||||
(maybe
|
(maybe (hexString "00") (getHash . value . fst) sTree)
|
||||||
(hexString "00")
|
(maybe (hexString "00") (getHash . value . fst) oTree)
|
||||||
(getHash . value . fst)
|
|
||||||
sTree)
|
|
||||||
(maybe
|
|
||||||
(hexString "00")
|
|
||||||
(getHash . value . fst)
|
|
||||||
oTree)
|
|
||||||
tSpends
|
tSpends
|
||||||
[]
|
[]
|
||||||
[]
|
[]
|
||||||
|
@ -1155,26 +822,8 @@ shieldTransparentNotes pool zHost zPort znet za bh = do
|
||||||
znet
|
znet
|
||||||
(bh + 3)
|
(bh + 3)
|
||||||
True
|
True
|
||||||
case tx of
|
logDebugN $ T.pack $ show tx
|
||||||
Left e ->
|
return tx
|
||||||
finalizeOperation pool opkey' Failed $
|
|
||||||
T.pack $ show e
|
|
||||||
Right rawTx -> do
|
|
||||||
zebraRes <-
|
|
||||||
makeZebraCall
|
|
||||||
zHost
|
|
||||||
zPort
|
|
||||||
"sendrawtransaction"
|
|
||||||
[Data.Aeson.String $ toText rawTx]
|
|
||||||
case zebraRes of
|
|
||||||
Left e1 ->
|
|
||||||
finalizeOperation pool opkey' Failed $
|
|
||||||
T.pack $ show e1
|
|
||||||
Right txId ->
|
|
||||||
finalizeOperation pool opkey' Successful $
|
|
||||||
"Tx ID: " <> toText txId
|
|
||||||
logDebugN $ T.pack $ show opid
|
|
||||||
return $ Right opid
|
|
||||||
where
|
where
|
||||||
getTotalAmount ::
|
getTotalAmount ::
|
||||||
( [Entity WalletTrNote]
|
( [Entity WalletTrNote]
|
||||||
|
@ -1186,13 +835,10 @@ shieldTransparentNotes pool zHost zPort znet za bh = do
|
||||||
sum (map (fromIntegral . walletSapNoteValue . entityVal) s) +
|
sum (map (fromIntegral . walletSapNoteValue . entityVal) s) +
|
||||||
sum (map (fromIntegral . walletOrchNoteValue . entityVal) o)
|
sum (map (fromIntegral . walletOrchNoteValue . entityVal) o)
|
||||||
prepTSpends ::
|
prepTSpends ::
|
||||||
Maybe TransparentSpendingKey
|
TransparentSpendingKey
|
||||||
-> [Entity WalletTrNote]
|
-> [Entity WalletTrNote]
|
||||||
-> IO [TransparentTxSpend]
|
-> IO [TransparentTxSpend]
|
||||||
prepTSpends sk' notes = do
|
prepTSpends sk notes = do
|
||||||
case sk' of
|
|
||||||
Nothing -> return []
|
|
||||||
Just sk -> do
|
|
||||||
forM notes $ \n -> do
|
forM notes $ \n -> do
|
||||||
tAddRead <- getAddressById pool $ walletTrNoteAddress $ entityVal n
|
tAddRead <- getAddressById pool $ walletTrNoteAddress $ entityVal n
|
||||||
case tAddRead of
|
case tAddRead of
|
||||||
|
@ -1203,8 +849,7 @@ shieldTransparentNotes pool zHost zPort znet za bh = do
|
||||||
(walletAddressIndex $ entityVal tAdd)
|
(walletAddressIndex $ entityVal tAdd)
|
||||||
(getScope $ walletAddressScope $ entityVal tAdd)
|
(getScope $ walletAddressScope $ entityVal tAdd)
|
||||||
sk
|
sk
|
||||||
mReverseTxId <-
|
mReverseTxId <- getWalletTxId pool $ walletTrNoteTx $ entityVal n
|
||||||
getWalletTxId pool $ walletTrNoteTx $ entityVal n
|
|
||||||
case mReverseTxId of
|
case mReverseTxId of
|
||||||
Nothing -> throwIO $ userError "failed to get tx ID"
|
Nothing -> throwIO $ userError "failed to get tx ID"
|
||||||
Just (ESQ.Value reverseTxId) -> do
|
Just (ESQ.Value reverseTxId) -> do
|
||||||
|
@ -1280,8 +925,7 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
policy
|
policy
|
||||||
case draft of
|
case draft of
|
||||||
Left e -> return $ Left e
|
Left e -> return $ Left e
|
||||||
Right draftOut' -> do
|
Right draftOut -> do
|
||||||
let draftOut = catMaybes draftOut'
|
|
||||||
let fee = calculateTxFee (tList, sList, oList) draftOut
|
let fee = calculateTxFee (tList, sList, oList) draftOut
|
||||||
logDebugN $ T.pack $ "calculated fee " ++ show fee
|
logDebugN $ T.pack $ "calculated fee " ++ show fee
|
||||||
finalNotePlan <-
|
finalNotePlan <-
|
||||||
|
@ -1301,19 +945,18 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
tSpends1 <-
|
tSpends1 <-
|
||||||
liftIO $
|
liftIO $
|
||||||
prepTSpends
|
prepTSpends
|
||||||
(getTranSK <$> zcashAccountTPrivateKey (entityVal acc))
|
(getTranSK $ zcashAccountTPrivateKey $ entityVal acc)
|
||||||
tList1
|
tList1
|
||||||
sSpends1 <-
|
sSpends1 <-
|
||||||
liftIO $
|
liftIO $
|
||||||
prepSSpends
|
prepSSpends
|
||||||
(getSapSK <$> zcashAccountSapSpendKey (entityVal acc))
|
(getSapSK $ zcashAccountSapSpendKey $ entityVal acc)
|
||||||
(maybe InvalidTree fst sTree)
|
(maybe InvalidTree fst sTree)
|
||||||
sList1
|
sList1
|
||||||
oSpends1 <-
|
oSpends1 <-
|
||||||
liftIO $
|
liftIO $
|
||||||
prepOSpends
|
prepOSpends
|
||||||
(getOrchSK <$>
|
(getOrchSK $ zcashAccountOrchSpendKey $ entityVal acc)
|
||||||
zcashAccountOrchSpendKey (entityVal acc))
|
|
||||||
(maybe InvalidTree fst oTree)
|
(maybe InvalidTree fst oTree)
|
||||||
oList1
|
oList1
|
||||||
let noteTotal1 = getTotalAmount (tList1, sList1, oList1)
|
let noteTotal1 = getTotalAmount (tList1, sList1, oList1)
|
||||||
|
@ -1327,8 +970,7 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
logDebugN $ T.pack $ show outgoing'
|
logDebugN $ T.pack $ show outgoing'
|
||||||
case outgoing' of
|
case outgoing' of
|
||||||
Left e -> return $ Left e
|
Left e -> return $ Left e
|
||||||
Right outgoing'' -> do
|
Right outgoing -> do
|
||||||
let outgoing = catMaybes outgoing''
|
|
||||||
tx <-
|
tx <-
|
||||||
liftIO $
|
liftIO $
|
||||||
createTransaction
|
createTransaction
|
||||||
|
@ -1409,14 +1051,8 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
, zats
|
, zats
|
||||||
, fromMaybe "" m)
|
, fromMaybe "" m)
|
||||||
prepareOutgoingNote ::
|
prepareOutgoingNote ::
|
||||||
ZcashAccount
|
ZcashAccount -> (Int, BS.ByteString, Int64, T.Text) -> OutgoingNote
|
||||||
-> (Int, BS.ByteString, Int64, T.Text)
|
prepareOutgoingNote zac (k, r, a, m) =
|
||||||
-> Maybe OutgoingNote
|
|
||||||
prepareOutgoingNote zac (k, r, a, m)
|
|
||||||
| k == 4 && isNothing (zcashAccountOrchSpendKey zac) = Nothing
|
|
||||||
| k == 3 && isNothing (zcashAccountSapSpendKey zac) = Nothing
|
|
||||||
| otherwise =
|
|
||||||
Just $
|
|
||||||
OutgoingNote
|
OutgoingNote
|
||||||
(if k == 5
|
(if k == 5
|
||||||
then 1
|
then 1
|
||||||
|
@ -1424,8 +1060,8 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
then 2
|
then 2
|
||||||
else fromIntegral k)
|
else fromIntegral k)
|
||||||
(case k of
|
(case k of
|
||||||
4 -> getBytes $ getOrchSK $ fromJust $ zcashAccountOrchSpendKey zac
|
4 -> getBytes $ getOrchSK $ zcashAccountOrchSpendKey zac
|
||||||
3 -> getBytes $ getSapSK $ fromJust $ zcashAccountSapSpendKey zac
|
3 -> getBytes $ getSapSK $ zcashAccountSapSpendKey zac
|
||||||
_anyOther -> BS.empty)
|
_anyOther -> BS.empty)
|
||||||
r
|
r
|
||||||
(fromIntegral a)
|
(fromIntegral a)
|
||||||
|
@ -1436,11 +1072,11 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
-> [(Int, BS.ByteString, Int64, T.Text)]
|
-> [(Int, BS.ByteString, Int64, T.Text)]
|
||||||
-> Int64
|
-> Int64
|
||||||
-> PrivacyPolicy
|
-> PrivacyPolicy
|
||||||
-> IO (Either TxError [Maybe OutgoingNote])
|
-> IO (Either TxError [OutgoingNote])
|
||||||
makeOutgoing acc recvs chg pol = do
|
makeOutgoing acc recvs chg pol = do
|
||||||
let k = map (\(x, _, _, _) -> x) recvs
|
let k = map (\(x, _, _, _) -> x) recvs
|
||||||
let j = map (\(_, _, x, _) -> x) recvs
|
let j = map (\(_, _, x, _) -> x) recvs
|
||||||
chgAddr <- getInternalAddresses pool $ entityKey acc
|
chgAddr <- runNoLoggingT $ getInternalAddresses pool $ entityKey acc
|
||||||
let internalUA = getUA $ walletAddressUAddress $ entityVal $ head chgAddr
|
let internalUA = getUA $ walletAddressUAddress $ entityVal $ head chgAddr
|
||||||
case pol of
|
case pol of
|
||||||
Full ->
|
Full ->
|
||||||
|
@ -1454,8 +1090,7 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
Left $
|
Left $
|
||||||
PrivacyPolicyError
|
PrivacyPolicyError
|
||||||
"Multiple shielded pools not allowed for Full privacy"
|
"Multiple shielded pools not allowed for Full privacy"
|
||||||
else if 3 `elem` k &&
|
else if 3 `elem` k
|
||||||
isJust (zcashAccountSapSpendKey $ entityVal acc)
|
|
||||||
then do
|
then do
|
||||||
let chgRcvr =
|
let chgRcvr =
|
||||||
fromJust $
|
fromJust $
|
||||||
|
@ -1463,12 +1098,10 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
isValidUnifiedAddress
|
isValidUnifiedAddress
|
||||||
(E.encodeUtf8 internalUA)
|
(E.encodeUtf8 internalUA)
|
||||||
let cnote =
|
let cnote =
|
||||||
Just $
|
|
||||||
OutgoingNote
|
OutgoingNote
|
||||||
3
|
3
|
||||||
(getBytes $
|
(getBytes $
|
||||||
getSapSK $
|
getSapSK $
|
||||||
fromJust $
|
|
||||||
zcashAccountSapSpendKey $ entityVal acc)
|
zcashAccountSapSpendKey $ entityVal acc)
|
||||||
(getBytes chgRcvr)
|
(getBytes chgRcvr)
|
||||||
(fromIntegral chg)
|
(fromIntegral chg)
|
||||||
|
@ -1479,9 +1112,7 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
(prepareOutgoingNote (entityVal acc))
|
(prepareOutgoingNote (entityVal acc))
|
||||||
recvs
|
recvs
|
||||||
return $ Right $ cnote : onotes
|
return $ Right $ cnote : onotes
|
||||||
else if 4 `elem` k &&
|
else if 4 `elem` k
|
||||||
isJust
|
|
||||||
(zcashAccountOrchSpendKey $ entityVal acc)
|
|
||||||
then do
|
then do
|
||||||
let chgRcvr =
|
let chgRcvr =
|
||||||
fromJust $
|
fromJust $
|
||||||
|
@ -1489,12 +1120,10 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
isValidUnifiedAddress
|
isValidUnifiedAddress
|
||||||
(E.encodeUtf8 internalUA)
|
(E.encodeUtf8 internalUA)
|
||||||
let cnote =
|
let cnote =
|
||||||
Just $
|
|
||||||
OutgoingNote
|
OutgoingNote
|
||||||
4
|
4
|
||||||
(getBytes $
|
(getBytes $
|
||||||
getOrchSK $
|
getOrchSK $
|
||||||
fromJust $
|
|
||||||
zcashAccountOrchSpendKey $
|
zcashAccountOrchSpendKey $
|
||||||
entityVal acc)
|
entityVal acc)
|
||||||
(getBytes chgRcvr)
|
(getBytes chgRcvr)
|
||||||
|
@ -1518,12 +1147,10 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
fromJust $
|
fromJust $
|
||||||
o_rec =<< isValidUnifiedAddress (E.encodeUtf8 internalUA)
|
o_rec =<< isValidUnifiedAddress (E.encodeUtf8 internalUA)
|
||||||
let cnote =
|
let cnote =
|
||||||
Just $
|
|
||||||
OutgoingNote
|
OutgoingNote
|
||||||
4
|
4
|
||||||
(getBytes $
|
(getBytes $
|
||||||
getOrchSK $
|
getOrchSK $ zcashAccountOrchSpendKey $ entityVal acc)
|
||||||
fromJust $ zcashAccountOrchSpendKey $ entityVal acc)
|
|
||||||
(getBytes chgRcvr)
|
(getBytes chgRcvr)
|
||||||
(fromIntegral chg)
|
(fromIntegral chg)
|
||||||
""
|
""
|
||||||
|
@ -1541,12 +1168,10 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
fromJust $
|
fromJust $
|
||||||
o_rec =<< isValidUnifiedAddress (E.encodeUtf8 internalUA)
|
o_rec =<< isValidUnifiedAddress (E.encodeUtf8 internalUA)
|
||||||
let cnote =
|
let cnote =
|
||||||
Just $
|
|
||||||
OutgoingNote
|
OutgoingNote
|
||||||
4
|
4
|
||||||
(getBytes $
|
(getBytes $
|
||||||
getOrchSK $
|
getOrchSK $ zcashAccountOrchSpendKey $ entityVal acc)
|
||||||
fromJust $ zcashAccountOrchSpendKey $ entityVal acc)
|
|
||||||
(getBytes chgRcvr)
|
(getBytes chgRcvr)
|
||||||
(fromIntegral chg)
|
(fromIntegral chg)
|
||||||
""
|
""
|
||||||
|
@ -1564,7 +1189,6 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
fromJust $
|
fromJust $
|
||||||
t_rec =<< isValidUnifiedAddress (E.encodeUtf8 internalUA)
|
t_rec =<< isValidUnifiedAddress (E.encodeUtf8 internalUA)
|
||||||
let cnote =
|
let cnote =
|
||||||
Just $
|
|
||||||
OutgoingNote
|
OutgoingNote
|
||||||
1
|
1
|
||||||
BS.empty
|
BS.empty
|
||||||
|
@ -1584,13 +1208,10 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
sum (map (fromIntegral . walletSapNoteValue . entityVal) s) +
|
sum (map (fromIntegral . walletSapNoteValue . entityVal) s) +
|
||||||
sum (map (fromIntegral . walletOrchNoteValue . entityVal) o)
|
sum (map (fromIntegral . walletOrchNoteValue . entityVal) o)
|
||||||
prepTSpends ::
|
prepTSpends ::
|
||||||
Maybe TransparentSpendingKey
|
TransparentSpendingKey
|
||||||
-> [Entity WalletTrNote]
|
-> [Entity WalletTrNote]
|
||||||
-> IO [TransparentTxSpend]
|
-> IO [TransparentTxSpend]
|
||||||
prepTSpends sk' notes = do
|
prepTSpends sk notes = do
|
||||||
case sk' of
|
|
||||||
Nothing -> return []
|
|
||||||
Just sk -> do
|
|
||||||
forM notes $ \n -> do
|
forM notes $ \n -> do
|
||||||
tAddRead <- getAddressById pool $ walletTrNoteAddress $ entityVal n
|
tAddRead <- getAddressById pool $ walletTrNoteAddress $ entityVal n
|
||||||
case tAddRead of
|
case tAddRead of
|
||||||
|
@ -1601,8 +1222,7 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
(walletAddressIndex $ entityVal tAdd)
|
(walletAddressIndex $ entityVal tAdd)
|
||||||
(getScope $ walletAddressScope $ entityVal tAdd)
|
(getScope $ walletAddressScope $ entityVal tAdd)
|
||||||
sk
|
sk
|
||||||
mReverseTxId <-
|
mReverseTxId <- getWalletTxId pool $ walletTrNoteTx $ entityVal n
|
||||||
getWalletTxId pool $ walletTrNoteTx $ entityVal n
|
|
||||||
case mReverseTxId of
|
case mReverseTxId of
|
||||||
Nothing -> throwIO $ userError "failed to get tx ID"
|
Nothing -> throwIO $ userError "failed to get tx ID"
|
||||||
Just (ESQ.Value reverseTxId) -> do
|
Just (ESQ.Value reverseTxId) -> do
|
||||||
|
@ -1617,14 +1237,11 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
(fromIntegral $ walletTrNoteValue $ entityVal n)
|
(fromIntegral $ walletTrNoteValue $ entityVal n)
|
||||||
(walletTrNoteScript $ entityVal n))
|
(walletTrNoteScript $ entityVal n))
|
||||||
prepSSpends ::
|
prepSSpends ::
|
||||||
Maybe SaplingSpendingKey
|
SaplingSpendingKey
|
||||||
-> Tree SaplingNode
|
-> Tree SaplingNode
|
||||||
-> [Entity WalletSapNote]
|
-> [Entity WalletSapNote]
|
||||||
-> IO [SaplingTxSpend]
|
-> IO [SaplingTxSpend]
|
||||||
prepSSpends sk' tree notes = do
|
prepSSpends sk tree notes = do
|
||||||
case sk' of
|
|
||||||
Nothing -> return []
|
|
||||||
Just sk -> do
|
|
||||||
forM notes $ \n -> do
|
forM notes $ \n -> do
|
||||||
let notePath =
|
let notePath =
|
||||||
Zenith.Tree.path
|
Zenith.Tree.path
|
||||||
|
@ -1642,14 +1259,11 @@ prepareTxV2 pool zebraHost zebraPort zn za bh pnotes policy = do
|
||||||
(getRseed $ walletSapNoteRseed $ entityVal n))
|
(getRseed $ walletSapNoteRseed $ entityVal n))
|
||||||
(fromMaybe nullPath notePath)
|
(fromMaybe nullPath notePath)
|
||||||
prepOSpends ::
|
prepOSpends ::
|
||||||
Maybe OrchardSpendingKey
|
OrchardSpendingKey
|
||||||
-> Tree OrchardNode
|
-> Tree OrchardNode
|
||||||
-> [Entity WalletOrchNote]
|
-> [Entity WalletOrchNote]
|
||||||
-> IO [OrchardTxSpend]
|
-> IO [OrchardTxSpend]
|
||||||
prepOSpends sk' tree notes = do
|
prepOSpends sk tree notes = do
|
||||||
case sk' of
|
|
||||||
Nothing -> return []
|
|
||||||
Just sk -> do
|
|
||||||
forM notes $ \n -> do
|
forM notes $ \n -> do
|
||||||
let notePath =
|
let notePath =
|
||||||
Zenith.Tree.path
|
Zenith.Tree.path
|
||||||
|
@ -1684,7 +1298,8 @@ syncWallet config w = do
|
||||||
mapM (liftIO . runNoLoggingT . getAddresses pool . entityKey) accs
|
mapM (liftIO . runNoLoggingT . getAddresses pool . entityKey) accs
|
||||||
logDebugN $ "addrs: " <> T.pack (show addrs)
|
logDebugN $ "addrs: " <> T.pack (show addrs)
|
||||||
intAddrs <-
|
intAddrs <-
|
||||||
concat <$> mapM (liftIO . getInternalAddresses pool . entityKey) accs
|
concat <$>
|
||||||
|
mapM (liftIO . runNoLoggingT . getInternalAddresses pool . entityKey) accs
|
||||||
chainTip <- liftIO $ getMaxBlock pool znet
|
chainTip <- liftIO $ getMaxBlock pool znet
|
||||||
logDebugN $ "chain tip: " <> T.pack (show chainTip)
|
logDebugN $ "chain tip: " <> T.pack (show chainTip)
|
||||||
lastBlock <- liftIO $ getLastSyncBlock pool $ entityKey w
|
lastBlock <- liftIO $ getLastSyncBlock pool $ entityKey w
|
||||||
|
|
249
src/Zenith/DB.hs
249
src/Zenith/DB.hs
|
@ -20,14 +20,13 @@ module Zenith.DB where
|
||||||
|
|
||||||
import Codec.Borsh
|
import Codec.Borsh
|
||||||
import Control.Exception (SomeException(..), throw, throwIO, try)
|
import Control.Exception (SomeException(..), throw, throwIO, try)
|
||||||
import Control.Monad (forM_, unless, when)
|
import Control.Monad (unless, when)
|
||||||
import Control.Monad.IO.Class (MonadIO, liftIO)
|
import Control.Monad.IO.Class (MonadIO, liftIO)
|
||||||
import Control.Monad.Logger
|
import Control.Monad.Logger
|
||||||
( LoggingT
|
( LoggingT
|
||||||
, NoLoggingT
|
, NoLoggingT
|
||||||
, logDebugN
|
, logDebugN
|
||||||
, logErrorN
|
, logErrorN
|
||||||
, logInfoN
|
|
||||||
, runNoLoggingT
|
, runNoLoggingT
|
||||||
, runStderrLoggingT
|
, runStderrLoggingT
|
||||||
)
|
)
|
||||||
|
@ -53,7 +52,6 @@ import Haskoin.Transaction.Common
|
||||||
)
|
)
|
||||||
import System.Directory (doesFileExist, getHomeDirectory, removeFile)
|
import System.Directory (doesFileExist, getHomeDirectory, removeFile)
|
||||||
import System.FilePath ((</>))
|
import System.FilePath ((</>))
|
||||||
import ZcashHaskell.Keys (deriveUfvk, deriveUivk)
|
|
||||||
import ZcashHaskell.Orchard
|
import ZcashHaskell.Orchard
|
||||||
( compareAddress
|
( compareAddress
|
||||||
, getSaplingFromUA
|
, getSaplingFromUA
|
||||||
|
@ -67,7 +65,6 @@ import ZcashHaskell.Types
|
||||||
, OrchardBundle(..)
|
, OrchardBundle(..)
|
||||||
, OrchardReceiver(..)
|
, OrchardReceiver(..)
|
||||||
, OrchardWitness(..)
|
, OrchardWitness(..)
|
||||||
, Phrase(..)
|
|
||||||
, SaplingAddress(..)
|
, SaplingAddress(..)
|
||||||
, SaplingBundle(..)
|
, SaplingBundle(..)
|
||||||
, SaplingReceiver(..)
|
, SaplingReceiver(..)
|
||||||
|
@ -83,13 +80,11 @@ import ZcashHaskell.Types
|
||||||
, TxError(..)
|
, TxError(..)
|
||||||
, UnifiedAddress(..)
|
, UnifiedAddress(..)
|
||||||
, ValidAddress(..)
|
, ValidAddress(..)
|
||||||
, ValidVk(..)
|
|
||||||
, ZcashNet(..)
|
, ZcashNet(..)
|
||||||
)
|
)
|
||||||
import Zenith.Tree (OrchardNode(..), SaplingNode(..), Tree(..), truncateTree)
|
import Zenith.Tree (OrchardNode(..), SaplingNode(..), Tree(..), truncateTree)
|
||||||
import Zenith.Types
|
import Zenith.Types
|
||||||
( AccountBalance(..)
|
( AccountBalance(..)
|
||||||
, AccountType(..)
|
|
||||||
, HexStringDB(..)
|
, HexStringDB(..)
|
||||||
, OrchardSpendingKeyDB(..)
|
, OrchardSpendingKeyDB(..)
|
||||||
, PhraseDB(..)
|
, PhraseDB(..)
|
||||||
|
@ -97,10 +92,8 @@ import Zenith.Types
|
||||||
, RseedDB(..)
|
, RseedDB(..)
|
||||||
, SaplingSpendingKeyDB(..)
|
, SaplingSpendingKeyDB(..)
|
||||||
, ScopeDB(..)
|
, ScopeDB(..)
|
||||||
, TransparentSpendingKeyDB(..)
|
, TransparentSpendingKeyDB
|
||||||
, UnifiedAddressDB(..)
|
, UnifiedAddressDB(..)
|
||||||
, UnifiedFvkDB(..)
|
|
||||||
, UnifiedIvkDB(..)
|
|
||||||
, ZcashAccountAPI(..)
|
, ZcashAccountAPI(..)
|
||||||
, ZcashAddressAPI(..)
|
, ZcashAddressAPI(..)
|
||||||
, ZcashNetDB(..)
|
, ZcashNetDB(..)
|
||||||
|
@ -111,16 +104,6 @@ import Zenith.Types
|
||||||
, ZenithUuid(..)
|
, ZenithUuid(..)
|
||||||
)
|
)
|
||||||
|
|
||||||
share
|
|
||||||
[mkPersist sqlSettings, mkMigrate "schemaMigration"]
|
|
||||||
[persistLowerCase|
|
|
||||||
ZenithSchema
|
|
||||||
version Int
|
|
||||||
action T.Text
|
|
||||||
UniqueAction version action
|
|
||||||
deriving Show Eq
|
|
||||||
|]
|
|
||||||
|
|
||||||
share
|
share
|
||||||
[mkPersist sqlSettings, mkMigrate "migrateAll"]
|
[mkPersist sqlSettings, mkMigrate "migrateAll"]
|
||||||
[persistLowerCase|
|
[persistLowerCase|
|
||||||
|
@ -130,19 +113,15 @@ share
|
||||||
seedPhrase PhraseDB
|
seedPhrase PhraseDB
|
||||||
birthdayHeight Int
|
birthdayHeight Int
|
||||||
lastSync Int default=0
|
lastSync Int default=0
|
||||||
local Bool default=TRUE
|
|
||||||
UniqueWallet name network
|
UniqueWallet name network
|
||||||
deriving Show Eq
|
deriving Show Eq
|
||||||
ZcashAccount
|
ZcashAccount
|
||||||
index Int
|
index Int
|
||||||
walletId ZcashWalletId
|
walletId ZcashWalletId
|
||||||
name T.Text
|
name T.Text
|
||||||
orchSpendKey OrchardSpendingKeyDB Maybe default=NULL
|
orchSpendKey OrchardSpendingKeyDB
|
||||||
sapSpendKey SaplingSpendingKeyDB Maybe default=NULL
|
sapSpendKey SaplingSpendingKeyDB
|
||||||
tPrivateKey TransparentSpendingKeyDB Maybe default=NULL
|
tPrivateKey TransparentSpendingKeyDB
|
||||||
fvk UnifiedFvkDB Maybe default=NULL
|
|
||||||
ivk UnifiedIvkDB Maybe default=NULL
|
|
||||||
type AccountType default='Local'
|
|
||||||
UniqueAccount index walletId
|
UniqueAccount index walletId
|
||||||
UniqueAccName walletId name
|
UniqueAccName walletId name
|
||||||
deriving Show Eq
|
deriving Show Eq
|
||||||
|
@ -346,7 +325,6 @@ toZcashWalletAPI w =
|
||||||
(getNet $ zcashWalletNetwork $ entityVal w)
|
(getNet $ zcashWalletNetwork $ entityVal w)
|
||||||
(zcashWalletBirthdayHeight $ entityVal w)
|
(zcashWalletBirthdayHeight $ entityVal w)
|
||||||
(zcashWalletLastSync $ entityVal w)
|
(zcashWalletLastSync $ entityVal w)
|
||||||
(zcashWalletLocal $ entityVal w)
|
|
||||||
|
|
||||||
-- | @ZcashAccount@
|
-- | @ZcashAccount@
|
||||||
toZcashAccountAPI :: Entity ZcashAccount -> ZcashAccountAPI
|
toZcashAccountAPI :: Entity ZcashAccount -> ZcashAccountAPI
|
||||||
|
@ -355,7 +333,6 @@ toZcashAccountAPI a =
|
||||||
(fromIntegral $ fromSqlKey $ entityKey a)
|
(fromIntegral $ fromSqlKey $ entityKey a)
|
||||||
(fromIntegral $ fromSqlKey $ zcashAccountWalletId $ entityVal a)
|
(fromIntegral $ fromSqlKey $ zcashAccountWalletId $ entityVal a)
|
||||||
(zcashAccountName $ entityVal a)
|
(zcashAccountName $ entityVal a)
|
||||||
(zcashAccountType $ entityVal a)
|
|
||||||
|
|
||||||
-- | @WalletAddress@
|
-- | @WalletAddress@
|
||||||
toZcashAddressAPI :: Entity WalletAddress -> ZcashAddressAPI
|
toZcashAddressAPI :: Entity WalletAddress -> ZcashAddressAPI
|
||||||
|
@ -448,45 +425,14 @@ orchToZcashNoteAPI pool n = do
|
||||||
-- | Initializes the database
|
-- | Initializes the database
|
||||||
initDb ::
|
initDb ::
|
||||||
T.Text -- ^ The database path to check
|
T.Text -- ^ The database path to check
|
||||||
-> NoLoggingT IO (Either String Bool)
|
-> IO (Either String Bool)
|
||||||
initDb dbName = do
|
initDb dbName = do
|
||||||
x <-
|
|
||||||
liftIO
|
|
||||||
(try $ PS.runSqlite dbName $ runMigrationUnsafeQuiet schemaMigration :: IO
|
|
||||||
(Either SomeException [T.Text]))
|
|
||||||
case x of
|
|
||||||
Left _ -> do
|
|
||||||
logErrorN "Failed to initiate schema table"
|
|
||||||
return $ Left "Failed to initiate schema table"
|
|
||||||
Right _ -> do
|
|
||||||
pool <- liftIO $ runNoLoggingT $ initPool dbName
|
|
||||||
j <-
|
j <-
|
||||||
liftIO
|
try $ PS.runSqlite dbName $ runMigrationQuiet migrateAll :: IO
|
||||||
(try $ PS.runSqlite dbName $ runMigrationQuiet migrateAll :: IO
|
(Either SomeException [T.Text])
|
||||||
(Either SomeException [T.Text]))
|
|
||||||
case j of
|
case j of
|
||||||
Left e1 -> do
|
Left _e1 -> do
|
||||||
logDebugN "Automatic migration failed, starting manual"
|
pool <- runNoLoggingT $ initPool dbName
|
||||||
versions <- liftIO $ getVersions pool
|
|
||||||
migrateTables pool versions
|
|
||||||
PS.runSqlite dbName $ printMigration migrateAll
|
|
||||||
m <-
|
|
||||||
liftIO
|
|
||||||
(try $ PS.runSqlite dbName $ runMigration migrateAll :: IO
|
|
||||||
(Either SomeException ()))
|
|
||||||
case m of
|
|
||||||
Left e2 -> do
|
|
||||||
logErrorN $ "Failed to migrate data tables " <> T.pack (show e2)
|
|
||||||
return $ Left $ "Failed to migrate data tables" ++ show e2
|
|
||||||
Right _ -> do
|
|
||||||
logInfoN "Migration of tables successful"
|
|
||||||
return $ Right False
|
|
||||||
Right _ -> do
|
|
||||||
_ <-
|
|
||||||
runNoLoggingT $
|
|
||||||
PS.retryOnBusy $
|
|
||||||
flip PS.runSqlPool pool $ do
|
|
||||||
upsert (ZenithSchema 1 "Viewing Keys") []
|
|
||||||
wallets <-
|
wallets <-
|
||||||
runNoLoggingT $
|
runNoLoggingT $
|
||||||
PS.retryOnBusy $
|
PS.retryOnBusy $
|
||||||
|
@ -495,20 +441,16 @@ initDb dbName = do
|
||||||
runNoLoggingT $
|
runNoLoggingT $
|
||||||
PS.retryOnBusy $
|
PS.retryOnBusy $
|
||||||
flip PS.runSqlPool pool $ do select . from $ table @ZcashAccount
|
flip PS.runSqlPool pool $ do select . from $ table @ZcashAccount
|
||||||
addresses <-
|
|
||||||
runNoLoggingT $
|
|
||||||
PS.retryOnBusy $
|
|
||||||
flip PS.runSqlPool pool $ do select . from $ table @WalletAddress
|
|
||||||
abook <-
|
abook <-
|
||||||
runNoLoggingT $
|
runNoLoggingT $
|
||||||
PS.retryOnBusy $
|
PS.retryOnBusy $
|
||||||
flip PS.runSqlPool pool $ do select . from $ table @AddressBook
|
flip PS.runSqlPool pool $ do select . from $ table @AddressBook
|
||||||
hDir <- liftIO getHomeDirectory
|
hDir <- getHomeDirectory
|
||||||
let backupDb = hDir </> "Zenith/.backup.db"
|
let backupDb = hDir </> "Zenith/.backup.db"
|
||||||
checkDbFile <- liftIO $ doesFileExist backupDb
|
checkDbFile <- doesFileExist backupDb
|
||||||
when checkDbFile $ liftIO $ removeFile backupDb
|
when checkDbFile $ removeFile backupDb
|
||||||
_ <- PS.runSqlite (T.pack backupDb) $ runMigrationQuiet migrateAll
|
_ <- PS.runSqlite (T.pack backupDb) $ runMigrationQuiet migrateAll
|
||||||
backupPool <- liftIO $ runNoLoggingT $ initPool $ T.pack backupDb
|
backupPool <- runNoLoggingT $ initPool $ T.pack backupDb
|
||||||
_ <-
|
_ <-
|
||||||
runNoLoggingT $
|
runNoLoggingT $
|
||||||
PS.retryOnBusy $
|
PS.retryOnBusy $
|
||||||
|
@ -521,86 +463,23 @@ initDb dbName = do
|
||||||
runNoLoggingT $
|
runNoLoggingT $
|
||||||
PS.retryOnBusy $
|
PS.retryOnBusy $
|
||||||
flip PS.runSqlPool backupPool $ insertMany_ $ entityVal <$> abook
|
flip PS.runSqlPool backupPool $ insertMany_ $ entityVal <$> abook
|
||||||
_ <-
|
clearWalletTransactions pool
|
||||||
runNoLoggingT $
|
clearWalletData pool
|
||||||
PS.retryOnBusy $
|
m <-
|
||||||
flip PS.runSqlPool backupPool $
|
try $ PS.runSqlite dbName $ runMigrationUnsafeQuiet migrateAll :: IO
|
||||||
insertMany_ $ entityVal <$> addresses
|
(Either SomeException [T.Text])
|
||||||
|
case m of
|
||||||
|
Left e2 -> return $ Left $ "Failed to migrate data tables" ++ show e2
|
||||||
|
Right _ -> do
|
||||||
|
return $ Right True
|
||||||
|
Right _ -> do
|
||||||
return $ Right False
|
return $ Right False
|
||||||
|
|
||||||
migrateTables :: ConnectionPool -> [Int] -> NoLoggingT IO ()
|
|
||||||
migrateTables pool versions = do
|
|
||||||
unless (1 `elem` versions) $ do
|
|
||||||
logDebugN "Making version 1 changes"
|
|
||||||
_ <-
|
|
||||||
runNoLoggingT $
|
|
||||||
PS.retryOnBusy $
|
|
||||||
flip PS.runSqlPool pool $ do
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_wallet\" ADD COLUMN \"local\" BOOLEAN NOT NULL DEFAULT TRUE;"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" RENAME COLUMN \"orch_spend_key\" TO \"orch_spend_key_old\";"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" RENAME COLUMN \"sap_spend_key\" TO \"sap_spend_key_old\";"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" RENAME COLUMN \"t_private_key\" TO \"t_private_key_old\";"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" ADD COLUMN \"orch_spend_key\" VARCHAR NULL DEFAULT NULL;"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" ADD COLUMN \"sap_spend_key\" VARCHAR NULL DEFAULT NULL;"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" ADD COLUMN \"t_private_key\" VARCHAR NULL DEFAULT NULL;"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"UPDATE \"zcash_account\" SET \"orch_spend_key\" = \"orch_spend_key_old\", \"sap_spend_key\" = \"sap_spend_key_old\", \"t_private_key\" = \"t_private_key_old\" WHERE 1=1;"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" DROP COLUMN \"orch_spend_key_old\";"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" DROP COLUMN \"sap_spend_key_old\";"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" DROP COLUMN \"t_private_key_old\";"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" ADD COLUMN \"fvk\" VARCHAR NULL DEFAULT NULL;"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" ADD COLUMN \"ivk\" VARCHAR NULL DEFAULT NULL;"
|
|
||||||
[]
|
|
||||||
rawExecute
|
|
||||||
"ALTER TABLE \"zcash_account\" ADD COLUMN \"type\" VARCHAR NOT NULL DEFAULT 'Local';"
|
|
||||||
[]
|
|
||||||
_ <-
|
|
||||||
runNoLoggingT $
|
|
||||||
PS.retryOnBusy $
|
|
||||||
flip PS.runSqlPool pool $ do upsert (ZenithSchema 1 "Viewing Keys") []
|
|
||||||
logDebugN "Version 1 changes complete"
|
|
||||||
|
|
||||||
initPool :: T.Text -> NoLoggingT IO ConnectionPool
|
initPool :: T.Text -> NoLoggingT IO ConnectionPool
|
||||||
initPool dbPath = do
|
initPool dbPath = do
|
||||||
let dbInfo = PS.mkSqliteConnectionInfo dbPath
|
let dbInfo = PS.mkSqliteConnectionInfo dbPath
|
||||||
PS.createSqlitePoolFromInfo dbInfo 5
|
PS.createSqlitePoolFromInfo dbInfo 5
|
||||||
|
|
||||||
getVersions :: ConnectionPool -> IO [Int]
|
|
||||||
getVersions pool = do
|
|
||||||
versions <-
|
|
||||||
runNoLoggingT $
|
|
||||||
PS.retryOnBusy $
|
|
||||||
flip PS.runSqlPool pool $ do
|
|
||||||
select $ do
|
|
||||||
v <- from $ table @ZenithSchema
|
|
||||||
orderBy [asc $ v ^. ZenithSchemaVersion]
|
|
||||||
pure (v ^. ZenithSchemaVersion)
|
|
||||||
return $ map (\(Value x) -> x) versions
|
|
||||||
|
|
||||||
-- | Upgrade the database
|
-- | Upgrade the database
|
||||||
upgradeDb ::
|
upgradeDb ::
|
||||||
T.Text -- ^ database path
|
T.Text -- ^ database path
|
||||||
|
@ -629,32 +508,6 @@ walletExists pool n =
|
||||||
where_ (wallets ^. ZcashWalletId ==. val (toSqlKey $ fromIntegral n))
|
where_ (wallets ^. ZcashWalletId ==. val (toSqlKey $ fromIntegral n))
|
||||||
pure wallets
|
pure wallets
|
||||||
|
|
||||||
getVkWallet :: ConnectionPool -> IO (Maybe (Entity ZcashWallet))
|
|
||||||
getVkWallet pool = do
|
|
||||||
runNoLoggingT $
|
|
||||||
PS.retryOnBusy $
|
|
||||||
flip PS.runSqlPool pool $ do
|
|
||||||
selectOne $ do
|
|
||||||
wal <- from $ table @ZcashWallet
|
|
||||||
where_ (wal ^. ZcashWalletName ==. val "Viewing Keys")
|
|
||||||
where_ (wal ^. ZcashWalletLocal ==. val False)
|
|
||||||
pure wal
|
|
||||||
|
|
||||||
saveVkWallet ::
|
|
||||||
ConnectionPool -> ZcashNet -> Int -> IO (Maybe (Entity ZcashWallet))
|
|
||||||
saveVkWallet pool znet bh = do
|
|
||||||
runNoLoggingT $
|
|
||||||
PS.retryOnBusy $
|
|
||||||
flip PS.runSqlPool pool $
|
|
||||||
insertUniqueEntity $
|
|
||||||
ZcashWallet
|
|
||||||
"Viewing Keys"
|
|
||||||
(ZcashNetDB znet)
|
|
||||||
(PhraseDB $ Phrase "")
|
|
||||||
bh
|
|
||||||
0
|
|
||||||
False
|
|
||||||
|
|
||||||
getNetwork :: ConnectionPool -> WalletAddressId -> IO ZcashNet
|
getNetwork :: ConnectionPool -> WalletAddressId -> IO ZcashNet
|
||||||
getNetwork pool a = do
|
getNetwork pool a = do
|
||||||
n <-
|
n <-
|
||||||
|
@ -707,23 +560,6 @@ getAccounts pool w =
|
||||||
where_ (accs ^. ZcashAccountWalletId ==. val w)
|
where_ (accs ^. ZcashAccountWalletId ==. val w)
|
||||||
pure accs
|
pure accs
|
||||||
|
|
||||||
-- | Returns a list of accounts with no viewing keys. For database migration purposes
|
|
||||||
getAccountsNoVKs ::
|
|
||||||
ConnectionPool -- ^ The database path
|
|
||||||
-> NoLoggingT IO [(Value ZcashNetDB, Entity ZcashAccount)]
|
|
||||||
getAccountsNoVKs pool =
|
|
||||||
PS.retryOnBusy $
|
|
||||||
flip PS.runSqlPool pool $ do
|
|
||||||
select $ do
|
|
||||||
(wallet :& acc) <-
|
|
||||||
from $ table @ZcashWallet `innerJoin` table @ZcashAccount `on`
|
|
||||||
(\(wallet :& acc) ->
|
|
||||||
wallet ^. ZcashWalletId ==. acc ^. ZcashAccountWalletId)
|
|
||||||
where_
|
|
||||||
(acc ^. ZcashAccountType ==. val Local &&.
|
|
||||||
isNothing (acc ^. ZcashAccountFvk))
|
|
||||||
pure (wallet ^. ZcashWalletNetwork, acc)
|
|
||||||
|
|
||||||
getAccountById ::
|
getAccountById ::
|
||||||
ConnectionPool -> ZcashAccountId -> IO (Maybe (Entity ZcashAccount))
|
ConnectionPool -> ZcashAccountId -> IO (Maybe (Entity ZcashAccount))
|
||||||
getAccountById pool za = do
|
getAccountById pool za = do
|
||||||
|
@ -794,7 +630,6 @@ getAddresses pool a =
|
||||||
addrs <- from $ table @WalletAddress
|
addrs <- from $ table @WalletAddress
|
||||||
where_ (addrs ^. WalletAddressAccId ==. val a)
|
where_ (addrs ^. WalletAddressAccId ==. val a)
|
||||||
where_ (addrs ^. WalletAddressScope ==. val (ScopeDB External))
|
where_ (addrs ^. WalletAddressScope ==. val (ScopeDB External))
|
||||||
orderBy [asc $ addrs ^. WalletAddressId]
|
|
||||||
pure addrs
|
pure addrs
|
||||||
|
|
||||||
getAddressById ::
|
getAddressById ::
|
||||||
|
@ -812,9 +647,8 @@ getAddressById pool a = do
|
||||||
getInternalAddresses ::
|
getInternalAddresses ::
|
||||||
ConnectionPool -- ^ The database path
|
ConnectionPool -- ^ The database path
|
||||||
-> ZcashAccountId -- ^ The account ID to check
|
-> ZcashAccountId -- ^ The account ID to check
|
||||||
-> IO [Entity WalletAddress]
|
-> NoLoggingT IO [Entity WalletAddress]
|
||||||
getInternalAddresses pool a =
|
getInternalAddresses pool a =
|
||||||
runNoLoggingT $
|
|
||||||
PS.retryOnBusy $
|
PS.retryOnBusy $
|
||||||
flip PS.runSqlPool pool $ do
|
flip PS.runSqlPool pool $ do
|
||||||
select $ do
|
select $ do
|
||||||
|
@ -1075,36 +909,6 @@ upgradeQrTable pool = do
|
||||||
[PersistText "TransparentPool", PersistText "Transparent"]
|
[PersistText "TransparentPool", PersistText "Transparent"]
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
upgradeAccountTable :: ConnectionPool -> NoLoggingT IO ()
|
|
||||||
upgradeAccountTable pool = do
|
|
||||||
accs <- liftIO $ runNoLoggingT $ getAccountsNoVKs pool
|
|
||||||
logDebugN $ T.pack $ show $ length accs
|
|
||||||
forM_ accs $ \(Value znet, a) -> do
|
|
||||||
FullVk b <-
|
|
||||||
liftIO $
|
|
||||||
deriveUfvk
|
|
||||||
(getNet znet)
|
|
||||||
(getOrchSK <$> zcashAccountOrchSpendKey (entityVal a))
|
|
||||||
(getSapSK <$> zcashAccountSapSpendKey (entityVal a))
|
|
||||||
(getTranSK <$> zcashAccountTPrivateKey (entityVal a))
|
|
||||||
IncomingVk c <-
|
|
||||||
liftIO $
|
|
||||||
deriveUivk
|
|
||||||
(getNet znet)
|
|
||||||
(getOrchSK <$> zcashAccountOrchSpendKey (entityVal a))
|
|
||||||
(getSapSK <$> zcashAccountSapSpendKey (entityVal a))
|
|
||||||
(getTranSK <$> zcashAccountTPrivateKey (entityVal a))
|
|
||||||
runNoLoggingT $
|
|
||||||
PS.retryOnBusy $
|
|
||||||
flip PS.runSqlPool pool $ do
|
|
||||||
update $ \w -> do
|
|
||||||
set
|
|
||||||
w
|
|
||||||
[ ZcashAccountFvk =. just (val $ UnifiedFvkDB b)
|
|
||||||
, ZcashAccountIvk =. just (val $ UnifiedIvkDB c)
|
|
||||||
]
|
|
||||||
where_ $ w ^. ZcashAccountId ==. val (entityKey a)
|
|
||||||
|
|
||||||
-- * Wallet
|
-- * Wallet
|
||||||
-- | Get the block of the last transaction known to the wallet
|
-- | Get the block of the last transaction known to the wallet
|
||||||
getMaxWalletBlock ::
|
getMaxWalletBlock ::
|
||||||
|
@ -1632,8 +1436,7 @@ getWalletTransactions ::
|
||||||
-> NoLoggingT IO ()
|
-> NoLoggingT IO ()
|
||||||
getWalletTransactions pool w = do
|
getWalletTransactions pool w = do
|
||||||
let w' = entityVal w
|
let w' = entityVal w
|
||||||
chgAddr <-
|
chgAddr <- getInternalAddresses pool $ walletAddressAccId $ entityVal w
|
||||||
liftIO $ getInternalAddresses pool $ walletAddressAccId $ entityVal w
|
|
||||||
let ctReceiver = t_rec =<< readUnifiedAddressDB (entityVal $ head chgAddr)
|
let ctReceiver = t_rec =<< readUnifiedAddressDB (entityVal $ head chgAddr)
|
||||||
let csReceiver = s_rec =<< readUnifiedAddressDB (entityVal $ head chgAddr)
|
let csReceiver = s_rec =<< readUnifiedAddressDB (entityVal $ head chgAddr)
|
||||||
let coReceiver = o_rec =<< readUnifiedAddressDB (entityVal $ head chgAddr)
|
let coReceiver = o_rec =<< readUnifiedAddressDB (entityVal $ head chgAddr)
|
||||||
|
|
1067
src/Zenith/GUI.hs
1067
src/Zenith/GUI.hs
File diff suppressed because it is too large
Load diff
|
@ -13,14 +13,14 @@
|
||||||
module Zenith.RPC where
|
module Zenith.RPC where
|
||||||
|
|
||||||
import Control.Concurrent (forkIO)
|
import Control.Concurrent (forkIO)
|
||||||
import Control.Exception (SomeException(..), try)
|
import Control.Exception (try)
|
||||||
import Control.Monad (unless)
|
import Control.Monad (unless, when)
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import Control.Monad.Logger (runNoLoggingT, runStderrLoggingT)
|
import Control.Monad.Logger (runFileLoggingT, runNoLoggingT, runStderrLoggingT)
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import qualified Data.HexString as H
|
import qualified Data.HexString as H
|
||||||
import Data.Int
|
import Data.Int
|
||||||
import Data.Scientific (Scientific(..), floatingOrInteger)
|
import Data.Scientific (floatingOrInteger)
|
||||||
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 Data.Time.Clock (getCurrentTime)
|
import Data.Time.Clock (getCurrentTime)
|
||||||
|
@ -36,18 +36,12 @@ import Database.Esqueleto.Experimental
|
||||||
)
|
)
|
||||||
import Servant
|
import Servant
|
||||||
import Text.Read (readMaybe)
|
import Text.Read (readMaybe)
|
||||||
import ZcashHaskell.Keys
|
import ZcashHaskell.Keys (generateWalletSeedPhrase)
|
||||||
( deriveUfvk
|
|
||||||
, deriveUivk
|
|
||||||
, encodeVK
|
|
||||||
, generateWalletSeedPhrase
|
|
||||||
)
|
|
||||||
import ZcashHaskell.Orchard (parseAddress)
|
import ZcashHaskell.Orchard (parseAddress)
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
( BlockResponse(..)
|
( BlockResponse(..)
|
||||||
, RpcError(..)
|
, RpcError(..)
|
||||||
, Scope(..)
|
, Scope(..)
|
||||||
, ValidVk(..)
|
|
||||||
, ZcashNet(..)
|
, ZcashNet(..)
|
||||||
, ZebraGetBlockChainInfo(..)
|
, ZebraGetBlockChainInfo(..)
|
||||||
)
|
)
|
||||||
|
@ -56,11 +50,7 @@ import Zenith.Core
|
||||||
( checkBlockChain
|
( checkBlockChain
|
||||||
, createCustomWalletAddress
|
, createCustomWalletAddress
|
||||||
, createZcashAccount
|
, createZcashAccount
|
||||||
, deshieldNotes
|
|
||||||
, importViewingKey
|
|
||||||
, parseVK
|
|
||||||
, prepareTxV2
|
, prepareTxV2
|
||||||
, shieldTransparentNotes
|
|
||||||
, syncWallet
|
, syncWallet
|
||||||
, updateCommitmentTrees
|
, updateCommitmentTrees
|
||||||
)
|
)
|
||||||
|
@ -104,15 +94,11 @@ import Zenith.DB
|
||||||
import Zenith.Scanner (checkIntegrity, processTx, updateConfs)
|
import Zenith.Scanner (checkIntegrity, processTx, updateConfs)
|
||||||
import Zenith.Types
|
import Zenith.Types
|
||||||
( AccountBalance(..)
|
( AccountBalance(..)
|
||||||
, AccountType(..)
|
|
||||||
, Config(..)
|
, Config(..)
|
||||||
, HexStringDB(..)
|
, HexStringDB(..)
|
||||||
, OrchardSpendingKeyDB(..)
|
|
||||||
, PhraseDB(..)
|
, PhraseDB(..)
|
||||||
, PrivacyPolicy(..)
|
, PrivacyPolicy(..)
|
||||||
, ProposedNote(..)
|
, ProposedNote(..)
|
||||||
, UnifiedFvkDB(..)
|
|
||||||
, UnifiedIvkDB(..)
|
|
||||||
, ZcashAccountAPI(..)
|
, ZcashAccountAPI(..)
|
||||||
, ZcashAddressAPI(..)
|
, ZcashAddressAPI(..)
|
||||||
, ZcashNetDB(..)
|
, ZcashNetDB(..)
|
||||||
|
@ -135,11 +121,6 @@ data ZenithMethod
|
||||||
| GetNewAddress
|
| GetNewAddress
|
||||||
| GetOperationStatus
|
| GetOperationStatus
|
||||||
| SendMany
|
| SendMany
|
||||||
| ShieldNotes
|
|
||||||
| DeshieldFunds
|
|
||||||
| GetFVK
|
|
||||||
| GetIVK
|
|
||||||
| ImportVK
|
|
||||||
| UnknownMethod
|
| UnknownMethod
|
||||||
deriving (Eq, Prelude.Show)
|
deriving (Eq, Prelude.Show)
|
||||||
|
|
||||||
|
@ -155,11 +136,6 @@ instance ToJSON ZenithMethod where
|
||||||
toJSON GetNewAddress = Data.Aeson.String "getnewaddress"
|
toJSON GetNewAddress = Data.Aeson.String "getnewaddress"
|
||||||
toJSON GetOperationStatus = Data.Aeson.String "getoperationstatus"
|
toJSON GetOperationStatus = Data.Aeson.String "getoperationstatus"
|
||||||
toJSON SendMany = Data.Aeson.String "sendmany"
|
toJSON SendMany = Data.Aeson.String "sendmany"
|
||||||
toJSON ShieldNotes = Data.Aeson.String "shieldnotes"
|
|
||||||
toJSON DeshieldFunds = Data.Aeson.String "deshieldfunds"
|
|
||||||
toJSON GetFVK = Data.Aeson.String "getfullvk"
|
|
||||||
toJSON GetIVK = Data.Aeson.String "getincomingvk"
|
|
||||||
toJSON ImportVK = Data.Aeson.String "importvk"
|
|
||||||
toJSON UnknownMethod = Data.Aeson.Null
|
toJSON UnknownMethod = Data.Aeson.Null
|
||||||
|
|
||||||
instance FromJSON ZenithMethod where
|
instance FromJSON ZenithMethod where
|
||||||
|
@ -176,11 +152,6 @@ instance FromJSON ZenithMethod where
|
||||||
"getnewaddress" -> pure GetNewAddress
|
"getnewaddress" -> pure GetNewAddress
|
||||||
"getoperationstatus" -> pure GetOperationStatus
|
"getoperationstatus" -> pure GetOperationStatus
|
||||||
"sendmany" -> pure SendMany
|
"sendmany" -> pure SendMany
|
||||||
"shieldnotes" -> pure ShieldNotes
|
|
||||||
"deshieldfunds" -> pure DeshieldFunds
|
|
||||||
"getfullvk" -> pure GetFVK
|
|
||||||
"getincomingvk" -> pure GetIVK
|
|
||||||
"importvk" -> pure ImportVK
|
|
||||||
_ -> pure UnknownMethod
|
_ -> pure UnknownMethod
|
||||||
|
|
||||||
data ZenithParams
|
data ZenithParams
|
||||||
|
@ -196,10 +167,6 @@ data ZenithParams
|
||||||
| OpParams !ZenithUuid
|
| OpParams !ZenithUuid
|
||||||
| SendParams !Int ![ProposedNote] !PrivacyPolicy
|
| SendParams !Int ![ProposedNote] !PrivacyPolicy
|
||||||
| TestParams !T.Text
|
| TestParams !T.Text
|
||||||
| ShieldNotesParams !Int
|
|
||||||
| DeshieldParams !Int !Scientific
|
|
||||||
| ViewingKeyParams !Int
|
|
||||||
| ImportVkParams !T.Text !T.Text !Int
|
|
||||||
deriving (Eq, Prelude.Show)
|
deriving (Eq, Prelude.Show)
|
||||||
|
|
||||||
instance ToJSON ZenithParams where
|
instance ToJSON ZenithParams where
|
||||||
|
@ -224,13 +191,6 @@ instance ToJSON ZenithParams where
|
||||||
Data.Aeson.Array $ V.fromList [Data.Aeson.String $ U.toText $ getUuid i]
|
Data.Aeson.Array $ V.fromList [Data.Aeson.String $ U.toText $ getUuid i]
|
||||||
toJSON (SendParams i ns p) =
|
toJSON (SendParams i ns p) =
|
||||||
Data.Aeson.Array $ V.fromList [jsonNumber i, toJSON ns, toJSON p]
|
Data.Aeson.Array $ V.fromList [jsonNumber i, toJSON ns, toJSON p]
|
||||||
toJSON (ShieldNotesParams i) = Data.Aeson.Array $ V.fromList [jsonNumber i]
|
|
||||||
toJSON (DeshieldParams i s) =
|
|
||||||
Data.Aeson.Array $ V.fromList [jsonNumber i, Data.Aeson.Number s]
|
|
||||||
toJSON (ViewingKeyParams i) = Data.Aeson.Array $ V.fromList [jsonNumber i]
|
|
||||||
toJSON (ImportVkParams n k b) =
|
|
||||||
Data.Aeson.Array $
|
|
||||||
V.fromList [Data.Aeson.String n, Data.Aeson.String k, jsonNumber b]
|
|
||||||
|
|
||||||
data ZenithResponse
|
data ZenithResponse
|
||||||
= InfoResponse !T.Text !ZenithInfo
|
= InfoResponse !T.Text !ZenithInfo
|
||||||
|
@ -243,8 +203,6 @@ data ZenithResponse
|
||||||
| NewAddrResponse !T.Text !ZcashAddressAPI
|
| NewAddrResponse !T.Text !ZcashAddressAPI
|
||||||
| OpResponse !T.Text !Operation
|
| OpResponse !T.Text !Operation
|
||||||
| SendResponse !T.Text !U.UUID
|
| SendResponse !T.Text !U.UUID
|
||||||
| MultiOpResponse !T.Text ![T.Text]
|
|
||||||
| ViewingKeyResponse !T.Text !T.Text
|
|
||||||
| ErrorResponse !T.Text !Double !T.Text
|
| ErrorResponse !T.Text !Double !T.Text
|
||||||
deriving (Eq, Prelude.Show)
|
deriving (Eq, Prelude.Show)
|
||||||
|
|
||||||
|
@ -266,8 +224,6 @@ instance ToJSON ZenithResponse where
|
||||||
toJSON (NewAddrResponse i a) = packRpcResponse i a
|
toJSON (NewAddrResponse i a) = packRpcResponse i a
|
||||||
toJSON (OpResponse i u) = packRpcResponse i u
|
toJSON (OpResponse i u) = packRpcResponse i u
|
||||||
toJSON (SendResponse i o) = packRpcResponse i o
|
toJSON (SendResponse i o) = packRpcResponse i o
|
||||||
toJSON (MultiOpResponse i o) = packRpcResponse i o
|
|
||||||
toJSON (ViewingKeyResponse i k) = packRpcResponse i k
|
|
||||||
|
|
||||||
instance FromJSON ZenithResponse where
|
instance FromJSON ZenithResponse where
|
||||||
parseJSON =
|
parseJSON =
|
||||||
|
@ -342,9 +298,6 @@ instance FromJSON ZenithResponse where
|
||||||
k5 <- parseJSON r1
|
k5 <- parseJSON r1
|
||||||
pure $ NoteListResponse i k5
|
pure $ NoteListResponse i k5
|
||||||
Nothing -> fail "Unknown object"
|
Nothing -> fail "Unknown object"
|
||||||
String s -> do
|
|
||||||
k7 <- parseJSON r1
|
|
||||||
pure $ MultiOpResponse i k7
|
|
||||||
_anyOther -> fail "Malformed JSON"
|
_anyOther -> fail "Malformed JSON"
|
||||||
Number k -> do
|
Number k -> do
|
||||||
case floatingOrInteger k of
|
case floatingOrInteger k of
|
||||||
|
@ -352,7 +305,7 @@ instance FromJSON ZenithResponse where
|
||||||
Right k' -> pure $ NewItemResponse i k'
|
Right k' -> pure $ NewItemResponse i k'
|
||||||
String s -> do
|
String s -> do
|
||||||
case U.fromText s of
|
case U.fromText s of
|
||||||
Nothing -> pure $ ViewingKeyResponse i s
|
Nothing -> fail "Unknown value"
|
||||||
Just u -> pure $ SendResponse i u
|
Just u -> pure $ SendResponse i u
|
||||||
_anyOther -> fail "Malformed JSON"
|
_anyOther -> fail "Malformed JSON"
|
||||||
Just e1 -> pure $ ErrorResponse i (ecode e1) (emessage e1)
|
Just e1 -> pure $ ErrorResponse i (ecode e1) (emessage e1)
|
||||||
|
@ -536,59 +489,6 @@ instance FromJSON RpcCall where
|
||||||
_anyOther -> pure $ RpcCall v i SendMany BadParams
|
_anyOther -> pure $ RpcCall v i SendMany BadParams
|
||||||
else pure $ RpcCall v i SendMany BadParams
|
else pure $ RpcCall v i SendMany BadParams
|
||||||
_anyOther -> pure $ RpcCall v i SendMany BadParams
|
_anyOther -> pure $ RpcCall v i SendMany BadParams
|
||||||
ShieldNotes -> do
|
|
||||||
p <- obj .: "params"
|
|
||||||
case p of
|
|
||||||
Array a ->
|
|
||||||
if V.length a == 1
|
|
||||||
then do
|
|
||||||
x <- parseJSON $ a V.! 0
|
|
||||||
pure $ RpcCall v i ShieldNotes (ShieldNotesParams x)
|
|
||||||
else pure $ RpcCall v i ShieldNotes BadParams
|
|
||||||
_anyOther -> pure $ RpcCall v i ShieldNotes BadParams
|
|
||||||
DeshieldFunds -> do
|
|
||||||
p <- obj .: "params"
|
|
||||||
case p of
|
|
||||||
Array a ->
|
|
||||||
if V.length a == 2
|
|
||||||
then do
|
|
||||||
x <- parseJSON $ a V.! 0
|
|
||||||
y <- parseJSON $ a V.! 1
|
|
||||||
pure $ RpcCall v i DeshieldFunds (DeshieldParams x y)
|
|
||||||
else pure $ RpcCall v i DeshieldFunds BadParams
|
|
||||||
_anyOther -> pure $ RpcCall v i DeshieldFunds BadParams
|
|
||||||
GetFVK -> do
|
|
||||||
p <- obj .: "params"
|
|
||||||
case p of
|
|
||||||
Array a ->
|
|
||||||
if V.length a == 1
|
|
||||||
then do
|
|
||||||
x <- parseJSON $ a V.! 0
|
|
||||||
pure $ RpcCall v i GetFVK (ViewingKeyParams x)
|
|
||||||
else pure $ RpcCall v i GetFVK BadParams
|
|
||||||
_anyOther -> pure $ RpcCall v i GetFVK BadParams
|
|
||||||
GetIVK -> do
|
|
||||||
p <- obj .: "params"
|
|
||||||
case p of
|
|
||||||
Array a ->
|
|
||||||
if V.length a == 1
|
|
||||||
then do
|
|
||||||
x <- parseJSON $ a V.! 0
|
|
||||||
pure $ RpcCall v i GetIVK (ViewingKeyParams x)
|
|
||||||
else pure $ RpcCall v i GetIVK BadParams
|
|
||||||
_anyOther -> pure $ RpcCall v i GetIVK BadParams
|
|
||||||
ImportVK -> do
|
|
||||||
p <- obj .: "params"
|
|
||||||
case p of
|
|
||||||
Array a ->
|
|
||||||
if V.length a == 3
|
|
||||||
then do
|
|
||||||
x <- parseJSON $ a V.! 0
|
|
||||||
y <- parseJSON $ a V.! 1
|
|
||||||
z <- parseJSON $ a V.! 2
|
|
||||||
pure $ RpcCall v i ImportVK (ImportVkParams x y z)
|
|
||||||
else pure $ RpcCall v i ImportVK BadParams
|
|
||||||
_anyOther -> pure $ RpcCall v i ImportVK BadParams
|
|
||||||
|
|
||||||
type ZenithRPC
|
type ZenithRPC
|
||||||
= "status" :> Get '[ JSON] Value :<|> BasicAuth "zenith-realm" Bool :> ReqBody
|
= "status" :> Get '[ JSON] Value :<|> BasicAuth "zenith-realm" Bool :> ReqBody
|
||||||
|
@ -611,7 +511,7 @@ zenithServer state = getinfo :<|> handleRPC
|
||||||
getinfo =
|
getinfo =
|
||||||
return $
|
return $
|
||||||
object
|
object
|
||||||
[ "version" .= ("0.9.1.0-beta" :: String)
|
[ "version" .= ("0.7.0.0-beta" :: String)
|
||||||
, "network" .= ("testnet" :: String)
|
, "network" .= ("testnet" :: String)
|
||||||
]
|
]
|
||||||
handleRPC :: Bool -> RpcCall -> Handler ZenithResponse
|
handleRPC :: Bool -> RpcCall -> Handler ZenithResponse
|
||||||
|
@ -687,7 +587,7 @@ zenithServer state = getinfo :<|> handleRPC
|
||||||
return $
|
return $
|
||||||
InfoResponse
|
InfoResponse
|
||||||
(callId req)
|
(callId req)
|
||||||
(ZenithInfo "0.9.1.0-beta" (w_network state) (w_build state))
|
(ZenithInfo "0.7.0.0-beta" (w_network state) (w_build state))
|
||||||
_anyOtherParams ->
|
_anyOtherParams ->
|
||||||
return $ ErrorResponse (callId req) (-32602) "Invalid params"
|
return $ ErrorResponse (callId req) (-32602) "Invalid params"
|
||||||
ListReceived ->
|
ListReceived ->
|
||||||
|
@ -734,12 +634,9 @@ zenithServer state = getinfo :<|> handleRPC
|
||||||
acc <- liftIO $ getAccountById pool $ toSqlKey i
|
acc <- liftIO $ getAccountById pool $ toSqlKey i
|
||||||
case acc of
|
case acc of
|
||||||
Just acc' -> do
|
Just acc' -> do
|
||||||
if zcashAccountType (entityVal acc') /= IncomingViewKey
|
|
||||||
then do
|
|
||||||
c <- liftIO $ getPoolBalance pool $ entityKey acc'
|
c <- liftIO $ getPoolBalance pool $ entityKey acc'
|
||||||
u <- liftIO $ getUnconfPoolBalance pool $ entityKey acc'
|
u <- liftIO $ getUnconfPoolBalance pool $ entityKey acc'
|
||||||
return $ BalanceResponse (callId req) c u
|
return $ BalanceResponse (callId req) c u
|
||||||
else return $ readOnlyError $ callId req
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
return $
|
return $
|
||||||
ErrorResponse (callId req) (-32006) "Account does not exist."
|
ErrorResponse (callId req) (-32006) "Account does not exist."
|
||||||
|
@ -768,7 +665,6 @@ zenithServer state = getinfo :<|> handleRPC
|
||||||
(PhraseDB sP)
|
(PhraseDB sP)
|
||||||
(w_startBlock state)
|
(w_startBlock state)
|
||||||
0
|
0
|
||||||
True
|
|
||||||
case r of
|
case r of
|
||||||
Nothing ->
|
Nothing ->
|
||||||
return $
|
return $
|
||||||
|
@ -798,21 +694,14 @@ zenithServer state = getinfo :<|> handleRPC
|
||||||
case w of
|
case w of
|
||||||
Just w' -> do
|
Just w' -> do
|
||||||
aIdx <- liftIO $ getMaxAccount pool $ entityKey w'
|
aIdx <- liftIO $ getMaxAccount pool $ entityKey w'
|
||||||
if zcashWalletLocal $ entityVal w'
|
|
||||||
then do
|
|
||||||
nAcc <-
|
nAcc <-
|
||||||
liftIO
|
liftIO
|
||||||
(try $
|
(try $ createZcashAccount t (aIdx + 1) w' :: IO
|
||||||
createZcashAccount
|
(Either IOError ZcashAccount))
|
||||||
t
|
|
||||||
(aIdx + 1)
|
|
||||||
(getNet $ zcashWalletNetwork $ entityVal w')
|
|
||||||
w' :: IO (Either IOError ZcashAccount))
|
|
||||||
case nAcc of
|
case nAcc of
|
||||||
Left e ->
|
Left e ->
|
||||||
return $
|
return $
|
||||||
ErrorResponse (callId req) (-32010) $
|
ErrorResponse (callId req) (-32010) $ T.pack $ show e
|
||||||
T.pack $ show e
|
|
||||||
Right nAcc' -> do
|
Right nAcc' -> do
|
||||||
r <- liftIO $ saveAccount pool nAcc'
|
r <- liftIO $ saveAccount pool nAcc'
|
||||||
case r of
|
case r of
|
||||||
|
@ -826,7 +715,6 @@ zenithServer state = getinfo :<|> handleRPC
|
||||||
return $
|
return $
|
||||||
NewItemResponse (callId req) $
|
NewItemResponse (callId req) $
|
||||||
fromSqlKey $ entityKey x
|
fromSqlKey $ entityKey x
|
||||||
else return $ notLocalError $ callId req
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
return $
|
return $
|
||||||
ErrorResponse
|
ErrorResponse
|
||||||
|
@ -936,8 +824,6 @@ zenithServer state = getinfo :<|> handleRPC
|
||||||
liftIO $ getAccountById pool $ toSqlKey $ fromIntegral a
|
liftIO $ getAccountById pool $ toSqlKey $ fromIntegral a
|
||||||
case acc of
|
case acc of
|
||||||
Just acc' -> do
|
Just acc' -> do
|
||||||
if zcashAccountType (entityVal acc') == Local
|
|
||||||
then do
|
|
||||||
bl <-
|
bl <-
|
||||||
liftIO $
|
liftIO $
|
||||||
getLastSyncBlock
|
getLastSyncBlock
|
||||||
|
@ -958,141 +844,6 @@ zenithServer state = getinfo :<|> handleRPC
|
||||||
bl
|
bl
|
||||||
ns
|
ns
|
||||||
p
|
p
|
||||||
case res of
|
|
||||||
Left e ->
|
|
||||||
finalizeOperation pool opkey' Failed $
|
|
||||||
T.pack $ show e
|
|
||||||
Right rawTx -> do
|
|
||||||
zebraRes <-
|
|
||||||
makeZebraCall
|
|
||||||
zHost
|
|
||||||
zPort
|
|
||||||
"sendrawtransaction"
|
|
||||||
[Data.Aeson.String $ H.toText rawTx]
|
|
||||||
case zebraRes of
|
|
||||||
Left e1 ->
|
|
||||||
finalizeOperation pool opkey' Failed $
|
|
||||||
T.pack $ show e1
|
|
||||||
Right txId ->
|
|
||||||
finalizeOperation
|
|
||||||
pool
|
|
||||||
opkey'
|
|
||||||
Successful $
|
|
||||||
"Tx ID: " <> H.toText txId
|
|
||||||
return $ SendResponse (callId req) opid
|
|
||||||
else return $ readOnlyError $ callId req
|
|
||||||
Nothing ->
|
|
||||||
return $
|
|
||||||
ErrorResponse
|
|
||||||
(callId req)
|
|
||||||
(-32006)
|
|
||||||
"Account does not exist."
|
|
||||||
_anyOtherParams ->
|
|
||||||
return $ ErrorResponse (callId req) (-32602) "Invalid params"
|
|
||||||
ShieldNotes -> do
|
|
||||||
case parameters req of
|
|
||||||
ShieldNotesParams i -> do
|
|
||||||
let dbPath = w_dbPath state
|
|
||||||
let net = w_network state
|
|
||||||
let zHost = w_host state
|
|
||||||
let zPort = w_port state
|
|
||||||
pool <- liftIO $ runNoLoggingT $ initPool dbPath
|
|
||||||
syncChk <- liftIO $ isSyncing pool
|
|
||||||
if syncChk
|
|
||||||
then return $
|
|
||||||
ErrorResponse
|
|
||||||
(callId req)
|
|
||||||
(-32012)
|
|
||||||
"The Zenith server is syncing, please try again later."
|
|
||||||
else do
|
|
||||||
acc <-
|
|
||||||
liftIO $ getAccountById pool $ toSqlKey $ fromIntegral i
|
|
||||||
case acc of
|
|
||||||
Just acc' -> do
|
|
||||||
bl <-
|
|
||||||
liftIO $
|
|
||||||
getLastSyncBlock
|
|
||||||
pool
|
|
||||||
(zcashAccountWalletId $ entityVal acc')
|
|
||||||
opids <-
|
|
||||||
liftIO $
|
|
||||||
runNoLoggingT $
|
|
||||||
shieldTransparentNotes
|
|
||||||
pool
|
|
||||||
zHost
|
|
||||||
zPort
|
|
||||||
net
|
|
||||||
(entityKey acc')
|
|
||||||
bl
|
|
||||||
let ops =
|
|
||||||
map
|
|
||||||
(\case
|
|
||||||
Left e -> T.pack $ show e
|
|
||||||
Right op -> U.toText op)
|
|
||||||
opids
|
|
||||||
return $ MultiOpResponse (callId req) ops
|
|
||||||
Nothing ->
|
|
||||||
return $
|
|
||||||
ErrorResponse
|
|
||||||
(callId req)
|
|
||||||
(-32006)
|
|
||||||
"Account does not exist."
|
|
||||||
_anyOtherParams ->
|
|
||||||
return $ ErrorResponse (callId req) (-32602) "Invalid params"
|
|
||||||
DeshieldFunds -> do
|
|
||||||
case parameters req of
|
|
||||||
DeshieldParams i k -> do
|
|
||||||
let dbPath = w_dbPath state
|
|
||||||
let net = w_network state
|
|
||||||
let zHost = w_host state
|
|
||||||
let zPort = w_port state
|
|
||||||
pool <- liftIO $ runNoLoggingT $ initPool dbPath
|
|
||||||
syncChk <- liftIO $ isSyncing pool
|
|
||||||
if syncChk
|
|
||||||
then return $
|
|
||||||
ErrorResponse
|
|
||||||
(callId req)
|
|
||||||
(-32012)
|
|
||||||
"The Zenith server is syncing, please try again later."
|
|
||||||
else do
|
|
||||||
opid <- liftIO nextRandom
|
|
||||||
startTime <- liftIO getCurrentTime
|
|
||||||
opkey <-
|
|
||||||
liftIO $
|
|
||||||
saveOperation pool $
|
|
||||||
Operation
|
|
||||||
(ZenithUuid opid)
|
|
||||||
startTime
|
|
||||||
Nothing
|
|
||||||
Processing
|
|
||||||
Nothing
|
|
||||||
case opkey of
|
|
||||||
Nothing ->
|
|
||||||
return $
|
|
||||||
ErrorResponse (callId req) (-32010) "Internal Error"
|
|
||||||
Just opkey' -> do
|
|
||||||
acc <-
|
|
||||||
liftIO $ getAccountById pool $ toSqlKey $ fromIntegral i
|
|
||||||
case acc of
|
|
||||||
Just acc' -> do
|
|
||||||
bl <-
|
|
||||||
liftIO $
|
|
||||||
getLastSyncBlock
|
|
||||||
pool
|
|
||||||
(zcashAccountWalletId $ entityVal acc')
|
|
||||||
_ <-
|
|
||||||
liftIO $
|
|
||||||
forkIO $ do
|
|
||||||
res <-
|
|
||||||
runNoLoggingT $
|
|
||||||
deshieldNotes
|
|
||||||
pool
|
|
||||||
zHost
|
|
||||||
zPort
|
|
||||||
net
|
|
||||||
(entityKey acc')
|
|
||||||
bl
|
|
||||||
k
|
|
||||||
case res of
|
case res of
|
||||||
Left e ->
|
Left e ->
|
||||||
finalizeOperation pool opkey' Failed $
|
finalizeOperation pool opkey' Failed $
|
||||||
|
@ -1120,65 +871,6 @@ zenithServer state = getinfo :<|> handleRPC
|
||||||
"Account does not exist."
|
"Account does not exist."
|
||||||
_anyOtherParams ->
|
_anyOtherParams ->
|
||||||
return $ ErrorResponse (callId req) (-32602) "Invalid params"
|
return $ ErrorResponse (callId req) (-32602) "Invalid params"
|
||||||
GetFVK -> do
|
|
||||||
case parameters req of
|
|
||||||
ViewingKeyParams aid -> do
|
|
||||||
let dbPath = w_dbPath state
|
|
||||||
pool <- liftIO $ runNoLoggingT $ initPool dbPath
|
|
||||||
acc <- liftIO $ getAccountById pool $ toSqlKey $ fromIntegral aid
|
|
||||||
case acc of
|
|
||||||
Just acc' -> do
|
|
||||||
case zcashAccountFvk (entityVal acc') of
|
|
||||||
Nothing ->
|
|
||||||
return $
|
|
||||||
ErrorResponse (callId req) (-32010) "Internal Error"
|
|
||||||
Just fvk ->
|
|
||||||
return $
|
|
||||||
ViewingKeyResponse
|
|
||||||
(callId req)
|
|
||||||
(encodeVK (FullVk $ getFvk fvk))
|
|
||||||
Nothing ->
|
|
||||||
return $
|
|
||||||
ErrorResponse (callId req) (-32006) "Account does not exist."
|
|
||||||
_anyOtherParams ->
|
|
||||||
return $ ErrorResponse (callId req) (-32602) "Invalid params"
|
|
||||||
GetIVK -> do
|
|
||||||
case parameters req of
|
|
||||||
ViewingKeyParams aid -> do
|
|
||||||
let dbPath = w_dbPath state
|
|
||||||
pool <- liftIO $ runNoLoggingT $ initPool dbPath
|
|
||||||
acc <- liftIO $ getAccountById pool $ toSqlKey $ fromIntegral aid
|
|
||||||
case acc of
|
|
||||||
Just acc' -> do
|
|
||||||
case zcashAccountIvk (entityVal acc') of
|
|
||||||
Nothing ->
|
|
||||||
return $
|
|
||||||
ErrorResponse (callId req) (-32010) "Internal Error"
|
|
||||||
Just ivk ->
|
|
||||||
return $
|
|
||||||
ViewingKeyResponse
|
|
||||||
(callId req)
|
|
||||||
(encodeVK $ IncomingVk $ getIvk ivk)
|
|
||||||
Nothing ->
|
|
||||||
return $
|
|
||||||
ErrorResponse (callId req) (-32006) "Account does not exist."
|
|
||||||
_anyOtherParams ->
|
|
||||||
return $ ErrorResponse (callId req) (-32602) "Invalid params"
|
|
||||||
ImportVK -> do
|
|
||||||
case parameters req of
|
|
||||||
ImportVkParams n k b -> do
|
|
||||||
let dbPath = w_dbPath state
|
|
||||||
let znet = w_network state
|
|
||||||
pool <- liftIO $ runNoLoggingT $ initPool dbPath
|
|
||||||
case parseVK k of
|
|
||||||
Nothing -> return $ invalidVkError $ callId req
|
|
||||||
Just vk -> do
|
|
||||||
res <- liftIO $ importViewingKey pool n znet vk b
|
|
||||||
case res of
|
|
||||||
Left e -> return $ ErrorResponse (callId req) (-32010) e
|
|
||||||
Right x -> return $ NewItemResponse (callId req) x
|
|
||||||
_anyOtherParams ->
|
|
||||||
return $ ErrorResponse (callId req) (-32602) "Invalid params"
|
|
||||||
|
|
||||||
authenticate :: Config -> BasicAuthCheck Bool
|
authenticate :: Config -> BasicAuthCheck Bool
|
||||||
authenticate config = BasicAuthCheck check
|
authenticate config = BasicAuthCheck check
|
||||||
|
@ -1224,7 +916,7 @@ scanZebra dbPath zHost zPort net = do
|
||||||
updateCommitmentTrees pool zHost zPort $ ZcashNetDB net
|
updateCommitmentTrees pool zHost zPort $ ZcashNetDB net
|
||||||
runNoLoggingT $
|
runNoLoggingT $
|
||||||
mapM_
|
mapM_
|
||||||
(syncWallet (Config dbPath zHost zPort "user" "pwd" 8080 "usd"))
|
(syncWallet (Config dbPath zHost zPort "user" "pwd" 8080))
|
||||||
wals
|
wals
|
||||||
_ <- completeSync pool Successful
|
_ <- completeSync pool Successful
|
||||||
return ()
|
return ()
|
||||||
|
@ -1240,28 +932,22 @@ scanZebra dbPath zHost zPort net = do
|
||||||
case r of
|
case r of
|
||||||
Left _ -> completeSync pool Failed
|
Left _ -> completeSync pool Failed
|
||||||
Right blk -> do
|
Right blk -> do
|
||||||
|
r2 <-
|
||||||
|
makeZebraCall
|
||||||
|
zHost
|
||||||
|
zPort
|
||||||
|
"getblock"
|
||||||
|
[Data.Aeson.String $ T.pack (show bl), jsonNumber 0]
|
||||||
|
case r2 of
|
||||||
|
Left _ -> completeSync pool Failed
|
||||||
|
Right hb -> do
|
||||||
|
let blockTime = getBlockTime hb
|
||||||
bi <-
|
bi <-
|
||||||
saveBlock pool $
|
saveBlock pool $
|
||||||
ZcashBlock
|
ZcashBlock
|
||||||
(fromIntegral $ bl_height blk)
|
(fromIntegral $ bl_height blk)
|
||||||
(HexStringDB $ bl_hash blk)
|
(HexStringDB $ bl_hash blk)
|
||||||
(fromIntegral $ bl_confirmations blk)
|
(fromIntegral $ bl_confirmations blk)
|
||||||
(fromIntegral $ bl_time blk)
|
blockTime
|
||||||
(ZcashNetDB net)
|
(ZcashNetDB net)
|
||||||
mapM_ (processTx zHost zPort bi pool) $ bl_txs blk
|
mapM_ (processTx zHost zPort bi pool) $ bl_txs blk
|
||||||
|
|
||||||
-- * Errors
|
|
||||||
invalidVkError :: T.Text -> ZenithResponse
|
|
||||||
invalidVkError i =
|
|
||||||
ErrorResponse i (-32013) "The viewing key provided is not valid."
|
|
||||||
|
|
||||||
readOnlyError :: T.Text -> ZenithResponse
|
|
||||||
readOnlyError i =
|
|
||||||
ErrorResponse i (-32014) "Read-only account, operation is not valid."
|
|
||||||
|
|
||||||
notLocalError :: T.Text -> ZenithResponse
|
|
||||||
notLocalError i =
|
|
||||||
ErrorResponse
|
|
||||||
i
|
|
||||||
(-32015)
|
|
||||||
"The wallet is not local, cannot create new accounts."
|
|
||||||
|
|
|
@ -50,7 +50,6 @@ import Zenith.DB
|
||||||
, saveTransaction
|
, saveTransaction
|
||||||
, startSync
|
, startSync
|
||||||
, updateWalletSync
|
, updateWalletSync
|
||||||
, upgradeAccountTable
|
|
||||||
, upgradeQrTable
|
, upgradeQrTable
|
||||||
)
|
)
|
||||||
import Zenith.Types
|
import Zenith.Types
|
||||||
|
@ -78,7 +77,7 @@ rescanZebra host port dbFilePath = do
|
||||||
pool1 <- runNoLoggingT $ initPool dbFilePath
|
pool1 <- runNoLoggingT $ initPool dbFilePath
|
||||||
{-pool2 <- runNoLoggingT $ initPool dbFilePath-}
|
{-pool2 <- runNoLoggingT $ initPool dbFilePath-}
|
||||||
{-pool3 <- runNoLoggingT $ initPool dbFilePath-}
|
{-pool3 <- runNoLoggingT $ initPool dbFilePath-}
|
||||||
_ <- runNoLoggingT $ initDb dbFilePath
|
_ <- initDb dbFilePath
|
||||||
upgradeQrTable pool1
|
upgradeQrTable pool1
|
||||||
clearWalletTransactions pool1
|
clearWalletTransactions pool1
|
||||||
clearWalletData pool1
|
clearWalletData pool1
|
||||||
|
@ -134,13 +133,26 @@ processBlock host port pool pg net b = do
|
||||||
_ <- completeSync pool Failed
|
_ <- completeSync pool Failed
|
||||||
liftIO $ throwIO $ userError e
|
liftIO $ throwIO $ userError e
|
||||||
Right blk -> do
|
Right blk -> do
|
||||||
|
r2 <-
|
||||||
|
liftIO $
|
||||||
|
makeZebraCall
|
||||||
|
host
|
||||||
|
port
|
||||||
|
"getblock"
|
||||||
|
[Data.Aeson.String $ T.pack $ show b, jsonNumber 0]
|
||||||
|
case r2 of
|
||||||
|
Left e2 -> do
|
||||||
|
_ <- completeSync pool Failed
|
||||||
|
liftIO $ throwIO $ userError e2
|
||||||
|
Right hb -> do
|
||||||
|
let blockTime = getBlockTime hb
|
||||||
bi <-
|
bi <-
|
||||||
saveBlock pool $
|
saveBlock pool $
|
||||||
ZcashBlock
|
ZcashBlock
|
||||||
(fromIntegral $ bl_height blk)
|
(fromIntegral $ bl_height blk)
|
||||||
(HexStringDB $ bl_hash blk)
|
(HexStringDB $ bl_hash blk)
|
||||||
(fromIntegral $ bl_confirmations blk)
|
(fromIntegral $ bl_confirmations blk)
|
||||||
(fromIntegral $ bl_time blk)
|
blockTime
|
||||||
net
|
net
|
||||||
mapM_ (processTx host port bi pool) $ bl_txs blk
|
mapM_ (processTx host port bi pool) $ bl_txs blk
|
||||||
liftIO $ tick pg
|
liftIO $ tick pg
|
||||||
|
@ -217,9 +229,8 @@ clearSync config = do
|
||||||
case bc of
|
case bc of
|
||||||
Left e1 -> throwIO e1
|
Left e1 -> throwIO e1
|
||||||
Right chainInfo -> do
|
Right chainInfo -> do
|
||||||
x <- runNoLoggingT $ initDb dbPath
|
x <- initDb dbPath
|
||||||
_ <- upgradeQrTable pool
|
_ <- upgradeQrTable pool
|
||||||
_ <- runNoLoggingT $ upgradeAccountTable pool
|
|
||||||
case x of
|
case x of
|
||||||
Left e2 -> throwIO $ userError e2
|
Left e2 -> throwIO $ userError e2
|
||||||
Right x' -> do
|
Right x' -> do
|
||||||
|
|
|
@ -40,8 +40,6 @@ import ZcashHaskell.Types
|
||||||
, Scope(..)
|
, Scope(..)
|
||||||
, TransparentAddress(..)
|
, TransparentAddress(..)
|
||||||
, TransparentSpendingKey
|
, TransparentSpendingKey
|
||||||
, UnifiedFullViewingKey(..)
|
|
||||||
, UnifiedIncomingViewingKey(..)
|
|
||||||
, ValidAddress(..)
|
, ValidAddress(..)
|
||||||
, ZcashNet(..)
|
, ZcashNet(..)
|
||||||
)
|
)
|
||||||
|
@ -105,41 +103,6 @@ newtype RseedDB = RseedDB
|
||||||
|
|
||||||
derivePersistField "RseedDB"
|
derivePersistField "RseedDB"
|
||||||
|
|
||||||
newtype UnifiedFvkDB = UnifiedFvkDB
|
|
||||||
{ getFvk :: UnifiedFullViewingKey
|
|
||||||
} deriving newtype (Eq, Show, Read)
|
|
||||||
|
|
||||||
derivePersistField "UnifiedFvkDB"
|
|
||||||
|
|
||||||
newtype UnifiedIvkDB = UnifiedIvkDB
|
|
||||||
{ getIvk :: UnifiedIncomingViewingKey
|
|
||||||
} deriving newtype (Eq, Show, Read)
|
|
||||||
|
|
||||||
derivePersistField "UnifiedIvkDB"
|
|
||||||
|
|
||||||
data AccountType
|
|
||||||
= Local
|
|
||||||
| FullViewKey
|
|
||||||
| IncomingViewKey
|
|
||||||
deriving (Eq, Show, Read)
|
|
||||||
|
|
||||||
derivePersistField "AccountType"
|
|
||||||
|
|
||||||
instance ToJSON AccountType where
|
|
||||||
toJSON at =
|
|
||||||
case at of
|
|
||||||
Local -> Data.Aeson.String "Local"
|
|
||||||
FullViewKey -> Data.Aeson.String "FullViewKey"
|
|
||||||
IncomingViewKey -> Data.Aeson.String "IncomingViewKey"
|
|
||||||
|
|
||||||
instance FromJSON AccountType where
|
|
||||||
parseJSON =
|
|
||||||
withText "AccountType" $ \case
|
|
||||||
"Local" -> return Local
|
|
||||||
"FullViewKey" -> return FullViewKey
|
|
||||||
"IncomingViewKey" -> return IncomingViewKey
|
|
||||||
_ -> fail "Not a valid Account type"
|
|
||||||
|
|
||||||
-- * RPC
|
-- * RPC
|
||||||
-- | Type for Configuration parameters
|
-- | Type for Configuration parameters
|
||||||
data Config = Config
|
data Config = Config
|
||||||
|
@ -149,7 +112,6 @@ data Config = Config
|
||||||
, c_zenithUser :: !BS.ByteString
|
, c_zenithUser :: !BS.ByteString
|
||||||
, c_zenithPwd :: !BS.ByteString
|
, c_zenithPwd :: !BS.ByteString
|
||||||
, c_zenithPort :: !Int
|
, c_zenithPort :: !Int
|
||||||
, c_currencyCode :: !T.Text
|
|
||||||
} deriving (Eq, Prelude.Show)
|
} deriving (Eq, Prelude.Show)
|
||||||
|
|
||||||
data ZcashPool
|
data ZcashPool
|
||||||
|
@ -191,7 +153,6 @@ data ZcashWalletAPI = ZcashWalletAPI
|
||||||
, zw_network :: !ZcashNet
|
, zw_network :: !ZcashNet
|
||||||
, zw_birthday :: !Int
|
, zw_birthday :: !Int
|
||||||
, zw_lastSync :: !Int
|
, zw_lastSync :: !Int
|
||||||
, zw_local :: !Bool
|
|
||||||
} deriving (Eq, Prelude.Show)
|
} deriving (Eq, Prelude.Show)
|
||||||
|
|
||||||
$(deriveJSON defaultOptions {fieldLabelModifier = drop 3} ''ZcashWalletAPI)
|
$(deriveJSON defaultOptions {fieldLabelModifier = drop 3} ''ZcashWalletAPI)
|
||||||
|
@ -200,7 +161,6 @@ data ZcashAccountAPI = ZcashAccountAPI
|
||||||
{ za_index :: !Int
|
{ za_index :: !Int
|
||||||
, za_wallet :: !Int
|
, za_wallet :: !Int
|
||||||
, za_name :: !T.Text
|
, za_name :: !T.Text
|
||||||
, za_type :: !AccountType
|
|
||||||
} deriving (Eq, Prelude.Show)
|
} deriving (Eq, Prelude.Show)
|
||||||
|
|
||||||
$(deriveJSON defaultOptions {fieldLabelModifier = drop 3} ''ZcashAccountAPI)
|
$(deriveJSON defaultOptions {fieldLabelModifier = drop 3} ''ZcashAccountAPI)
|
||||||
|
@ -547,19 +507,3 @@ 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)
|
|
||||||
|
|
||||||
-- | Define a data structure for the URI QR image
|
|
||||||
data URIQrCode = URIQrCode
|
|
||||||
{ uriBytes :: BS.ByteString -- Image as ByteString
|
|
||||||
, uriWidth :: Double -- Number of columns in QR Image
|
|
||||||
, uriHeight :: Double -- Number of rows in a QR Image
|
|
||||||
} deriving (Show, Eq)
|
|
||||||
|
|
|
@ -2,32 +2,16 @@
|
||||||
|
|
||||||
module Zenith.Utils where
|
module Zenith.Utils where
|
||||||
|
|
||||||
import Control.Exception (SomeException, try)
|
|
||||||
import Control.Monad (when)
|
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import qualified Data.Aeson.Key as K
|
|
||||||
import qualified Data.Aeson.KeyMap as KM
|
|
||||||
import Data.Aeson.Types (parseMaybe)
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
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, scientific, toRealFloat)
|
import Data.Scientific (Scientific(..), scientific)
|
||||||
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 qualified Data.Text.Encoding as TE
|
|
||||||
import Network.HTTP.Simple
|
|
||||||
import Network.URI (escapeURIString, isUnreserved)
|
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import System.Process (createProcess_, shell)
|
import System.Process (createProcess_, shell)
|
||||||
import Text.Printf (printf)
|
|
||||||
import Text.Read (readMaybe)
|
|
||||||
import Text.Regex.Posix
|
import Text.Regex.Posix
|
||||||
import ZcashHaskell.Orchard
|
import ZcashHaskell.Orchard
|
||||||
( encodeUnifiedAddress
|
( encodeUnifiedAddress
|
||||||
|
@ -41,13 +25,10 @@ import ZcashHaskell.Transparent
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
( ExchangeAddress(..)
|
( ExchangeAddress(..)
|
||||||
, ExchangeAddress(..)
|
|
||||||
, Phrase(..)
|
|
||||||
, SaplingAddress(..)
|
, SaplingAddress(..)
|
||||||
, TransparentAddress(..)
|
, TransparentAddress(..)
|
||||||
, UnifiedAddress(..)
|
, UnifiedAddress(..)
|
||||||
, ValidAddress(..)
|
, ValidAddress(..)
|
||||||
, ValidAddress(..)
|
|
||||||
, ZcashNet(..)
|
, ZcashNet(..)
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Utils (makeZebraCall)
|
import ZcashHaskell.Utils (makeZebraCall)
|
||||||
|
@ -56,7 +37,6 @@ import Zenith.Types
|
||||||
, PrivacyPolicy(..)
|
, PrivacyPolicy(..)
|
||||||
, UnifiedAddressDB(..)
|
, UnifiedAddressDB(..)
|
||||||
, ZcashAddress(..)
|
, ZcashAddress(..)
|
||||||
, ZcashPaymentURI(..)
|
|
||||||
, ZcashPool(..)
|
, ZcashPool(..)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -72,7 +52,7 @@ displayZec s
|
||||||
| abs s < 100000000 = show (fromIntegral s / 100000) ++ " mZEC"
|
| abs s < 100000000 = show (fromIntegral s / 100000) ++ " mZEC"
|
||||||
| otherwise = show (fromIntegral s / 100000000) ++ " ZEC "
|
| otherwise = show (fromIntegral s / 100000000) ++ " ZEC "
|
||||||
|
|
||||||
-- | Helper function to display small amounts of TAZ
|
-- | Helper function to display small amounts of ZEC
|
||||||
displayTaz :: Integer -> String
|
displayTaz :: Integer -> String
|
||||||
displayTaz s
|
displayTaz s
|
||||||
| abs s < 100 = show s ++ " tazs"
|
| abs s < 100 = show s ++ " tazs"
|
||||||
|
@ -255,7 +235,7 @@ isValidString c = do
|
||||||
|
|
||||||
padWithZero :: Int -> String -> String
|
padWithZero :: Int -> String -> String
|
||||||
padWithZero n s
|
padWithZero n s
|
||||||
| length s >= n = s
|
| (length s) >= n = s
|
||||||
| otherwise = padWithZero n ("0" ++ s)
|
| otherwise = padWithZero n ("0" ++ s)
|
||||||
|
|
||||||
isEmpty :: [a] -> Bool
|
isEmpty :: [a] -> Bool
|
||||||
|
@ -268,119 +248,3 @@ getChainTip zHost zPort = do
|
||||||
case r of
|
case r of
|
||||||
Left e1 -> pure 0
|
Left e1 -> pure 0
|
||||||
Right i -> pure i
|
Right i -> pure i
|
||||||
|
|
||||||
-- Function to fetch Zcash price from CoinGecko
|
|
||||||
getZcashPrice :: T.Text -> IO (Maybe Double)
|
|
||||||
getZcashPrice currency = do
|
|
||||||
let url =
|
|
||||||
"https://api.coingecko.com/api/v3/simple/price?ids=zcash&vs_currencies=" <>
|
|
||||||
T.unpack currency
|
|
||||||
response <- httpJSONEither (parseRequest_ url)
|
|
||||||
case getResponseBody response of
|
|
||||||
Right (Object obj)
|
|
||||||
-- Extract "zcash" object
|
|
||||||
-> do
|
|
||||||
case KM.lookup "zcash" obj of
|
|
||||||
Just (Object zcashObj)
|
|
||||||
-- Extract the currency price
|
|
||||||
->
|
|
||||||
case KM.lookup (K.fromText (T.toLower currency)) zcashObj of
|
|
||||||
Just (Number price) -> return (Just (toRealFloat price))
|
|
||||||
_ -> 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
|
|
||||||
|
|
||||||
-- Function to encode memo as un-padded Base64
|
|
||||||
encodeBase64Memo :: String -> String
|
|
||||||
encodeBase64Memo = BC.unpack . BC.takeWhile (/= '=') . B64.encode . BC.pack
|
|
||||||
|
|
||||||
-- Function to drop trailing zeros
|
|
||||||
dropTrailingZeros :: String -> String
|
|
||||||
dropTrailingZeros str =
|
|
||||||
let withoutZeros = reverse (dropWhile (== '0') (reverse str))
|
|
||||||
in if last withoutZeros == '.'
|
|
||||||
then withoutZeros ++ "0" -- Ensure at least one decimal place
|
|
||||||
else withoutZeros
|
|
||||||
|
|
||||||
-- Function to create a ZIP-321 URI
|
|
||||||
createZip321 :: String -> Maybe Double -> Maybe String -> String
|
|
||||||
createZip321 address mAmount mMemo =
|
|
||||||
"zcash:" ++
|
|
||||||
address ++
|
|
||||||
maybe
|
|
||||||
""
|
|
||||||
(\amount -> "?amount=" ++ dropTrailingZeros (printf "%.8f" amount))
|
|
||||||
mAmount ++
|
|
||||||
maybe
|
|
||||||
""
|
|
||||||
(\memo -> "&memo=" ++ escapeURIString isUnreserved (encodeBase64Memo memo))
|
|
||||||
mMemo
|
|
||||||
|
|
||||||
getTransparentFromUA :: UnifiedAddress -> Maybe TransparentAddress
|
|
||||||
getTransparentFromUA ua = TransparentAddress (ua_net ua) <$> t_rec ua
|
|
||||||
|
|
||||||
-- Function to check if Text is non-empty after trimming leading spaces
|
|
||||||
isNotEmptyAfterTrim :: T.Text -> Bool
|
|
||||||
isNotEmptyAfterTrim txt = not (T.null (T.stripStart txt))
|
|
||||||
|
|
||||||
-- Function to convert a Scientific number to Int
|
|
||||||
scientificToInt :: Scientific -> Int
|
|
||||||
scientificToInt sc = fromIntegral $ round $ toRealFloat sc
|
|
||||||
|
|
||||||
-- Convert a ByteString to Phrase
|
|
||||||
toPhrase :: BS.ByteString -> Phrase
|
|
||||||
toPhrase = Phrase
|
|
||||||
|
|
|
@ -38,8 +38,7 @@ import Zenith.RPC
|
||||||
, zenithServer
|
, zenithServer
|
||||||
)
|
)
|
||||||
import Zenith.Types
|
import Zenith.Types
|
||||||
( AccountType(..)
|
( Config(..)
|
||||||
, Config(..)
|
|
||||||
, PrivacyPolicy(..)
|
, PrivacyPolicy(..)
|
||||||
, ProposedNote(..)
|
, ProposedNote(..)
|
||||||
, ValidAddressAPI(..)
|
, ValidAddressAPI(..)
|
||||||
|
@ -59,16 +58,7 @@ 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"
|
||||||
currencyCode <- require config "currencyCode"
|
let myConfig = Config dbFilePath zebraHost zebraPort nodeUser nodePwd nodePort
|
||||||
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
|
||||||
|
@ -96,7 +86,7 @@ main = do
|
||||||
Left e -> assertFailure e
|
Left e -> assertFailure e
|
||||||
Right r ->
|
Right r ->
|
||||||
r `shouldBe`
|
r `shouldBe`
|
||||||
InfoResponse "zh" (ZenithInfo "0.8.0.0-beta" TestNet "v2.1.0")
|
InfoResponse "zh" (ZenithInfo "0.7.0.0-beta" TestNet "v1.9.0")
|
||||||
describe "Wallets" $ do
|
describe "Wallets" $ do
|
||||||
describe "listwallet" $ do
|
describe "listwallet" $ do
|
||||||
it "bad credentials" $ do
|
it "bad credentials" $ do
|
||||||
|
@ -308,9 +298,7 @@ main = do
|
||||||
Left e -> assertFailure e
|
Left e -> assertFailure e
|
||||||
Right r ->
|
Right r ->
|
||||||
r `shouldBe`
|
r `shouldBe`
|
||||||
AccountListResponse
|
AccountListResponse "zh" [ZcashAccountAPI 1 1 "Personal"]
|
||||||
"zh"
|
|
||||||
[ZcashAccountAPI 1 1 "Personal" Local]
|
|
||||||
describe "Addresses" $ do
|
describe "Addresses" $ do
|
||||||
describe "listaddresses" $ do
|
describe "listaddresses" $ do
|
||||||
it "bad credentials" $ do
|
it "bad credentials" $ do
|
||||||
|
@ -688,204 +676,6 @@ main = do
|
||||||
case res of
|
case res of
|
||||||
Left e -> assertFailure e
|
Left e -> assertFailure e
|
||||||
Right (SendResponse i o) -> o `shouldNotBe` U.nil
|
Right (SendResponse i o) -> o `shouldNotBe` U.nil
|
||||||
describe "Shield notes" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
ShieldNotes
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no parameters" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ShieldNotes
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "invalid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ShieldNotes
|
|
||||||
(ShieldNotesParams 27)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32006)
|
|
||||||
it "valid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ShieldNotes
|
|
||||||
(ShieldNotesParams 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (MultiOpResponse i c) -> c `shouldNotBe` []
|
|
||||||
describe "Viewing Keys" $ do
|
|
||||||
describe "Full" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
GetFVK
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no parameters" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetFVK
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "invalid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetFVK
|
|
||||||
(ViewingKeyParams 27)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32006)
|
|
||||||
it "valid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetFVK
|
|
||||||
(ViewingKeyParams 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ViewingKeyResponse i c) -> c `shouldNotBe` ""
|
|
||||||
Right x -> assertFailure $ show x
|
|
||||||
describe "Incoming" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
GetIVK
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no parameters" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetIVK
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "invalid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetIVK
|
|
||||||
(ViewingKeyParams 27)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32006)
|
|
||||||
it "valid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetIVK
|
|
||||||
(ViewingKeyParams 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ViewingKeyResponse i c) -> c `shouldNotBe` ""
|
|
||||||
Right x -> assertFailure $ show x
|
|
||||||
describe "Importing" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
ImportVK
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no parameters" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ImportVK
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "correct params" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ImportVK
|
|
||||||
(ImportVkParams
|
|
||||||
"OldWallet"
|
|
||||||
"uviewtest1jna46ql5qns5rlg99jgs6mhf0j9tk8zxvqsm472scgvmj0vs0rqv2kvdf626gftx7dgn2tltyf0s200gvjlsdvz5celpue9wxxw78txswqmayxc3pfrt5fs5frvr3ep0jrjg8euahqzc63yx9sy4z8lql4ev6q3asptl9rhsfzzrup2g5slwnlvy3dgft44jw3l08xtzypjmsrwxskgnp5s03xlc2kg5520a25pa6fdjxhzutam4wkwr6mh4zeq3qndpks8dk0y90y7gucgsp0j5k2xnhh90m3krk5glz4794dj93pf59h85dqms6337f85ccvpxhays94kvsj2hyjsltf52tygqs8y0vp2yf39drxl687the6xkp8nxkfffc3kqlkhw53t5plplde0vk9rwv340ys04gg48fs0pxfp35rvt2f2pvxjmgmln6lp5k2yzkm0r87k89p6xqv68a6uyfpsauswh9fsckfqey02pjedz5gs934qa"
|
|
||||||
3249286)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (NewItemResponse i k) -> k `shouldSatisfy` (> 0)
|
|
||||||
it "list wallets" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListWallets
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (WalletListResponse i k) -> length k `shouldBe` 2
|
|
||||||
|
|
||||||
startAPI :: Config -> IO ()
|
startAPI :: Config -> IO ()
|
||||||
startAPI config = do
|
startAPI config = do
|
||||||
|
@ -904,7 +694,7 @@ startAPI config = do
|
||||||
case bc of
|
case bc of
|
||||||
Left e1 -> throwIO e1
|
Left e1 -> throwIO e1
|
||||||
Right chainInfo -> do
|
Right chainInfo -> do
|
||||||
x <- runNoLoggingT $ initDb "test.db"
|
x <- initDb "test.db"
|
||||||
case x of
|
case x of
|
||||||
Left e2 -> throwIO $ userError e2
|
Left e2 -> throwIO $ userError e2
|
||||||
Right x' -> do
|
Right x' -> do
|
||||||
|
|
77
test/Spec.hs
77
test/Spec.hs
|
@ -9,7 +9,6 @@ import qualified Data.ByteString.Lazy as LBS
|
||||||
import Data.HexString
|
import Data.HexString
|
||||||
import Data.List (foldl')
|
import Data.List (foldl')
|
||||||
import Data.Maybe (fromJust)
|
import Data.Maybe (fromJust)
|
||||||
import qualified Data.Text as T
|
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
import Database.Persist.Sqlite
|
import Database.Persist.Sqlite
|
||||||
|
@ -70,7 +69,6 @@ import Zenith.Core
|
||||||
import Zenith.DB
|
import Zenith.DB
|
||||||
import Zenith.Tree
|
import Zenith.Tree
|
||||||
import Zenith.Types
|
import Zenith.Types
|
||||||
import Zenith.Utils
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
@ -645,7 +643,8 @@ 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 <- runNoLoggingT $ truncateTree oTree i
|
updatedTree <-
|
||||||
|
runFileLoggingT "test.log" $ truncateTree oTree i
|
||||||
let finalAnchor =
|
let finalAnchor =
|
||||||
getOrchardTreeAnchor $
|
getOrchardTreeAnchor $
|
||||||
OrchardCommitmentTree $ ztiOrchard zebraTreesIn
|
OrchardCommitmentTree $ ztiOrchard zebraTreesIn
|
||||||
|
@ -738,7 +737,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -764,7 +763,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -788,7 +787,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -816,7 +815,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -848,7 +847,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -874,7 +873,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -898,7 +897,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -927,7 +926,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -958,7 +957,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -984,7 +983,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -1008,7 +1007,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -1035,7 +1034,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -1062,7 +1061,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -1087,7 +1086,7 @@ main = do
|
||||||
Just ua -> do
|
Just ua -> do
|
||||||
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db"
|
||||||
tx <-
|
tx <-
|
||||||
runNoLoggingT $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTxV2
|
prepareTxV2
|
||||||
pool
|
pool
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -1104,47 +1103,3 @@ main = do
|
||||||
case tx of
|
case tx of
|
||||||
Left e -> assertFailure $ show e
|
Left e -> assertFailure $ show e
|
||||||
Right h -> h `shouldNotBe` hexString "deadbeef"
|
Right h -> h `shouldNotBe` hexString "deadbeef"
|
||||||
describe "Call CoinGecko to get ZEC price" $ do
|
|
||||||
it "Testing for USD " $ do
|
|
||||||
price <- getZcashPrice $ T.pack "usd"
|
|
||||||
case price of
|
|
||||||
Just p -> p `shouldNotBe` 0.0
|
|
||||||
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
|
|
||||||
describe "Create a ZIP-321 URI payment string " $ do
|
|
||||||
it "Creating an URI using a valid Zcash address, an amount, and a memo " $ do
|
|
||||||
let address =
|
|
||||||
"ztestsapling10yy2ex5dcqkclhc7z7yrnjq2z6feyjad56ptwlfgmy77dmaqqrl9gyhprdx59qgmsnyfska2kez"
|
|
||||||
let amount = Just 1.2345
|
|
||||||
let memo = Just "This is a simple memo."
|
|
||||||
let uriString = createZip321 address amount memo
|
|
||||||
print uriString
|
|
||||||
uriString `shouldBe`
|
|
||||||
"zcash:ztestsapling10yy2ex5dcqkclhc7z7yrnjq2z6feyjad56ptwlfgmy77dmaqqrl9gyhprdx59qgmsnyfska2kez?amount=1.2345&memo=VGhpcyBpcyBhIHNpbXBsZSBtZW1vLg"
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0d042d639d471af14ebe94707f64b5ff5c2cb5eb
|
Subproject commit d45bd7dcf3c3cf4e893900a1774d24b14bf56591
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"openrpc": "1.0.0-rc1",
|
"openrpc": "1.0.0-rc1",
|
||||||
"info": {
|
"info": {
|
||||||
"version": "0.9.0.0-beta",
|
"version": "0.7.0.0-beta",
|
||||||
"title": "Zenith RPC",
|
"title": "Zenith RPC",
|
||||||
"description": "The RPC methods to interact with the Zenith Zcash wallet",
|
"description": "The RPC methods to interact with the Zenith Zcash wallet",
|
||||||
"license": {
|
"license": {
|
||||||
|
@ -230,8 +230,7 @@
|
||||||
{ "$ref": "#/components/errors/ZebraNotAvailable" },
|
{ "$ref": "#/components/errors/ZebraNotAvailable" },
|
||||||
{ "$ref": "#/components/errors/DuplicateName" },
|
{ "$ref": "#/components/errors/DuplicateName" },
|
||||||
{ "$ref": "#/components/errors/ZenithBusy" },
|
{ "$ref": "#/components/errors/ZenithBusy" },
|
||||||
{ "$ref": "#/components/errors/InvalidWallet" },
|
{ "$ref": "#/components/errors/InvalidWallet" }
|
||||||
{ "$ref": "#/components/errors/NotLocal" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -497,8 +496,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"errors": [
|
"errors": [
|
||||||
{ "$ref": "#/components/errors/InvalidAccount" },
|
{ "$ref": "#/components/errors/InvalidAccount" }
|
||||||
{ "$ref": "#/components/errors/ReadOnly" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -607,9 +605,10 @@
|
||||||
],
|
],
|
||||||
"paramStructure": "by-position",
|
"paramStructure": "by-position",
|
||||||
"result": {
|
"result": {
|
||||||
"name": "Operation ID",
|
"name": "Operation ID(s)",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/contentDescriptors/OperationId"
|
"type": "array",
|
||||||
|
"items": { "$ref": "#/components/contentDescriptors/OperationId"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"examples": [
|
"examples": [
|
||||||
|
@ -621,7 +620,7 @@
|
||||||
{
|
{
|
||||||
"name": "Account index",
|
"name": "Account index",
|
||||||
"summary": "The index for the account to use",
|
"summary": "The index for the account to use",
|
||||||
"value": 1
|
"value": "1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Privacy Policy",
|
"name": "Privacy Policy",
|
||||||
|
@ -642,16 +641,16 @@
|
||||||
],
|
],
|
||||||
"result": {
|
"result": {
|
||||||
"name": "SendMany result",
|
"name": "SendMany result",
|
||||||
"value": "3cc31c07-07cf-4a6e-9190-156c4b8c4088"
|
"value": [
|
||||||
|
"3cc31c07-07cf-4a6e-9190-156c4b8c4088"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"errors": [
|
"errors": [
|
||||||
{ "$ref": "#/components/errors/ZebraNotAvailable" },
|
{ "$ref": "#/components/errors/ZebraNotAvailable" },
|
||||||
{ "$ref": "#/components/errors/ZenithBusy" },
|
{ "$ref": "#/components/errors/ZenithBusy" },
|
||||||
{ "$ref": "#/components/errors/InvalidAccount" },
|
{ "$ref": "#/components/errors/InvalidAccount" }
|
||||||
{ "$ref": "#/components/errors/ReadOnly" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -670,226 +669,6 @@
|
||||||
"errors": [
|
"errors": [
|
||||||
{ "$ref": "#/components/errors/OpNotFound" }
|
{ "$ref": "#/components/errors/OpNotFound" }
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "shieldnotes",
|
|
||||||
"summary": "Shield all transparent notes into the Orchard pool for the given account",
|
|
||||||
"description": "Creates one or more transactions, grouping all the unspent transparent notes for the given account by their transparent address to avoid associating different transparent addresses. These notes are sent to the given account's internal change address as shielded Orchard notes.",
|
|
||||||
"tags": [],
|
|
||||||
"params": [
|
|
||||||
{ "$ref": "#/components/contentDescriptors/AccountId"}
|
|
||||||
],
|
|
||||||
"paramStructure": "by-position",
|
|
||||||
"result": {
|
|
||||||
"name": "Operation ID(s)",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": { "$ref": "#/components/contentDescriptors/OperationId"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"examples": [
|
|
||||||
{
|
|
||||||
"name": "Shield transparent notes",
|
|
||||||
"summary": "Shield transparent notes",
|
|
||||||
"description": "Shield the transparent notes in a given account",
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"name": "Account index",
|
|
||||||
"summary": "The index for the account to use",
|
|
||||||
"value": "3"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"result": {
|
|
||||||
"name": "ShieldNotes result",
|
|
||||||
"value": [
|
|
||||||
"ab350df0-9f57-44c0-9e0d-f7b8af1f4231",
|
|
||||||
"8c6f2656-22ef-4f9d-b465-80ddd13fc485"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "No transparent funds",
|
|
||||||
"summary": "Shield transparent notes with no transparent funds",
|
|
||||||
"description": "Attempt to shield the transparent notes in a given account, when account has none",
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"name": "Account index",
|
|
||||||
"summary": "The index for the account to use",
|
|
||||||
"value": "3"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"result": {
|
|
||||||
"name": "ShieldNotes result",
|
|
||||||
"value": [
|
|
||||||
"InsufficientFunds"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"errors": [
|
|
||||||
{ "$ref": "#/components/errors/ZebraNotAvailable" },
|
|
||||||
{ "$ref": "#/components/errors/ZenithBusy" },
|
|
||||||
{ "$ref": "#/components/errors/InvalidAccount" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "deshieldfunds",
|
|
||||||
"summary": "De-shield the given amount of ZEC from the given account",
|
|
||||||
"description": "Creates a new internal transaction with the requested amount of ZEC to the transparent pool. The fee is not included in the given amount.",
|
|
||||||
"tags": [],
|
|
||||||
"params": [
|
|
||||||
{ "$ref": "#/components/contentDescriptors/AccountId"},
|
|
||||||
{ "$ref": "#/components/contentDescriptors/Amount"}
|
|
||||||
],
|
|
||||||
"paramStructure": "by-position",
|
|
||||||
"result": {
|
|
||||||
"name": "Operation ID",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/contentDescriptors/OperationId"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"examples": [
|
|
||||||
{
|
|
||||||
"name": "De-Shield funds",
|
|
||||||
"summary": "De-shield funds",
|
|
||||||
"description": "Move the given amount of ZEC for the given acount from the shielded pool to the transparent pool",
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"name": "Account index",
|
|
||||||
"summary": "The index for the account to use",
|
|
||||||
"value": "3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Amount",
|
|
||||||
"summary": "The amount of ZEC to use",
|
|
||||||
"value": 1.23
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"result": {
|
|
||||||
"name": "Deshield funds result",
|
|
||||||
"value": "ab350df0-9f57-44c0-9e0d-f7b8af1f4231"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "No transparent funds",
|
|
||||||
"summary": "Shield transparent notes with no transparent funds",
|
|
||||||
"description": "Attempt to shield the transparent notes in a given account, when account has none",
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"name": "Account index",
|
|
||||||
"summary": "The index for the account to use",
|
|
||||||
"value": "3"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"result": {
|
|
||||||
"name": "ShieldNotes result",
|
|
||||||
"value": [
|
|
||||||
"InsufficientFunds"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"errors": [
|
|
||||||
{ "$ref": "#/components/errors/ZebraNotAvailable" },
|
|
||||||
{ "$ref": "#/components/errors/ZenithBusy" },
|
|
||||||
{ "$ref": "#/components/errors/InvalidAccount" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "getfullvk",
|
|
||||||
"summary": "Derive the full viewing key for the given account.",
|
|
||||||
"description": "Derive the full viewing key for the given account, encoded per ZIP-316.",
|
|
||||||
"tags": [],
|
|
||||||
"params": [
|
|
||||||
{ "$ref": "#/components/contentDescriptors/AccountId"}
|
|
||||||
],
|
|
||||||
"paramStructure": "by-position",
|
|
||||||
"result": {
|
|
||||||
"name": "Full viewing key",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/ViewingKey"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"examples": [
|
|
||||||
{
|
|
||||||
"name": "Get full viewing key",
|
|
||||||
"summary": "Get the full viewing key",
|
|
||||||
"description": "Get the full viewing key for the give account, encoded per ZIP-316",
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"name": "Account index",
|
|
||||||
"summary": "The index for the account to use",
|
|
||||||
"value": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"result": {
|
|
||||||
"name": "Full Viewing key",
|
|
||||||
"value": "uview16qdhd9e283s4y53gmw72ag7adzdrj9f9v96dw89ggv9el0yrf7vkappau69j8luq7uf540sr78ncslnqk6kwpc4qeqgfg5vn4xcmllynyfr32cgq6nx5ptku44kfxtsj99px2g9yp7kyc32quun0elakgltqmqflprwmryuelcfwwt58vqap065as7qwljg02l6mkutsh2y9aefd284dsrj0246fd2n4hra3r03uftsh4njh3w590z78tpnfqhjvvwhgus476zrw3fd69qekru709ghr0zr7h8majy9aclwg7uhakt24lmuec8dd7t270kamcs99rz8jasj3jl6m9y77dvkdn23e2kwuc6kyagpstzrdjnlzdldmgsu4k056v80ucajcjvl99pcf2znjg37vztdp4zr5qrphxs4y7wppxmankmdwwgjxhlmyrjd68z80q0n0t2cyqge6mlc7pd5wre4392pjtdaqvtyeg0denh4ekynnjxnm"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"errors": [
|
|
||||||
{ "$ref": "#/components/errors/InvalidAccount" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "getincomingvk",
|
|
||||||
"summary": "Get the incoming viewing key for the given account.",
|
|
||||||
"description": "Derives the incoming viewing key for the given account per ZIP-316.",
|
|
||||||
"tags": [],
|
|
||||||
"params": [
|
|
||||||
{ "$ref": "#/components/contentDescriptors/AccountId"}
|
|
||||||
],
|
|
||||||
"paramStructure": "by-position",
|
|
||||||
"result": {
|
|
||||||
"name": "Incoming viewing key",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/ViewingKey"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"examples": [
|
|
||||||
{
|
|
||||||
"name": "Get incoming viewing key",
|
|
||||||
"summary": "Get the incoming viewing key",
|
|
||||||
"description": "Get the incoming viewing key for the give account, encoded per ZIP-316",
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"name": "Account index",
|
|
||||||
"summary": "The index for the account to use",
|
|
||||||
"value": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"result": {
|
|
||||||
"name": "Incoming Viewing key",
|
|
||||||
"value": "uivk199qcjxrj73n7fapg79a2ltah6f3j83haljcux5t5kvn5unn7rpfmvglttdt9g6na3llkefnd3pn0x9ky6lh8s42trj0vfg5wtv0nrerq0wsq5v4q7lt5j4l9svppspr6h7407ztgsuvkfk977c3tj408nx5phxap8fn3ecdmdrah9spp76md9tel89tuqz6m0xplqp83wj33qf7s3hwfe79t04rq49g24nr3emlpm298wpqla2dvh4rr584kwdtxc9ahse5x0drcjr95tt4k0hxr32l6yturje7dptlgjnr4cm6uk29ysu9l5xwgz40p6alyedzzqltqf5nswy48ekru4ahapw"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"errors": [
|
|
||||||
{ "$ref": "#/components/errors/InvalidAccount" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "importvk",
|
|
||||||
"summary": "Import the given Unified Viewing Key",
|
|
||||||
"description": "Imports the given Unified Viewing Key, autodetecting if it is Full or Incoming. Caution: If the given birthday height is lower than the lowest birthday height in the wallet, this will trigger a full re-scan of the wallet.",
|
|
||||||
"tags": [
|
|
||||||
],
|
|
||||||
"params": [
|
|
||||||
{ "$ref": "#/components/contentDescriptors/Name"},
|
|
||||||
{ "$ref": "#/components/contentDescriptors/ViewingKey"},
|
|
||||||
{ "$ref": "#/components/contentDescriptors/BirthdayHeight"}
|
|
||||||
],
|
|
||||||
"paramStructure": "by-position",
|
|
||||||
"result": {
|
|
||||||
"name": "Account Identifier",
|
|
||||||
"schema": { "$ref": "#/components/contentDescriptors/AccountId"}
|
|
||||||
},
|
|
||||||
"errors": [
|
|
||||||
{ "$ref": "#/components/errors/ZebraNotAvailable" },
|
|
||||||
{ "$ref": "#/components/errors/DuplicateName" },
|
|
||||||
{ "$ref": "#/components/errors/ZenithBusy" }
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"components": {
|
"components": {
|
||||||
|
@ -921,15 +700,6 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Amount": {
|
|
||||||
"name": "A numeric amount",
|
|
||||||
"summary": "A numeric amount",
|
|
||||||
"description": "A number that represents an amount to be used by a function as an input",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Name": {
|
"Name": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"summary": "A user-friendly name",
|
"summary": "A user-friendly name",
|
||||||
|
@ -985,24 +755,6 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["None", "Low", "Medium", "Full"]
|
"enum": ["None", "Low", "Medium", "Full"]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"BirthdayHeight": {
|
|
||||||
"name": "Birthday Height",
|
|
||||||
"summary": "The block height at which a wallet was created.",
|
|
||||||
"description": "The block height where a wallet was created. The wallet will not scan blocks at a lower block height than this, assuming there are no transactions on-chain before this point.",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ViewingKey": {
|
|
||||||
"name": "Viewing Key",
|
|
||||||
"summary": "A Unified viewing key.",
|
|
||||||
"description": "A Unified viewing key encoded per [ZIP-316](https://zips.z.cash/zip-0316). Zenith supports both full and incoming viewing keys.",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schemas": {
|
"schemas": {
|
||||||
|
@ -1021,8 +773,7 @@
|
||||||
"name": { "type": "string", "description": "User-friendly name of the wallet" },
|
"name": { "type": "string", "description": "User-friendly name of the wallet" },
|
||||||
"network": { "type": "string", "description": "Network the wallet is for. Testnet or MainNet" },
|
"network": { "type": "string", "description": "Network the wallet is for. Testnet or MainNet" },
|
||||||
"birthday": { "type": "integer", "description": "Wallet's birthday height" },
|
"birthday": { "type": "integer", "description": "Wallet's birthday height" },
|
||||||
"lastSync": { "type": "integer", "description": "Last block the wallet is synced to" },
|
"lastSync": { "type": "integer", "description": "Last block the wallet is synced to" }
|
||||||
"local": { "type": "boolean", "description": "True for wallets belonging to this Zenith instance, False for wallets created to manage viewing keys"}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ZcashAccount": {
|
"ZcashAccount": {
|
||||||
|
@ -1030,8 +781,7 @@
|
||||||
"properties": {
|
"properties": {
|
||||||
"index": { "type": "integer", "description": "Internal index for account"},
|
"index": { "type": "integer", "description": "Internal index for account"},
|
||||||
"wallet": { "type": "integer", "description": "ID of the wallet this account belongs to"},
|
"wallet": { "type": "integer", "description": "ID of the wallet this account belongs to"},
|
||||||
"name": { "type": "string", "description": "User-friendly name of the account"},
|
"name": { "type": "string", "description": "User-friendly name of the account"}
|
||||||
"type": { "type": "string", "description": "Local for accounts belonging to the wallet, FullViewKey for full viewing keys, IncomingViewKey for incoming"}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ZcashAddress": {
|
"ZcashAddress": {
|
||||||
|
@ -1085,10 +835,6 @@
|
||||||
"amount": { "type": "number", "description": "The amount to send in ZEC"},
|
"amount": { "type": "number", "description": "The amount to send in ZEC"},
|
||||||
"memo": { "type": "string", "description": "The shielded memo to include, if applicable"}
|
"memo": { "type": "string", "description": "The shielded memo to include, if applicable"}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"ViewingKey": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The viewing key, encoded per ZIP-316"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"examples": {},
|
"examples": {},
|
||||||
|
@ -1148,18 +894,6 @@
|
||||||
"ZenithBusy": {
|
"ZenithBusy": {
|
||||||
"code": -32012,
|
"code": -32012,
|
||||||
"message": "The Zenith server is syncing, please try again later."
|
"message": "The Zenith server is syncing, please try again later."
|
||||||
},
|
|
||||||
"InvalidVK": {
|
|
||||||
"code": -32013,
|
|
||||||
"message": "The viewing key provided is not valid."
|
|
||||||
},
|
|
||||||
"ReadOnly": {
|
|
||||||
"code": -32014,
|
|
||||||
"message": "Read-only account, operation is not valid."
|
|
||||||
},
|
|
||||||
"NotLocal": {
|
|
||||||
"code": -32015,
|
|
||||||
"message": "The wallet is not local, cannot create new accounts."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
cabal-version: 3.0
|
cabal-version: 3.0
|
||||||
name: zenith
|
name: zenith
|
||||||
version: 0.9.1.0-beta
|
version: 0.7.0.0-beta
|
||||||
license: MIT
|
license: MIT
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Rene Vergara
|
author: Rene Vergara
|
||||||
|
@ -96,8 +96,6 @@ library
|
||||||
, vty-crossplatform
|
, vty-crossplatform
|
||||||
, word-wrap
|
, word-wrap
|
||||||
, zcash-haskell
|
, zcash-haskell
|
||||||
, unordered-containers
|
|
||||||
, network-uri
|
|
||||||
--pkgconfig-depends: rustzcash_wrapper
|
--pkgconfig-depends: rustzcash_wrapper
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
|
41
zenith.cfg
41
zenith.cfg
|
@ -1,42 +1,5 @@
|
||||||
#
|
|
||||||
# Zenith Configuration File
|
|
||||||
#
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
# nodeUser -
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
nodeUser = "user"
|
nodeUser = "user"
|
||||||
# -------------------------------------------------------------
|
|
||||||
# nodePwd -
|
|
||||||
nodePwd = "superSecret"
|
nodePwd = "superSecret"
|
||||||
# -------------------------------------------------------------
|
dbFilePath = "zenith.db"
|
||||||
# nodePort -
|
|
||||||
nodePort = 8234
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
# nodePwd -
|
|
||||||
# dbFileName - contains the SQLite database name used for
|
|
||||||
# keeping all Zenith's data
|
|
||||||
# default = zenith.db
|
|
||||||
#
|
|
||||||
dbFileName = "zenith.db"
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
# zebraHost - Zebra IP
|
|
||||||
# Default - "127.0.0.1"
|
|
||||||
zebraHost = "127.0.0.1"
|
zebraHost = "127.0.0.1"
|
||||||
# -------------------------------------------------------------
|
zebraPort = 18232
|
||||||
# zebraPort - Port used for access Zebra API endpoints
|
|
||||||
# must be the same port configured for your
|
|
||||||
# Zebra node
|
|
||||||
zebraPort = 8232
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
# currencyCode - ISO 4217 currency code
|
|
||||||
#
|
|
||||||
# Example of currency codes are:
|
|
||||||
#
|
|
||||||
# United States -> currencyCode = "usd"
|
|
||||||
# Canada -> currencyCode = "cnd"
|
|
||||||
# Australia -> currencyCode = "aud"
|
|
||||||
# Euro Region -> currencyCode = "eur"
|
|
||||||
# Great Britain -> currencyCode = "gbp"
|
|
||||||
# Japan -> currencyCode = "jpy"
|
|
||||||
#
|
|
||||||
currencyCode = "usd"
|
|
||||||
|
|
BIN
zenith_er.bmp
Normal file
BIN
zenith_er.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.7 MiB |
BIN
zenith_er.png
Normal file
BIN
zenith_er.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 329 KiB |
Loading…
Add table
Reference in a new issue