P/L Calculations

This commit is contained in:
Hanh 2021-08-09 22:13:42 +08:00
parent 6508feaf85
commit d29127f729
12 changed files with 725 additions and 312 deletions

345
Cargo.lock generated
View File

@ -126,9 +126,9 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.50"
version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722"
checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e"
dependencies = [
"proc-macro2",
"quote",
@ -407,7 +407,7 @@ dependencies = [
"libc",
"num-integer",
"num-traits",
"time 0.1.43",
"time 0.1.44",
"winapi",
]
@ -526,9 +526,9 @@ dependencies = [
[[package]]
name = "criterion"
version = "0.3.4"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23"
checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
dependencies = [
"atty",
"cast",
@ -552,12 +552,12 @@ dependencies = [
[[package]]
name = "criterion-plot"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d"
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
dependencies = [
"cast",
"itertools 0.9.0",
"itertools 0.10.1",
]
[[package]]
@ -568,7 +568,7 @@ checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e"
dependencies = [
"cfg-if 0.1.10",
"crossbeam-channel 0.4.4",
"crossbeam-deque 0.7.3",
"crossbeam-deque 0.7.4",
"crossbeam-epoch 0.8.2",
"crossbeam-queue",
"crossbeam-utils 0.7.2",
@ -596,9 +596,9 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed"
dependencies = [
"crossbeam-epoch 0.8.2",
"crossbeam-utils 0.7.2",
@ -607,9 +607,9 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-epoch 0.9.5",
@ -816,6 +816,15 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "encoding_rs"
version = "0.8.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "endian-type"
version = "0.1.2"
@ -835,15 +844,6 @@ dependencies = [
"termcolor",
]
[[package]]
name = "equihash"
version = "0.1.0"
source = "git+https://github.com/hhanh00/zcash-params.git?branch=main#774d620a5df250cfd2dd4005e97c3088d4830c85"
dependencies = [
"blake2b_simd",
"byteorder",
]
[[package]]
name = "equihash"
version = "0.1.0"
@ -952,6 +952,16 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "fpe"
version = "0.4.0"
@ -1119,7 +1129,7 @@ checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
"wasi 0.10.0+wasi-snapshot-preview1",
]
[[package]]
@ -1257,9 +1267,9 @@ dependencies = [
[[package]]
name = "http-body"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9"
checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5"
dependencies = [
"bytes",
"http",
@ -1308,6 +1318,32 @@ dependencies = [
"want",
]
[[package]]
name = "hyper-rustls"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64"
dependencies = [
"futures-util",
"hyper",
"log",
"rustls",
"tokio",
"tokio-rustls",
"webpki",
]
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.7.0"
@ -1327,6 +1363,12 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "ipnet"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
[[package]]
name = "itertools"
version = "0.9.0"
@ -1353,9 +1395,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "js-sys"
version = "0.3.51"
version = "0.3.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
checksum = "ce791b7ca6638aae45be056e068fc756d871eb3b3b10b8efa62d1c9cec616752"
dependencies = [
"wasm-bindgen",
]
@ -1444,6 +1486,12 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "matches"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
name = "maybe-uninit"
version = "2.0.0"
@ -1480,6 +1528,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93c0d11ac30a033511ae414355d80f70d9f29a44a49140face477117a1ee90db"
[[package]]
name = "mime"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "miniz_oxide"
version = "0.4.4"
@ -1870,24 +1924,24 @@ dependencies = [
[[package]]
name = "protobuf"
version = "2.24.1"
version = "2.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db50e77ae196458ccd3dc58a31ea1a90b0698ab1b7928d89f644c25d72070267"
checksum = "020f86b07722c5c4291f7c723eac4676b3892d47d9a7708dc2779696407f039b"
[[package]]
name = "protobuf-codegen"
version = "2.24.1"
version = "2.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09321cef9bee9ddd36884f97b7f7cc92a586cdc74205c4b3aeba65b5fc9c6f90"
checksum = "7b8ac7c5128619b0df145d9bace18e8ed057f18aebda1aa837a5525d4422f68c"
dependencies = [
"protobuf",
]
[[package]]
name = "protobuf-codegen-pure"
version = "2.24.1"
version = "2.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1afb68a6d768571da3db86ce55f0f62966e0fc25eaf96acd070ea548a91b0d23"
checksum = "f6d0daa1b61d6e7a128cdca8c8604b3c5ee22c424c15c8d3a92fafffeda18aaf"
dependencies = [
"protobuf",
"protobuf-codegen",
@ -2012,7 +2066,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [
"autocfg",
"crossbeam-deque 0.8.0",
"crossbeam-deque 0.8.1",
"either",
"rayon-core",
]
@ -2024,7 +2078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [
"crossbeam-channel 0.5.1",
"crossbeam-deque 0.8.0",
"crossbeam-deque 0.8.1",
"crossbeam-utils 0.8.5",
"lazy_static",
"num_cpus",
@ -2032,9 +2086,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.2.9"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
"bitflags",
]
@ -2081,6 +2135,42 @@ dependencies = [
"winapi",
]
[[package]]
name = "reqwest"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22"
dependencies = [
"base64",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"http",
"http-body",
"hyper",
"hyper-rustls",
"ipnet",
"js-sys",
"lazy_static",
"log",
"mime",
"percent-encoding",
"pin-project-lite",
"rustls",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-rustls",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"webpki-roots",
"winreg",
]
[[package]]
name = "ring"
version = "0.16.20"
@ -2143,7 +2233,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver 1.0.3",
"semver 1.0.4",
]
[[package]]
@ -2288,9 +2378,9 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe"
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
[[package]]
name = "semver-parser"
@ -2300,9 +2390,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.126"
version = "1.0.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8"
dependencies = [
"serde_derive",
]
@ -2319,9 +2409,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.126"
version = "1.0.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc"
dependencies = [
"proc-macro2",
"quote",
@ -2330,15 +2420,27 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.64"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha1"
version = "0.6.0"
@ -2372,9 +2474,9 @@ dependencies = [
[[package]]
name = "slab"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590"
[[package]]
name = "smallvec"
@ -2384,9 +2486,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "socket2"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad"
dependencies = [
"libc",
"winapi",
@ -2510,6 +2612,7 @@ dependencies = [
"anyhow",
"bls12_381",
"byteorder",
"chrono",
"clap 3.0.0-beta.2",
"criterion",
"dotenv",
@ -2526,6 +2629,7 @@ dependencies = [
"protobuf",
"rand 0.8.4",
"rayon",
"reqwest",
"ripemd160",
"rusqlite",
"rustyline",
@ -2627,11 +2731,12 @@ dependencies = [
[[package]]
name = "time"
version = "0.1.43"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
@ -2932,6 +3037,15 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
[[package]]
name = "unicode-bidi"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0"
dependencies = [
"matches",
]
[[package]]
name = "unicode-normalization"
version = "0.1.19"
@ -2965,6 +3079,18 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "utf8parse"
version = "0.2.0"
@ -3034,25 +3160,27 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasm-bindgen"
version = "0.2.74"
version = "0.2.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586"
dependencies = [
"cfg-if 1.0.0",
"serde",
"serde_json",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.74"
version = "0.2.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f"
dependencies = [
"bumpalo",
"lazy_static",
@ -3064,10 +3192,22 @@ dependencies = [
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.74"
name = "wasm-bindgen-futures"
version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
checksum = "16646b21c3add8e13fdb8f20172f8a28c3dbf62f45406bcff0233188226cfe0c"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "171ebf0ed9e1458810dfcb31f2e766ad6b3a89dbda42d8901f2b268277e5f09c"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -3075,9 +3215,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.74"
version = "0.2.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
checksum = "6c2657dd393f03aa2a659c25c6ae18a13a4048cebd220e147933ea837efc589f"
dependencies = [
"proc-macro2",
"quote",
@ -3088,15 +3228,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.74"
version = "0.2.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2"
[[package]]
name = "web-sys"
version = "0.3.51"
version = "0.3.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
checksum = "01c70a82d842c9979078c772d4a1344685045f1a5628f677c2b2eab4dd7d2696"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3113,12 +3253,22 @@ dependencies = [
]
[[package]]
name = "which"
version = "4.1.0"
name = "webpki-roots"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b55551e42cbdf2ce2bedd2203d0cc08dba002c27510f86dab6d0ce304cba3dfe"
checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940"
dependencies = [
"webpki",
]
[[package]]
name = "which"
version = "4.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9"
dependencies = [
"either",
"lazy_static",
"libc",
]
@ -3153,6 +3303,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "winreg"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
dependencies = [
"winapi",
]
[[package]]
name = "wyz"
version = "0.2.0"
@ -3189,20 +3348,6 @@ dependencies = [
"zcash_primitives 0.5.0 (git+https://github.com/hhanh00/librustzcash.git?branch=warp-sync)",
]
[[package]]
name = "zcash_note_encryption"
version = "0.0.0"
source = "git+https://github.com/hhanh00/zcash-params.git?branch=main#774d620a5df250cfd2dd4005e97c3088d4830c85"
dependencies = [
"blake2b_simd",
"byteorder",
"crypto_api_chachapoly",
"ff",
"group",
"rand_core 0.6.3",
"subtle 2.4.1",
]
[[package]]
name = "zcash_note_encryption"
version = "0.0.0"
@ -3250,7 +3395,7 @@ dependencies = [
[[package]]
name = "zcash_params"
version = "0.1.0"
source = "git+https://github.com/hhanh00/zcash-params.git?branch=main#774d620a5df250cfd2dd4005e97c3088d4830c85"
source = "git+https://github.com/hhanh00/zcash-params.git?branch=main#d8bb59c1d137d7e2df3142b14aa9f8962ad68541"
dependencies = [
"bls12_381",
"byteorder",
@ -3261,35 +3406,7 @@ dependencies = [
"jubjub",
"lazy_static",
"rand 0.8.4",
"zcash_primitives 0.5.0 (git+https://github.com/hhanh00/zcash-params.git?branch=main)",
]
[[package]]
name = "zcash_primitives"
version = "0.5.0"
source = "git+https://github.com/hhanh00/zcash-params.git?branch=main#774d620a5df250cfd2dd4005e97c3088d4830c85"
dependencies = [
"aes",
"bitvec 0.20.4",
"blake2b_simd",
"blake2s_simd",
"bls12_381",
"byteorder",
"crypto_api_chachapoly",
"equihash 0.1.0 (git+https://github.com/hhanh00/zcash-params.git?branch=main)",
"ff",
"fpe",
"funty",
"group",
"hex",
"jubjub",
"lazy_static",
"log",
"rand 0.8.4",
"rand_core 0.6.3",
"sha2 0.9.5",
"subtle 2.4.1",
"zcash_note_encryption 0.0.0 (git+https://github.com/hhanh00/zcash-params.git?branch=main)",
"zcash_primitives 0.5.0 (git+ssh://git@github.com/hhanh00/librustzcash.git?branch=warp-sync)",
]
[[package]]

View File

@ -15,6 +15,7 @@ Future<void> showAbout(BuildContext context) async {
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text('About ZWallet'),
contentPadding: EdgeInsets.zero,
content: Container(
width: double.maxFinite,
child: Markdown(data: content),

View File

@ -4,7 +4,9 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:intl/intl.dart';
import 'package:local_auth/local_auth.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:warp/store.dart';
@ -39,7 +41,7 @@ class _AccountPageState extends State<AccountPage>
@override
initState() {
super.initState();
_tabController = TabController(length: 5, vsync: this);
_tabController = TabController(length: 6, vsync: this);
_tabController.addListener(() {
setState(() {
_accountTab = _tabController.index == 0;
@ -88,154 +90,157 @@ class _AccountPageState extends State<AccountPage>
final hasTAddr = accountManager.taddress.isNotEmpty;
final showTAddr = accountManager.showTAddr;
return Scaffold(
appBar: AppBar(
title: Observer(
builder: (context) =>
Text("\u24E9 Wallet - ${accountManager.active.name}")),
bottom: TabBar(controller: _tabController, isScrollable: true, tabs: [
Tab(text: "Account"),
Tab(text: "Notes"),
Tab(text: "History"),
Tab(text: "Budget"),
Tab(text: "Contacts"),
]),
actions: [
Observer(builder: (context) {
accountManager.canPay;
return PopupMenuButton<String>(
itemBuilder: (context) => [
PopupMenuItem(child: Text("Accounts"), value: "Accounts"),
PopupMenuItem(child: Text("Backup"), value: "Backup"),
PopupMenuItem(child: Text("Rescan"), value: "Rescan"),
if (accountManager.canPay)
PopupMenuItem(child: Text("Cold Storage"), value: "Cold"),
if (accountManager.canPay)
PopupMenuItem(child: Text('MultiPay'), value: "MultiPay"),
PopupMenuItem(child: Text('Broadcast'), value: "Broadcast"),
PopupMenuItem(child: Text('Settings'), value: "Settings"),
PopupMenuItem(child: Text("About"), value: "About"),
],
onSelected: _onMenu,
);
})
],
),
body: TabBarView(controller: _tabController, children: [
SingleChildScrollView(
padding: EdgeInsets.all(20),
child: Center(
child: Column(children: [
Observer(
builder: (context) => syncStatus.syncedHeight <= 0
? Text('Synching')
: syncStatus.isSynced()
? Text('${syncStatus.syncedHeight}',
style: theme.textTheme.caption)
: Text(
'${syncStatus.syncedHeight} / ${syncStatus.latestHeight}',
style: theme.textTheme.caption
.apply(color: theme.primaryColor))),
Padding(padding: EdgeInsets.symmetric(vertical: 8)),
Observer(builder: (context) {
final _ = accountManager.active.address;
final address = _address();
return Column(children: [
if (hasTAddr)
Text(showTAddr
? 'Tap QR Code for Shielded Address'
: 'Tap QR Code for Transparent Address'),
Padding(padding: EdgeInsets.symmetric(vertical: 4)),
GestureDetector(
onTap: hasTAddr ? _onQRTap : null,
child: QrImage(
data: address,
size: 200,
backgroundColor: Colors.white)),
Padding(padding: EdgeInsets.symmetric(vertical: 8)),
RichText(
text: TextSpan(children: [
TextSpan(
text: '$address ', style: theme.textTheme.bodyText2),
WidgetSpan(
child: GestureDetector(
child: Icon(Icons.content_copy),
onTap: _onAddressCopy)),
])),
if (!showTAddr)
TextButton(
child: Text('New Snap Address'),
onPressed: _onSnapAddress),
if (showTAddr)
TextButton(
child: Text('Shield Transp. Balance'),
onPressed: _onShieldTAddr,
)
]);
}),
Observer(builder: (context) {
final balance = showTAddr
? accountManager.tbalance
: accountManager.balance;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.ideographic,
children: <Widget>[
Text('\u24E9 ${_getBalance_hi(balance)}',
style: theme.textTheme.headline2),
Text('${_getBalance_lo(balance)}'),
]);
}),
Observer(builder: (context) {
final balance = showTAddr
? accountManager.tbalance
: accountManager.balance;
final fx = _fx();
final balanceFX = balance * fx / ZECUNIT;
return Column(children: [
if (fx != 0.0)
Text("${balanceFX.toStringAsFixed(2)} ${settings.currency}",
style: theme.textTheme.headline6),
if (fx != 0.0)
Text("1 ZEC = ${fx.toStringAsFixed(2)} ${settings.currency}"),
]);
}),
Padding(padding: EdgeInsets.symmetric(vertical: 8)),
Observer(
builder: (context) =>
(accountManager.unconfirmedBalance != 0)
? Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.ideographic,
children: <Widget>[
Text(
'${_sign(accountManager.unconfirmedBalance)} ${_getBalance_hi(accountManager.unconfirmedBalance)}',
style: theme.textTheme.headline4
?.merge(_unconfirmedStyle())),
Text(
'${_getBalance_lo(accountManager.unconfirmedBalance)}',
style: _unconfirmedStyle()),
])
: Container()),
if (_progress > 0)
LinearProgressIndicator(value: _progress / 100.0),
]))),
NoteWidget(tabTo),
HistoryWidget(tabTo),
BudgetWidget(),
ContactsWidget(),
appBar: AppBar(
title: Observer(
builder: (context) =>
Text("\u24E9 Wallet - ${accountManager.active.name}")),
bottom: TabBar(controller: _tabController, isScrollable: true, tabs: [
Tab(text: "Account"),
Tab(text: "Notes"),
Tab(text: "History"),
Tab(text: "Budget"),
Tab(text: "Trading P&L"),
Tab(text: "Contacts"),
]),
floatingActionButton: _accountTab
? FloatingActionButton(
onPressed: _onSend,
tooltip: 'Send',
backgroundColor: Theme.of(context).accentColor.withOpacity(
accountManager.canPay ? 1.0 : 0.3),
child: Icon(Icons.send),
)
: Container(), // This trailing comma makes auto-formatting nicer for build methods.
);
actions: [
Observer(builder: (context) {
accountManager.canPay;
return PopupMenuButton<String>(
itemBuilder: (context) => [
PopupMenuItem(child: Text("Accounts"), value: "Accounts"),
PopupMenuItem(child: Text("Backup"), value: "Backup"),
PopupMenuItem(child: Text("Rescan"), value: "Rescan"),
if (accountManager.canPay)
PopupMenuItem(child: Text("Cold Storage"), value: "Cold"),
if (accountManager.canPay)
PopupMenuItem(child: Text('MultiPay'), value: "MultiPay"),
PopupMenuItem(child: Text('Broadcast'), value: "Broadcast"),
PopupMenuItem(child: Text('Settings'), value: "Settings"),
PopupMenuItem(child: Text("About"), value: "About"),
],
onSelected: _onMenu,
);
})
],
),
body: TabBarView(controller: _tabController, children: [
SingleChildScrollView(
padding: EdgeInsets.all(20),
child: Center(
child: Column(children: [
Observer(
builder: (context) => syncStatus.syncedHeight <= 0
? Text('Synching')
: syncStatus.isSynced()
? Text('${syncStatus.syncedHeight}',
style: theme.textTheme.caption)
: Text(
'${syncStatus.syncedHeight} / ${syncStatus.latestHeight}',
style: theme.textTheme.caption
.apply(color: theme.primaryColor))),
Padding(padding: EdgeInsets.symmetric(vertical: 8)),
Observer(builder: (context) {
final _ = accountManager.active.address;
final address = _address();
return Column(children: [
if (hasTAddr)
Text(showTAddr
? 'Tap QR Code for Shielded Address'
: 'Tap QR Code for Transparent Address'),
Padding(padding: EdgeInsets.symmetric(vertical: 4)),
GestureDetector(
onTap: hasTAddr ? _onQRTap : null,
child: QrImage(
data: address,
size: 200,
backgroundColor: Colors.white)),
Padding(padding: EdgeInsets.symmetric(vertical: 8)),
RichText(
text: TextSpan(children: [
TextSpan(
text: '$address ', style: theme.textTheme.bodyText2),
WidgetSpan(
child: GestureDetector(
child: Icon(Icons.content_copy),
onTap: _onAddressCopy)),
])),
if (!showTAddr)
TextButton(
child: Text('New Snap Address'),
onPressed: _onSnapAddress),
if (showTAddr)
TextButton(
child: Text('Shield Transp. Balance'),
onPressed: _onShieldTAddr,
)
]);
}),
Observer(builder: (context) {
final balance = showTAddr
? accountManager.tbalance
: accountManager.balance;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.ideographic,
children: <Widget>[
Text('\u24E9 ${_getBalance_hi(balance)}',
style: theme.textTheme.headline2),
Text('${_getBalance_lo(balance)}'),
]);
}),
Observer(builder: (context) {
final balance = showTAddr
? accountManager.tbalance
: accountManager.balance;
final fx = _fx();
final balanceFX = balance * fx / ZECUNIT;
return Column(children: [
if (fx != 0.0)
Text("${balanceFX.toStringAsFixed(2)} ${settings.currency}",
style: theme.textTheme.headline6),
if (fx != 0.0)
Text(
"1 ZEC = ${fx.toStringAsFixed(2)} ${settings.currency}"),
]);
}),
Padding(padding: EdgeInsets.symmetric(vertical: 8)),
Observer(
builder: (context) => (accountManager.unconfirmedBalance != 0)
? Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.ideographic,
children: <Widget>[
Text(
'${_sign(accountManager.unconfirmedBalance)} ${_getBalance_hi(accountManager.unconfirmedBalance)}',
style: theme.textTheme.headline4
?.merge(_unconfirmedStyle())),
Text(
'${_getBalance_lo(accountManager.unconfirmedBalance)}',
style: _unconfirmedStyle()),
])
: Container()),
if (_progress > 0)
LinearProgressIndicator(value: _progress / 100.0),
]))),
NoteWidget(tabTo),
HistoryWidget(tabTo),
BudgetWidget(),
PnLWidget(),
ContactsWidget(),
]),
floatingActionButton: _accountTab
? FloatingActionButton(
onPressed: _onSend,
tooltip: 'Send',
backgroundColor: Theme.of(context)
.accentColor
.withOpacity(accountManager.canPay ? 1.0 : 0.3),
child: Icon(Icons.send),
)
: Container(), // This trailing comma makes auto-formatting nicer for build methods.
);
}
void tabTo(int index) {
@ -409,15 +414,13 @@ class _AccountPageState extends State<AccountPage>
if (didAuthenticate) {
Navigator.of(context).pushNamed('/backup', arguments: true);
}
}
on PlatformException catch (e) {
} on PlatformException catch (e) {
await showDialog(
context: context,
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
title: Text('No Authentication Method'),
content: Text(e.message)
));
title: Text('No Authentication Method'),
content: Text(e.message)));
}
}
@ -530,7 +533,9 @@ class _NoteState extends State<NoteWidget> with AutomaticKeepAliveClientMixin {
child: PaginatedDataTable(
columns: [
DataColumn(
label: settings.showConfirmations ? Text('Confs') : Text('Height'),
label: settings.showConfirmations
? Text('Confs')
: Text('Height'),
onSort: (_, __) {
setState(() {
settings.toggleShowConfirmations();
@ -575,7 +580,9 @@ class NotesDataSource extends DataTableSource {
DataRow getRow(int index) {
final note = accountManager.notes[index];
final theme = Theme.of(context);
final confsOrHeight = settings.showConfirmations ? syncStatus.latestHeight - note.height + 1: note.height;
final confsOrHeight = settings.showConfirmations
? syncStatus.latestHeight - note.height + 1
: note.height;
return DataRow.byIndex(
index: index,
selected: note.excluded,
@ -621,10 +628,10 @@ class HistoryWidget extends StatefulWidget {
HistoryWidget(this.tabTo);
@override
State<StatefulWidget> createState() => _HistoryState();
State<StatefulWidget> createState() => HistoryState();
}
class _HistoryState extends State<HistoryWidget>
class HistoryState extends State<HistoryWidget>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true; //Set to true
@ -651,7 +658,9 @@ class _HistoryState extends State<HistoryWidget>
child: PaginatedDataTable(
columns: [
DataColumn(
label: settings.showConfirmations ? Text('Confs') : Text('Height'),
label: settings.showConfirmations
? Text('Confs')
: Text('Height'),
onSort: (_, __) {
setState(() {
settings.toggleShowConfirmations();
@ -688,7 +697,9 @@ class HistoryDataSource extends DataTableSource {
@override
DataRow getRow(int index) {
final tx = accountManager.txs[index];
final confsOrHeight = settings.showConfirmations ? syncStatus.latestHeight - tx.height + 1: tx.height;
final confsOrHeight = settings.showConfirmations
? syncStatus.latestHeight - tx.height + 1
: tx.height;
return DataRow(
cells: [
DataCell(Text("$confsOrHeight")),
@ -869,41 +880,200 @@ class AccountBalanceTimeChartState extends State<AccountBalanceTimeChart> {
}
}
class PnLWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() => PnLState();
}
class PnLState extends State<PnLWidget> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true; //Set to true
@override
Widget build(BuildContext context) {
return Column(children: [
FormBuilderRadioGroup(
orientation: OptionsOrientation.horizontal,
name: 'Pnl',
initialValue: accountManager.pnlSeriesIndex,
onChanged: (v) {
setState(() {
accountManager.setPnlSeriesIndex(v);
});
},
options: [
FormBuilderFieldOption(child: Text('Real'), value: 0),
FormBuilderFieldOption(child: Text('M/M'), value: 1),
FormBuilderFieldOption(child: Text('Total'), value: 2),
FormBuilderFieldOption(child: Text('Price'), value: 3),
FormBuilderFieldOption(child: Text('Qty'), value: 4),
FormBuilderFieldOption(child: Text('Table'), value: 5),
]),
Observer(builder: (context) {
final _ = accountManager.pnls;
return Expanded(
child: accountManager.pnlSeriesIndex != 5
? PnLChart(accountManager.pnlSeriesIndex)
: PnLTable());
})
]);
}
}
class PnLChart extends StatelessWidget {
final data = accountManager.pnls;
final seriesIndex;
PnLChart(this.seriesIndex);
@override
Widget build(BuildContext context) {
final axisColor = charts.ColorUtil.fromDartColor(
Theme.of(context).textTheme.headline5.color);
final seriesList = _createSeries(data, seriesIndex,
charts.ColorUtil.fromDartColor(Theme.of(context).primaryColor));
return new charts.TimeSeriesChart(
seriesList,
animate: false,
dateTimeFactory: const charts.LocalDateTimeFactory(),
primaryMeasureAxis: charts.NumericAxisSpec(
tickProviderSpec: charts.BasicNumericTickProviderSpec(
zeroBound: true,
dataIsInWholeNumbers: false,
desiredTickCount: 5),
renderSpec: charts.GridlineRendererSpec(
labelStyle: charts.TextStyleSpec(color: axisColor))),
domainAxis: charts.DateTimeAxisSpec(
renderSpec: charts.SmallTickRendererSpec(
labelStyle: charts.TextStyleSpec(color: axisColor))),
behaviors: [
charts.SelectNearest(),
],
);
}
static _seriesData(PnL pnl, int index) {
switch (index) {
case 0:
return pnl.realized;
case 1:
return pnl.unrealized;
case 2:
return pnl.realized + pnl.unrealized;
case 3:
return pnl.price;
case 4:
return pnl.amount;
}
}
static List<charts.Series<PnL, DateTime>> _createSeries(
List<PnL> data, int index, charts.Color lineColor) {
return [
new charts.Series<PnL, DateTime>(
id: 'P/L',
colorFn: (_, __) => lineColor,
domainFn: (PnL pnl, _) => pnl.timestamp,
measureFn: (PnL pnl, _) => _seriesData(pnl, index),
data: data,
),
];
}
}
class PnLTable extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: PaginatedDataTable(
columns: [
DataColumn(label: Text('Date/Time')),
DataColumn(label: Text('Qty'), numeric: true),
DataColumn(label: Text('Price'), numeric: true),
DataColumn(label: Text('Realized'), numeric: true),
DataColumn(label: Text('M/M'), numeric: true),
DataColumn(label: Text('Total'), numeric: true),
],
columnSpacing: 16,
showCheckboxColumn: false,
availableRowsPerPage: [5, 10, 25, 100],
onRowsPerPageChanged: (int value) {
settings.setRowsPerPage(value);
},
showFirstLastButtons: true,
rowsPerPage: settings.rowsPerPage,
source: PnLDataSource(context)));
}
}
class PnLDataSource extends DataTableSource {
BuildContext context;
final dateFormat = DateFormat("MM-dd");
PnLDataSource(this.context);
@override
DataRow getRow(int index) {
final pnl = accountManager.pnls[index];
final ts = dateFormat.format(pnl.timestamp);
return DataRow(cells: [
DataCell(Text("$ts")),
DataCell(Text("${pnl.amount.toStringAsFixed(2)}")),
DataCell(Text("${pnl.price.toStringAsFixed(3)}")),
DataCell(Text("${pnl.realized.toStringAsFixed(3)}")),
DataCell(Text("${pnl.unrealized.toStringAsFixed(3)}")),
DataCell(Text("${(pnl.realized + pnl.unrealized).toStringAsFixed(3)}")),
]);
}
@override
bool get isRowCountApproximate => false;
@override
int get rowCount => accountManager.pnls.length;
@override
int get selectedRowCount => 0;
}
class ContactsWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() => ContactsState();
}
class ContactsState extends State<ContactsWidget> {
class ContactsState extends State<ContactsWidget>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true; //Set to true
@override
Widget build(BuildContext context) {
return Observer(builder: (context) {
final _ = accountManager.dataEpoch;
final theme = Theme.of(context);
return Column(children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: Text(
'To make a contact, send them a memo with "Contact: Name"',
style: Theme.of(context).textTheme.caption)),
Expanded(
child: GroupedListView<Contact, String>(
elements: accountManager.contacts,
groupBy: (e) => e.name.isEmpty ? "" : e.name[0],
itemBuilder: (context, c) => ListTile(
title: Text(c.name),
subtitle: Text(c.address),
trailing: accountManager.canPay
? IconButton(
icon: Icon(Icons.chevron_right),
onPressed: () {
_onContact(c);
})
: null),
groupSeparatorBuilder: (String h) =>
Text(h, style: theme.textTheme.headline5),
)),
]);
return Padding(
padding: EdgeInsets.all(12),
child: Column(children: [
Text('To make a contact, send them a memo with "Contact: Name"',
style: Theme.of(context).textTheme.caption),
Expanded(
child: GroupedListView<Contact, String>(
elements: accountManager.contacts,
groupBy: (e) => e.name.isEmpty ? "" : e.name[0],
itemBuilder: (context, c) => ListTile(
title: Text(c.name),
subtitle: Text(c.address),
trailing: accountManager.canPay
? IconButton(
icon: Icon(Icons.chevron_right),
onPressed: () {
_onContact(c);
})
: null),
groupSeparatorBuilder: (String h) =>
Text(h, style: theme.textTheme.headline5),
)),
]));
});
}

View File

@ -63,12 +63,22 @@ void main() {
: Container()));
}
class ZWalletApp extends StatelessWidget {
class ZWalletApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => ZWalletAppState();
}
class ZWalletAppState extends State<ZWalletApp> {
bool initialized = false;
Future<Widget> _init() async {
final dbPath = await getDatabasesPath();
WarpApi.initWallet(dbPath + "/zec.db", settings.getLWD());
await accountManager.init();
await syncStatus.init();
if (!initialized) {
initialized = true;
final dbPath = await getDatabasesPath();
WarpApi.initWallet(dbPath + "/zec.db", settings.getLWD());
await accountManager.init();
await syncStatus.init();
}
return Future.value(accountManager.accounts.isNotEmpty
? AccountPage()
: AccountManagerPage());

View File

@ -4,7 +4,6 @@ import 'dart:math' as math;
import 'package:json_annotation/json_annotation.dart';
import 'package:charts_flutter/flutter.dart' as charts show MaterialPalette;
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:mobx/mobx.dart';
@ -72,6 +71,7 @@ abstract class _Settings with Store {
theme = prefs.getString('theme') ?? "zcash";
themeBrightness = prefs.getString('theme_brightness') ?? "dark";
showConfirmations = prefs.getBool('show_confirmations') ?? false;
currency = prefs.getString('currency') ?? "USD";
_updateThemeData();
Future.microtask(_loadCurrencies); // lazily
return true;
@ -178,8 +178,11 @@ abstract class _Settings with Store {
@action
Future<void> setCurrency(String newCurrency) async {
final prefs = await SharedPreferences.getInstance();
currency = newCurrency;
prefs.setString('currency', currency);
await priceStore.fetchZecPrice();
await accountManager.fetchCashFlows();
}
@action
@ -237,6 +240,9 @@ abstract class _AccountManager with Store {
@observable
List<AccountBalance> accountBalances = [];
@observable
List<PnL> pnls = [];
@observable
List<Account> accounts = [];
@ -246,6 +252,9 @@ abstract class _AccountManager with Store {
@observable
SortOrder txSortOrder = SortOrder.Unsorted;
@observable
int pnlSeriesIndex = 0;
@observable
List<Contact> contacts = [];
@ -281,9 +290,9 @@ abstract class _AccountManager with Store {
final List<Map> res2 = await db.rawQuery(
"SELECT sk FROM accounts WHERE id_account = ?1", [account.id]);
canPay = res2.isNotEmpty && res2[0]['sk'] != null;
await _fetchData(account.id);
active = account;
print("Active account = ${account.id}");
await _fetchData(account.id);
}
@action
@ -376,6 +385,12 @@ abstract class _AccountManager with Store {
await _fetchData(active.id);
}
@action
Future<void> fetchCashFlows() async {
if (active == null) return;
await _fetchCashFlows(active.id);
}
@action
void toggleShowTAddr() {
showTAddr = !showTAddr;
@ -386,6 +401,9 @@ abstract class _AccountManager with Store {
await _fetchSpending(accountId);
await _fetchAccountBalanceTimeSeries(accountId);
await _fetchContacts(accountId);
int countNewPrices = await WarpApi.syncHistoricalPrices(settings.currency);
if (countNewPrices > 0 || pnls.isEmpty)
await _fetchCashFlows(accountId);
dataEpoch = DateTime.now().millisecondsSinceEpoch;
}
@ -496,6 +514,40 @@ abstract class _AccountManager with Store {
}
}
Future<void> _fetchCashFlows(int accountId) async {
final cutoff = DateTime.now().add(Duration(days: -365)).millisecondsSinceEpoch / 1000;
final List<Map> res = await db.rawQuery(
"WITH t AS (SELECT value, timestamp/86400 AS day FROM transactions WHERE account = ?1), p AS (SELECT price, timestamp, timestamp/86400 AS day FROM historical_prices WHERE currency = ?3) "
"SELECT t.value, p.price, p.timestamp FROM t, p WHERE t.day = p.day AND p.timestamp >= ?2 ORDER BY p.day",
[accountId, cutoff, settings.currency]);
var cash = 0.0;
var balance = 0.0;
var realized = 0.0;
Map<int, PnL> pnlMap = {};
for (var row in res) {
final ts = row['timestamp'];
final value = (row['value'] / ZECUNIT) as double;
final price = row['price'] as double;
final timestamp = DateTime.fromMillisecondsSinceEpoch(ts * 1000);
final closeQty = value * balance < 0 ? math.min(value.abs(), balance.abs()) * value.sign : 0.0;
final openQty = value - closeQty;
final avgPrice = balance != 0 ? cash / balance : 0.0;
cash += openQty * price + closeQty * avgPrice;
realized += closeQty * (price - avgPrice);
balance += value;
final unrealized = price * balance - cash;
pnlMap[ts] = PnL(timestamp, price, balance, realized, unrealized);
}
final _pnls = pnlMap.values.toList();
_pnls.sort((a, b) => a.timestamp.compareTo(b.timestamp));
pnls = _pnls;
}
@action
Future<void> convertToWatchOnly() async {
await db.rawUpdate(
@ -525,6 +577,11 @@ abstract class _AccountManager with Store {
contacts.add(contact);
}
}
@action
void setPnlSeriesIndex(int index) {
pnlSeriesIndex = index;
}
}
class Account {
@ -549,9 +606,10 @@ abstract class _PriceStore with Store {
final rep = await http.get(uri);
if (rep.statusCode == 200) {
final json = convert.jsonDecode(rep.body) as Map<String, dynamic>;
final price = json['zcash'][settings.currency.toLowerCase()] as double;
zecPrice = price;
final p = json['zcash'][settings.currency.toLowerCase()];
zecPrice = (p is double) ? p : (p as int).toDouble();
}
else zecPrice = 0.0;
}
}
@ -701,3 +759,13 @@ class Recipient {
factory Recipient.fromJson(Map<String, dynamic> json) => _$RecipientFromJson(json);
Map<String, dynamic> toJson() => _$RecipientToJson(this);
}
class PnL {
final DateTime timestamp;
final double price;
final double amount;
final double realized;
final double unrealized;
PnL(this.timestamp, this.price, this.amount, this.realized, this.unrealized);
}

View File

@ -63,4 +63,6 @@ char *prepare_offline_tx(uint32_t account,
char *broadcast(char *tx_filename);
uint32_t sync_historical_prices(char *currency);
void dummy_export(void);

View File

@ -330,3 +330,12 @@ pub fn broadcast(tx_filename: &str) -> String {
log_result_string(res)
})
}
pub fn sync_historical_prices(currency: &str) -> u32 {
let r = Runtime::new().unwrap();
r.block_on(async {
let mut wallet = WALLET.get().unwrap().lock().unwrap();
let res = wallet.sync_historical_prices(currency).await;
log_result(res)
})
}

View File

@ -168,5 +168,11 @@ pub unsafe extern "C" fn broadcast(tx_filename: *mut c_char) -> *mut c_char {
CString::new(res).unwrap().into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn sync_historical_prices(currency: *mut c_char) -> u32 {
let currency = CStr::from_ptr(currency).to_string_lossy();
api::sync_historical_prices(&currency)
}
#[no_mangle]
pub unsafe extern "C" fn dummy_export() {}

@ -1 +1 @@
Subproject commit da31fbdb8eded5ac20208028f0a8801337828232
Subproject commit 080aefe016cc2eb3ad3a995b6cc7d80b8e40186d

View File

@ -162,14 +162,14 @@ class WarpApi {
static String prepareTx(
int account,
String to_address,
String toAddress,
int amount,
String memo,
int maxAmountPerNote,
int anchorOffset,
String txFilename) {
final res = warp_api_lib.prepare_offline_tx(account,
to_address.toNativeUtf8().cast<Int8>(), amount,
toAddress.toNativeUtf8().cast<Int8>(), amount,
memo.toNativeUtf8().cast<Int8>(), maxAmountPerNote, anchorOffset,
txFilename.toNativeUtf8().cast<Int8>());
return res.cast<Utf8>().toDartString();
@ -179,6 +179,10 @@ class WarpApi {
final res = warp_api_lib.broadcast(txFilename.toNativeUtf8().cast<Int8>());
return res.cast<Utf8>().toDartString();
}
static Future<int> syncHistoricalPrices(String currency) async {
return await compute(syncHistoricalPricesIsolateFn, currency);
}
static updateLWD(String url) {
warp_api_lib.set_lwd_url(url.toNativeUtf8().cast<Int8>());
@ -227,3 +231,7 @@ String shieldTAddrIsolateFn(int account) {
final txId = warp_api_lib.shield_taddr(account);
return txId.cast<Utf8>().toDartString();
}
int syncHistoricalPricesIsolateFn(String currency) {
return warp_api_lib.sync_historical_prices(currency.toNativeUtf8().cast<Int8>());
}

View File

@ -318,6 +318,20 @@ class NativeLibrary {
late final _dart_broadcast _broadcast =
_broadcast_ptr.asFunction<_dart_broadcast>();
int sync_historical_prices(
ffi.Pointer<ffi.Int8> currency,
) {
return _sync_historical_prices(
currency,
);
}
late final _sync_historical_prices_ptr =
_lookup<ffi.NativeFunction<_c_sync_historical_prices>>(
'sync_historical_prices');
late final _dart_sync_historical_prices _sync_historical_prices =
_sync_historical_prices_ptr.asFunction<_dart_sync_historical_prices>();
void dummy_export() {
return _dummy_export();
}
@ -520,6 +534,14 @@ typedef _dart_broadcast = ffi.Pointer<ffi.Int8> Function(
ffi.Pointer<ffi.Int8> tx_filename,
);
typedef _c_sync_historical_prices = ffi.Uint32 Function(
ffi.Pointer<ffi.Int8> currency,
);
typedef _dart_sync_historical_prices = int Function(
ffi.Pointer<ffi.Int8> currency,
);
typedef _c_dummy_export = ffi.Void Function();
typedef _dart_dummy_export = void Function();

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.8+70
version: 1.0.9+76
environment:
sdk: ">=2.9.0 <3.0.0"