Squashed commit of the following:
commit 574702eaa472332d4624a9a655157585efc84dd3 Author: Hanh <hanh425@gmail.com> Date: Fri Nov 12 09:35:00 2021 +0800 Refactor multisig to crate commit 1c133aa083ea41b9fb33c9b5e56816ad4c5ffc89 Author: Hanh <hanh425@gmail.com> Date: Sat Nov 6 00:32:41 2021 +0800 Send & MultiSend commit f3dd0822edd6860e764c248c7f31acaf2c074d97 Author: Hanh <hanh425@gmail.com> Date: Tue Nov 2 18:19:48 2021 +0800 Improved Charts commit 17c365ad24c88f7a79de8ad5fd2114187f5ac33e Author: Hanh <hanh425@gmail.com> Date: Thu Oct 28 19:38:19 2021 +0800 Split account UI
This commit is contained in:
parent
f77bf079cf
commit
04958c291a
|
@ -4,3 +4,6 @@
|
|||
[submodule "native/zcash-params"]
|
||||
path = native/zcash-params
|
||||
url = https://github.com/hhanh00/zcash-params.git
|
||||
[submodule "native/zcash-multisig"]
|
||||
path = native/zcash-multisig
|
||||
url = https://github.com/hhanh00/zcash-multisig.git
|
||||
|
|
|
@ -47,18 +47,18 @@ checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
|
|||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allo-isolate"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95c5a443c8b833fc57ee060bb52639fb687d94e640737e71be5c8cccbbbb790c"
|
||||
checksum = "e13e2dba4602fed6c46f7d5cae67fe0fb9a6af1ce01848228f7533a8450c73be"
|
||||
dependencies = [
|
||||
"atomic",
|
||||
]
|
||||
|
@ -92,9 +92,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.44"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
|
||||
checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
|
@ -341,9 +341,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.17"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
||||
checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"memchr",
|
||||
|
@ -390,7 +390,7 @@ version = "0.19.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38728c31b994e4b849cf59feefb4a8bf26acd299ee0b92c9fb35bd14ad4b8dfa"
|
||||
dependencies = [
|
||||
"clap 2.33.3",
|
||||
"clap",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"log",
|
||||
|
@ -452,43 +452,12 @@ dependencies = [
|
|||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim 0.8.0",
|
||||
"textwrap 0.11.0",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.0.0-beta.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"os_str_bytes",
|
||||
"strsim 0.10.0",
|
||||
"termcolor",
|
||||
"textwrap 0.14.2",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.0.0-beta.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
version = "4.2.2"
|
||||
|
@ -554,7 +523,7 @@ checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
|
|||
dependencies = [
|
||||
"atty",
|
||||
"cast",
|
||||
"clap 2.33.3",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"csv",
|
||||
"itertools 0.10.1",
|
||||
|
@ -869,7 +838,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "equihash"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/hhanh00/librustzcash.git?rev=6baf1ba63261dda09e5b1d4b476977842a1f61c8#6baf1ba63261dda09e5b1d4b476977842a1f61c8"
|
||||
source = "git+https://github.com/hhanh00/librustzcash.git?rev=1518b145f8ee67e144fa8337c7dfd4c8cff899c9#1518b145f8ee67e144fa8337c7dfd4c8cff899c9"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"byteorder",
|
||||
|
@ -1449,9 +1418,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.105"
|
||||
version = "0.2.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
|
||||
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
|
||||
|
||||
[[package]]
|
||||
name = "libsecp256k1"
|
||||
|
@ -1503,9 +1472,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
version = "2.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
|
@ -1599,9 +1568,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "6.1.2"
|
||||
version = "6.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
|
||||
checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6"
|
||||
dependencies = [
|
||||
"bitvec 0.19.5",
|
||||
"funty",
|
||||
|
@ -1689,15 +1658,6 @@ version = "0.1.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pairing"
|
||||
version = "0.19.0"
|
||||
|
@ -1805,30 +1765,6 @@ version = "0.2.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
|
@ -2084,9 +2020,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
version = "1.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -2399,9 +2335,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.68"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
|
||||
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -2555,12 +2491,6 @@ version = "0.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "1.0.0"
|
||||
|
@ -2589,11 +2519,13 @@ name = "sync"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bech32",
|
||||
"bincode",
|
||||
"blake2b_simd",
|
||||
"bls12_381",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"clap 3.0.0-beta.5",
|
||||
"clap",
|
||||
"criterion",
|
||||
"dotenv",
|
||||
"env_logger",
|
||||
|
@ -2609,6 +2541,7 @@ dependencies = [
|
|||
"prost",
|
||||
"protobuf",
|
||||
"rand 0.8.4",
|
||||
"rand_chacha 0.3.1",
|
||||
"rayon",
|
||||
"reqwest",
|
||||
"ripemd160",
|
||||
|
@ -2627,7 +2560,8 @@ dependencies = [
|
|||
"tonic-build",
|
||||
"zcash_address",
|
||||
"zcash_client_backend",
|
||||
"zcash_params 0.1.0 (git+https://github.com/hhanh00/zcash-params.git?branch=main)",
|
||||
"zcash_multisig 0.1.0 (git+https://github.com/hhanh00/zcash-multisig.git?rev=f6ab9d9efcdc064a4b6f77623a263899b62a7bd7)",
|
||||
"zcash_params 0.1.0 (git+https://github.com/hhanh00/zcash-params.git?rev=f54214d0a6752188efd1404e39b10be58a27ea0f)",
|
||||
"zcash_primitives",
|
||||
"zcash_proofs",
|
||||
]
|
||||
|
@ -2682,15 +2616,6 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
|
@ -2819,9 +2744,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.12.0"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc"
|
||||
checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
|
@ -2836,9 +2761,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.5.0"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2dd85aeaba7b68df939bd357c6afb36c87951be9e80bf9c859f2fc3e9fca0fd"
|
||||
checksum = "114383b041aa6212c579467afa0075fbbdd0718de036100bc0ba7961d8cb9095"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2858,9 +2783,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f"
|
||||
checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
|
@ -2869,9 +2794,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd"
|
||||
checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
|
@ -3021,15 +2946,6 @@ version = "1.14.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.7"
|
||||
|
@ -3139,6 +3055,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"sync",
|
||||
"tokio",
|
||||
"zcash_multisig 0.1.0",
|
||||
"zcash_primitives",
|
||||
]
|
||||
|
||||
|
@ -3325,7 +3242,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_client_backend"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/hhanh00/librustzcash.git?rev=6baf1ba63261dda09e5b1d4b476977842a1f61c8#6baf1ba63261dda09e5b1d4b476977842a1f61c8"
|
||||
source = "git+https://github.com/hhanh00/librustzcash.git?rev=1518b145f8ee67e144fa8337c7dfd4c8cff899c9#1518b145f8ee67e144fa8337c7dfd4c8cff899c9"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bech32",
|
||||
|
@ -3346,10 +3263,31 @@ dependencies = [
|
|||
"zcash_primitives",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_multisig"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures 0.3.17",
|
||||
"jubjub",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_multisig"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/hhanh00/zcash-multisig.git?rev=f6ab9d9efcdc064a4b6f77623a263899b62a7bd7#f6ab9d9efcdc064a4b6f77623a263899b62a7bd7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures 0.3.17",
|
||||
"jubjub",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_note_encryption"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/hhanh00/librustzcash.git?rev=6baf1ba63261dda09e5b1d4b476977842a1f61c8#6baf1ba63261dda09e5b1d4b476977842a1f61c8"
|
||||
source = "git+https://github.com/hhanh00/librustzcash.git?rev=1518b145f8ee67e144fa8337c7dfd4c8cff899c9#1518b145f8ee67e144fa8337c7dfd4c8cff899c9"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"byteorder",
|
||||
|
@ -3373,13 +3311,14 @@ dependencies = [
|
|||
"jubjub",
|
||||
"lazy_static",
|
||||
"rand 0.8.4",
|
||||
"serde",
|
||||
"zcash_primitives",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_params"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/hhanh00/zcash-params.git?branch=main#f8eb2641dd7c4f3e57cd8c928334c1ae4e4284a4"
|
||||
source = "git+https://github.com/hhanh00/zcash-params.git?rev=f54214d0a6752188efd1404e39b10be58a27ea0f#f54214d0a6752188efd1404e39b10be58a27ea0f"
|
||||
dependencies = [
|
||||
"bls12_381",
|
||||
"byteorder",
|
||||
|
@ -3390,13 +3329,14 @@ dependencies = [
|
|||
"jubjub",
|
||||
"lazy_static",
|
||||
"rand 0.8.4",
|
||||
"serde",
|
||||
"zcash_primitives",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_primitives"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/hhanh00/librustzcash.git?rev=6baf1ba63261dda09e5b1d4b476977842a1f61c8#6baf1ba63261dda09e5b1d4b476977842a1f61c8"
|
||||
source = "git+https://github.com/hhanh00/librustzcash.git?rev=1518b145f8ee67e144fa8337c7dfd4c8cff899c9#1518b145f8ee67e144fa8337c7dfd4c8cff899c9"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bitvec 0.20.4",
|
||||
|
@ -3426,7 +3366,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_proofs"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/hhanh00/librustzcash.git?rev=6baf1ba63261dda09e5b1d4b476977842a1f61c8#6baf1ba63261dda09e5b1d4b476977842a1f61c8"
|
||||
source = "git+https://github.com/hhanh00/librustzcash.git?rev=1518b145f8ee67e144fa8337c7dfd4c8cff899c9#1518b145f8ee67e144fa8337c7dfd4c8cff899c9"
|
||||
dependencies = [
|
||||
"bellman",
|
||||
"blake2b_simd",
|
||||
|
@ -3443,18 +3383,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.4.2"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970"
|
||||
checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.2.0"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7"
|
||||
checksum = "65f1a51723ec88c66d5d1fe80c841f17f63587d6691901d66be9bec6c3b51f73"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -41,7 +41,6 @@ android {
|
|||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "me.hanh.zwallet"
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 30
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="me.hanh.zwallettest">
|
||||
package="me.hanh.zwallet">
|
||||
<application
|
||||
android:label="ZWalletTest"
|
||||
android:label="ZWallet"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
|
@ -27,7 +27,7 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data
|
||||
android:scheme="zcashtest"/>
|
||||
android:scheme="zcash"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
|
@ -1,12 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
|
@ -5,6 +5,7 @@
|
|||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
|
@ -15,4 +16,4 @@
|
|||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
</resources>
|
|
@ -19,4 +19,4 @@
|
|||
<style name="QuickActions">
|
||||
<item name="android:windowBackground">@drawable/quick_actions</item>
|
||||
</style>
|
||||
</resources>
|
||||
</resources>
|
|
@ -10,14 +10,14 @@ zcashtest)
|
|||
export APP_NAME=zwallettest
|
||||
;;
|
||||
zcash)
|
||||
export APP_TITLE=WarpWallet
|
||||
export APP_NAME=warpwallet
|
||||
export APP_TITLE=ZWallet
|
||||
export APP_NAME=zwallet
|
||||
;;
|
||||
esac
|
||||
|
||||
cp assets/$COIN.png assets/icon.png
|
||||
cp lib/coin/$COIN.dart lib/coin/coindef.dart
|
||||
cp native/zcash-sync/src/coindef/$COIN.rs native/zcash-sync/src/coin.rs
|
||||
cp native/zcash-params/src/coindef/$COIN.rs native/zcash-params/src/coin.rs
|
||||
|
||||
mo pubspec.yaml.tpl > pubspec.yaml
|
||||
mo android/app/src/main/AndroidManifest.xml.tpl > android/app/src/main/AndroidManifest.xml
|
||||
|
@ -28,3 +28,6 @@ flutter pub run flutter_launcher_icons:main
|
|||
flutter pub run flutter_app_name
|
||||
flutter pub run build_runner build
|
||||
flutter pub run flutter_native_splash:create
|
||||
|
||||
(cd packages/warp_api_ffi; flutter pub get; flutter pub run build_runner build)
|
||||
|
||||
|
|
|
@ -560,4 +560,4 @@
|
|||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
}
|
||||
}
|
|
@ -1,23 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 6.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 14 KiB |
|
@ -16,13 +16,19 @@
|
|||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="3T2-ad-Qdv"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="RPx-PI-7Xg"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="SdS-ul-q2q"/>
|
||||
<constraint firstAttribute="trailing" secondItem="tWc-Dq-wcI" secondAttribute="trailing" id="Swv-Gf-Rwn"/>
|
||||
<constraint firstAttribute="trailing" secondItem="YRO-k0-Ey4" secondAttribute="trailing" id="TQA-XW-tRk"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="duK-uY-Gun"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="kV7-tw-vXt"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="xPn-NY-SIU"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
|
@ -32,6 +38,7 @@
|
|||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="168" height="185"/>
|
||||
<image name="LaunchImage" width="256" height="256"/>
|
||||
<image name="LaunchBackground" width="1" height="1"/>
|
||||
</resources>
|
||||
</document>
|
||||
</document>
|
|
@ -11,7 +11,7 @@
|
|||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>WarpWallet</string>
|
||||
<string>YWallet</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
|
@ -49,16 +49,16 @@
|
|||
<false/>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>$(COIN)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>$(COIN)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -10,6 +10,7 @@ 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:k_chart/entity/index.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
import 'package:sensors_plus/sensors_plus.dart';
|
||||
|
@ -125,6 +126,7 @@ class _AccountPageState extends State<AccountPage>
|
|||
final theme = Theme.of(this.context);
|
||||
final hasTAddr = accountManager.taddress.isNotEmpty;
|
||||
final qrSize = getScreenSize(context) / 2.5;
|
||||
final hasMultisign = accountManager.canPay || accountManager.active.share != null;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
|
@ -154,11 +156,12 @@ class _AccountPageState extends State<AccountPage>
|
|||
if (accountManager.canPay)
|
||||
PopupMenuItem(
|
||||
child: Text(s.coldStorage), value: "Cold"),
|
||||
if (accountManager.canPay)
|
||||
PopupMenuItem(
|
||||
child: Text(s.multipay), value: "MultiPay"),
|
||||
PopupMenuItem(
|
||||
child: Text(s.multipay), value: "MultiPay"),
|
||||
PopupMenuItem(
|
||||
child: Text(s.broadcast), value: "Broadcast"),
|
||||
if (coin.supportsMultisig && hasMultisign) PopupMenuItem(
|
||||
child: Text(s.multisig), value: "Multisig"),
|
||||
PopupMenuItem(
|
||||
child: Text(s.settings), value: "Settings"),
|
||||
PopupMenuItem(child: Text(s.help), value: "Help"),
|
||||
|
@ -176,6 +179,10 @@ class _AccountPageState extends State<AccountPage>
|
|||
padding: EdgeInsets.all(20),
|
||||
child: Center(
|
||||
child: Column(children: [
|
||||
Observer(builder: (context) {
|
||||
final share = accountManager.active.share;
|
||||
return share != null ? Text("MULTISIG ${share.index}/${share.participants}") : SizedBox();
|
||||
}),
|
||||
Observer(builder: (context) {
|
||||
final _1 = eta.eta;
|
||||
final _2 = syncStatus.syncedHeight;
|
||||
|
@ -464,6 +471,9 @@ class _AccountPageState extends State<AccountPage>
|
|||
case "Broadcast":
|
||||
_broadcast();
|
||||
break;
|
||||
case "Multisig":
|
||||
_multisig();
|
||||
break;
|
||||
case "Settings":
|
||||
_settings();
|
||||
break;
|
||||
|
@ -519,6 +529,10 @@ class _AccountPageState extends State<AccountPage>
|
|||
}
|
||||
}
|
||||
|
||||
_multisig() {
|
||||
Navigator.of(context).pushNamed('/multisig');
|
||||
}
|
||||
|
||||
_convertToWatchOnly() {
|
||||
accountManager.convertToWatchOnly();
|
||||
Navigator.of(context).pop();
|
||||
|
@ -580,7 +594,7 @@ class BudgetState extends State<BudgetWidget>
|
|||
style: Theme.of(context).textTheme.headline6),
|
||||
Padding(padding: EdgeInsets.symmetric(vertical: 4)),
|
||||
Expanded(child: Padding(padding: EdgeInsets.only(right: 20),
|
||||
child: LineChartTimeSeries(accountManager.accountBalances)))
|
||||
child: LineChartTimeSeries.fromTimeSeries(accountManager.accountBalances)))
|
||||
]))),
|
||||
],
|
||||
);
|
||||
|
@ -659,7 +673,7 @@ class PnLChart extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final series = _createSeries(pnls, seriesIndex, context);
|
||||
return LineChartTimeSeries(series);
|
||||
return LineChartTimeSeries.fromTimeSeries(series);
|
||||
}
|
||||
|
||||
static double _seriesData(PnL pnl, int index) {
|
||||
|
|
|
@ -142,11 +142,11 @@ class AccountManagerState extends State<AccountManagerPage> {
|
|||
builder: (context) => AlertDialog(
|
||||
title: Text(S.of(context).changeAccountName),
|
||||
content: TextField(controller: _accountNameController),
|
||||
actions: confirmButtons(context, _changeAccountName)));
|
||||
actions: confirmButtons(context, () { _changeAccountName(account); })));
|
||||
}
|
||||
|
||||
_changeAccountName() {
|
||||
accountManager.changeAccountName(_accountNameController.text);
|
||||
_changeAccountName(Account account) {
|
||||
accountManager.changeAccountName(account, _accountNameController.text);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,12 +18,15 @@ class BackupState extends State<BackupPage> {
|
|||
final _backupController = TextEditingController();
|
||||
final _skController = TextEditingController();
|
||||
final _ivkController = TextEditingController();
|
||||
final _shareController = TextEditingController();
|
||||
|
||||
Future<bool> _init() async {
|
||||
backup = await accountManager.getBackup(widget.accountId ?? accountManager.active.id);
|
||||
_backupController.text = backup.value();
|
||||
_skController.text = backup.sk ?? "";
|
||||
_ivkController.text = backup.ivk;
|
||||
final share = backup.share;
|
||||
_shareController.text = share?.value ?? "";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -38,6 +41,8 @@ class BackupState extends State<BackupPage> {
|
|||
|
||||
Widget _build(BuildContext context, AsyncSnapshot<void> snapshot) {
|
||||
if (!snapshot.hasData) return LinearProgressIndicator();
|
||||
final name = backup.name;
|
||||
final share = backup.share;
|
||||
final type = backup.type;
|
||||
final theme = Theme.of(context);
|
||||
return SingleChildScrollView(child: Card(
|
||||
|
@ -46,7 +51,7 @@ class BackupState extends State<BackupPage> {
|
|||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: S.of(context).backupDataRequiredForRestore, prefixIcon: IconButton(icon: Icon(Icons.save),
|
||||
onPressed: () => _showQR(backup.value()))),
|
||||
onPressed: () => _showQR(backup.value(), "$name - backup"))),
|
||||
controller: _backupController,
|
||||
minLines: 3,
|
||||
maxLines: 10,
|
||||
|
@ -55,7 +60,7 @@ class BackupState extends State<BackupPage> {
|
|||
),
|
||||
if (type == 0) TextField(
|
||||
decoration: InputDecoration(labelText: S.of(context).secretKey, prefixIcon: IconButton(icon: Icon(Icons.vpn_key),
|
||||
onPressed: () => _showQR(backup.sk!))),
|
||||
onPressed: () => _showQR(backup.sk!, "$name - sk"))),
|
||||
controller: _skController,
|
||||
minLines: 3,
|
||||
maxLines: 10,
|
||||
|
@ -64,13 +69,22 @@ class BackupState extends State<BackupPage> {
|
|||
),
|
||||
if (type != 2) TextField(
|
||||
decoration: InputDecoration(labelText: S.of(context).viewingKey, prefixIcon: IconButton(icon: Icon(Icons.visibility),
|
||||
onPressed: () => _showQR(backup.ivk))),
|
||||
onPressed: () => _showQR(backup.ivk, "$name - vk"))),
|
||||
controller: _ivkController,
|
||||
minLines: 3,
|
||||
maxLines: 10,
|
||||
readOnly: true,
|
||||
style: theme.textTheme.caption
|
||||
),
|
||||
if (share != null) TextField(
|
||||
decoration: InputDecoration(labelText: S.of(context).secretShare, prefixIcon: IconButton(icon: Icon(Icons.share),
|
||||
onPressed: () => _showQR(share.value, "$name - ms ${share.index}/${share.participants}"))),
|
||||
controller: _shareController,
|
||||
minLines: 3,
|
||||
maxLines: 10,
|
||||
readOnly: true,
|
||||
style: theme.textTheme.caption
|
||||
),
|
||||
Padding(padding: EdgeInsets.symmetric(vertical: 4)),
|
||||
Text(S.of(context).tapAnIconToShowTheQrCode),
|
||||
Container(margin: EdgeInsets.all(8), padding: EdgeInsets.all(8), decoration: BoxDecoration(border: Border.all(width: 2, color: theme.primaryColor), borderRadius: BorderRadius.circular(4)),child:
|
||||
|
@ -81,5 +95,5 @@ class BackupState extends State<BackupPage> {
|
|||
));
|
||||
}
|
||||
|
||||
_showQR(String text) => showQR(context, text);
|
||||
_showQR(String text, String title) => showQR(context, text, title);
|
||||
}
|
||||
|
|
157
lib/chart.dart
157
lib/chart.dart
|
@ -1,154 +1,29 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:flutter_palette/flutter_palette.dart';
|
||||
import 'package:warp_api/warp_api.dart';
|
||||
import 'package:k_chart/k_chart_widget.dart';
|
||||
import 'package:k_chart/flutter_k_chart.dart';
|
||||
|
||||
import 'store.dart';
|
||||
import 'main.dart';
|
||||
|
||||
class LineChartTimeSeries extends StatefulWidget {
|
||||
final List<TimeSeriesPoint<double>> timeseries;
|
||||
class LineChartTimeSeries extends StatelessWidget {
|
||||
List<KLineEntity> datas;
|
||||
|
||||
LineChartTimeSeries(this.timeseries);
|
||||
|
||||
@override
|
||||
LineChartTimeSeriesState createState() => LineChartTimeSeriesState();
|
||||
}
|
||||
|
||||
class LineChartTimeSeriesState extends State<LineChartTimeSeries> {
|
||||
final numberFormat = NumberFormat.compact();
|
||||
|
||||
bool showAvg = false;
|
||||
var _minX = 0.0;
|
||||
var _maxX = 0.0;
|
||||
var _minY = 0.0;
|
||||
var _maxY = 0.0;
|
||||
LineChartTimeSeries(this.datas);
|
||||
factory LineChartTimeSeries.fromTimeSeries(List<TimeSeriesPoint<double>> quotes) =>
|
||||
LineChartTimeSeries(quotes.map((q) => KLineEntity.fromCustom(time: q.day * DAY_MS, open: q.value, close: q.value,
|
||||
high: q.value, low: q.value, amount: 0, vol: 0)).toList());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AspectRatio(
|
||||
aspectRatio: 1.7,
|
||||
child: LineChart(
|
||||
mainData(),
|
||||
));
|
||||
}
|
||||
|
||||
LineChartData mainData() {
|
||||
final theme = Theme.of(context);
|
||||
double minY = double.maxFinite;
|
||||
double maxY = 0.0;
|
||||
|
||||
final spots = widget.timeseries.map((ab) {
|
||||
if (minY > ab.value) minY = ab.value;
|
||||
if (maxY < ab.value) maxY = ab.value;
|
||||
return FlSpot(ab.day.toDouble(), ab.value);
|
||||
}).toList();
|
||||
|
||||
_minX = spots.first.x;
|
||||
_maxX = spots.last.x;
|
||||
_minY = minY;
|
||||
_maxY = maxY;
|
||||
var yInterval = 1.1 * (_maxY - _minY) / 6;
|
||||
if (yInterval == 0) {
|
||||
yInterval = 1;
|
||||
}
|
||||
|
||||
List<Color> gradientColors = [
|
||||
theme.colorScheme.secondary,
|
||||
theme.colorScheme.primary,
|
||||
];
|
||||
|
||||
final textStyle = theme.textTheme.bodyText1!;
|
||||
final bgColor = theme.backgroundColor;
|
||||
|
||||
return LineChartData(
|
||||
gridData: FlGridData(
|
||||
show: true,
|
||||
drawVerticalLine: true,
|
||||
getDrawingHorizontalLine: (value) {
|
||||
return FlLine(
|
||||
color: theme.colorScheme.secondary.withOpacity(0.2),
|
||||
strokeWidth: 1,
|
||||
);
|
||||
},
|
||||
getDrawingVerticalLine: (value) {
|
||||
return FlLine(
|
||||
color: theme.colorScheme.secondary.withOpacity(0.2),
|
||||
strokeWidth: 1,
|
||||
);
|
||||
},
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
rightTitles: SideTitles(showTitles: false),
|
||||
topTitles: SideTitles(showTitles: false),
|
||||
bottomTitles: SideTitles(
|
||||
showTitles: true,
|
||||
reservedSize: 22,
|
||||
getTextStyles: (context, value) => TextStyle(
|
||||
color: theme.primaryColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12),
|
||||
getTitles: (v) {
|
||||
final dt = DateTime.fromMillisecondsSinceEpoch(v.toInt() * DAY_MS);
|
||||
return DateFormat.Md().format(dt);
|
||||
},
|
||||
),
|
||||
leftTitles: SideTitles(
|
||||
showTitles: true,
|
||||
getTextStyles: (context, value) => TextStyle(
|
||||
color: theme.primaryColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
getTitles: (v) {
|
||||
return numberFormat.format(v);
|
||||
},
|
||||
reservedSize: 40,
|
||||
margin: 12,
|
||||
),
|
||||
),
|
||||
borderData: FlBorderData(
|
||||
show: true, border: Border.all(color: theme.colorScheme.secondary, width: 1)),
|
||||
minX: _minX,
|
||||
maxX: _maxX,
|
||||
minY: _minY,
|
||||
maxY: _maxY,
|
||||
lineBarsData: [
|
||||
LineChartBarData(
|
||||
spots: spots,
|
||||
isCurved: false,
|
||||
colors: gradientColors,
|
||||
barWidth: 4,
|
||||
isStrokeCapRound: true,
|
||||
dotData: FlDotData(
|
||||
show: false,
|
||||
),
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
colors:
|
||||
gradientColors.map((color) => color.withOpacity(0.3)).toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
lineTouchData: LineTouchData(
|
||||
touchTooltipData: LineTouchTooltipData(
|
||||
tooltipBgColor: bgColor,
|
||||
getTooltipItems: (touchedSpots) =>
|
||||
touchedSpots.map((LineBarSpot spot) {
|
||||
final x = spot.x;
|
||||
final dt = DateTime.fromMillisecondsSinceEpoch(x.toInt() * DAY_MS);
|
||||
final xdt = DateFormat.Md().format(dt);
|
||||
final y = decimalFormat(spot.y, 3);
|
||||
return LineTooltipItem("$xdt - $y",
|
||||
textStyle);
|
||||
}).toList()
|
||||
)
|
||||
return Container(
|
||||
child: KChartWidget(datas,
|
||||
ChartStyle(), ChartColors(context: context),
|
||||
isLine: true,
|
||||
volHidden: true,
|
||||
showInfoDialog: true,
|
||||
mainState: MainState.MA,
|
||||
secondaryState: SecondaryState.NONE,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,6 @@ class Coin {
|
|||
LWInstance("Lightwalletd", "https://lite.ycash.xyz:9067"),
|
||||
];
|
||||
bool supportsUA = false;
|
||||
|
||||
bool supportsMultisig = true;
|
||||
List<int> weights = [5, 25, 250];
|
||||
}
|
||||
|
|
|
@ -11,5 +11,6 @@ class Coin {
|
|||
LWInstance("Zecwallet", "https://lwdv3.zecwallet.co"),
|
||||
];
|
||||
bool supportsUA = false;
|
||||
bool supportsMultisig = false;
|
||||
List<double> weights = [0.05, 0.25, 2.50];
|
||||
}
|
||||
|
|
|
@ -10,5 +10,6 @@ class Coin {
|
|||
LWInstance("Lightwalletd", "https://testnet.lightwalletd.com:9067"),
|
||||
];
|
||||
bool supportsUA = false;
|
||||
bool supportsMultisig = true;
|
||||
List<double> weights = [0.05, 0.25, 2.50];
|
||||
}
|
||||
|
|
|
@ -24,22 +24,29 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
static String m1(ticker) =>
|
||||
"Are you sure you want to save your contacts? It will cost 0.01 m${ticker}";
|
||||
|
||||
static String m2(ticker) =>
|
||||
static String m2(address, amount) =>
|
||||
"Do you want to sign a transaction to ${address} for ${amount}";
|
||||
|
||||
static String m3(ticker) =>
|
||||
"Do you want to transfer your entire transparent balance to your shielded address? A Network fee of 0.01 m${ticker} will be deducted.";
|
||||
|
||||
static String m3(ticker) => "Receive ${ticker}";
|
||||
static String m4(num) => "${num} more signers needed";
|
||||
|
||||
static String m4(ticker) => "Send ${ticker}";
|
||||
static String m5(ticker) => "Receive ${ticker}";
|
||||
|
||||
static String m5(ticker) => "Send ${ticker} to...";
|
||||
static String m6(ticker) => "Send ${ticker}";
|
||||
|
||||
static String m6(amount, ticker, count) =>
|
||||
static String m7(ticker) => "Send ${ticker} to...";
|
||||
|
||||
static String m8(amount, ticker, count) =>
|
||||
"Sending a total of ${amount} ${ticker} to ${count} recipients";
|
||||
|
||||
static String m7(aZEC, ticker, address) =>
|
||||
static String m9(aZEC, ticker, address) =>
|
||||
"Sending ${aZEC} ${ticker} to ${address}";
|
||||
|
||||
static String m8(currency) => "Use ${currency}";
|
||||
static String m10(text) => "${text} copied to clipboard";
|
||||
|
||||
static String m11(currency) => "Use ${currency}";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
|
@ -102,9 +109,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"color": MessageLookupByLibrary.simpleMessage("Color"),
|
||||
"confirmDeleteAccount": MessageLookupByLibrary.simpleMessage(
|
||||
"Are you SURE you want to DELETE this account? You MUST have a BACKUP to recover it. This operation is NOT reversible."),
|
||||
"confirmSignATransactionToAddressFor": m2,
|
||||
"confirmSigning":
|
||||
MessageLookupByLibrary.simpleMessage("Confirm Signing"),
|
||||
"confs": MessageLookupByLibrary.simpleMessage("Confs"),
|
||||
"contactName": MessageLookupByLibrary.simpleMessage("Contact Name"),
|
||||
"contacts": MessageLookupByLibrary.simpleMessage("Contacts"),
|
||||
"copy": MessageLookupByLibrary.simpleMessage("Copy"),
|
||||
"createANewAccount":
|
||||
MessageLookupByLibrary.simpleMessage("Tap + to add a new account"),
|
||||
"createANewContactAndItWillShowUpHere":
|
||||
|
@ -120,14 +131,18 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"doYouWantToDeleteTheSecretKeyAndConvert":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Do you want to DELETE the secret key and convert this account to a watch-only account? You will not be able to spend from this device anymore. This operation is NOT reversible."),
|
||||
"doYouWantToTransferYourEntireTransparentBalanceTo": m2,
|
||||
"doYouWantToTransferYourEntireTransparentBalanceTo": m3,
|
||||
"duplicateAccount":
|
||||
MessageLookupByLibrary.simpleMessage("Duplicate Account"),
|
||||
"duplicateContact": MessageLookupByLibrary.simpleMessage(
|
||||
"Another contact has this address"),
|
||||
"enterSecretShareIfAccountIsMultisignature":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Enter secret share if account is multi-signature"),
|
||||
"enterSeed": MessageLookupByLibrary.simpleMessage(
|
||||
"Enter Seed, Secret Key or Viewing Key. Leave blank for a new account"),
|
||||
"excludedNotes": MessageLookupByLibrary.simpleMessage("Excluded Notes"),
|
||||
"fileSaved": MessageLookupByLibrary.simpleMessage("File saved"),
|
||||
"gold": MessageLookupByLibrary.simpleMessage("Gold"),
|
||||
"height": MessageLookupByLibrary.simpleMessage("Height"),
|
||||
"help": MessageLookupByLibrary.simpleMessage("Help"),
|
||||
|
@ -150,6 +165,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"mm": MessageLookupByLibrary.simpleMessage("M/M"),
|
||||
"multiPay": MessageLookupByLibrary.simpleMessage("Multi Pay"),
|
||||
"multipay": MessageLookupByLibrary.simpleMessage("MultiPay"),
|
||||
"multipleAddresses":
|
||||
MessageLookupByLibrary.simpleMessage("multiple addresses"),
|
||||
"multisig": MessageLookupByLibrary.simpleMessage("Multisig"),
|
||||
"multisigShares":
|
||||
MessageLookupByLibrary.simpleMessage("Multisig Shares"),
|
||||
"na": MessageLookupByLibrary.simpleMessage("N/A"),
|
||||
"nameIsEmpty": MessageLookupByLibrary.simpleMessage("Name is empty"),
|
||||
"newSnapAddress":
|
||||
|
@ -164,6 +184,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"notEnoughBalance":
|
||||
MessageLookupByLibrary.simpleMessage("Not enough balance"),
|
||||
"notes": MessageLookupByLibrary.simpleMessage("Notes"),
|
||||
"numMoreSignersNeeded": m4,
|
||||
"numberOfConfirmationsNeededBeforeSpending":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Number of Confirmations Needed before Spending"),
|
||||
|
@ -190,7 +211,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"purple": MessageLookupByLibrary.simpleMessage("Purple"),
|
||||
"qty": MessageLookupByLibrary.simpleMessage("Qty"),
|
||||
"realized": MessageLookupByLibrary.simpleMessage("Realized"),
|
||||
"receive": m3,
|
||||
"receive": m5,
|
||||
"receivePayment":
|
||||
MessageLookupByLibrary.simpleMessage("Receive Payment"),
|
||||
"rescan": MessageLookupByLibrary.simpleMessage("Rescan"),
|
||||
|
@ -209,16 +230,17 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage("Scan starting momentarily"),
|
||||
"secondary": MessageLookupByLibrary.simpleMessage("Secondary"),
|
||||
"secretKey": MessageLookupByLibrary.simpleMessage("Secret Key"),
|
||||
"secretShare": MessageLookupByLibrary.simpleMessage("Secret Share"),
|
||||
"seed": MessageLookupByLibrary.simpleMessage("Seed"),
|
||||
"selectAccount": MessageLookupByLibrary.simpleMessage("Select Account"),
|
||||
"selectNotesToExcludeFromPayments":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Select notes to EXCLUDE from payments"),
|
||||
"send": MessageLookupByLibrary.simpleMessage("Send"),
|
||||
"sendCointicker": m4,
|
||||
"sendCointickerTo": m5,
|
||||
"sendingATotalOfAmountCointickerToCountRecipients": m6,
|
||||
"sendingAzecCointickerToAddress": m7,
|
||||
"sendCointicker": m6,
|
||||
"sendCointickerTo": m7,
|
||||
"sendingATotalOfAmountCointickerToCountRecipients": m8,
|
||||
"sendingAzecCointickerToAddress": m9,
|
||||
"server": MessageLookupByLibrary.simpleMessage("Server"),
|
||||
"settings": MessageLookupByLibrary.simpleMessage("Settings"),
|
||||
"shieldTranspBalance":
|
||||
|
@ -230,9 +252,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Shield Transparent Balance When Sending"),
|
||||
"shieldingInProgress":
|
||||
MessageLookupByLibrary.simpleMessage("Shielding in progress..."),
|
||||
"sign": MessageLookupByLibrary.simpleMessage("Sign Transaction"),
|
||||
"spendable": MessageLookupByLibrary.simpleMessage("Spendable"),
|
||||
"spendableBalance":
|
||||
MessageLookupByLibrary.simpleMessage("Spendable Balance"),
|
||||
"splitAccount": MessageLookupByLibrary.simpleMessage("Split Account"),
|
||||
"synching": MessageLookupByLibrary.simpleMessage("Synching"),
|
||||
"table": MessageLookupByLibrary.simpleMessage("Table"),
|
||||
"tapAnIconToShowTheQrCode": MessageLookupByLibrary.simpleMessage(
|
||||
|
@ -246,6 +270,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Tap QR Code for Transparent Address"),
|
||||
"tapTransactionForDetails":
|
||||
MessageLookupByLibrary.simpleMessage("Tap Transaction for Details"),
|
||||
"textCopiedToClipboard": m10,
|
||||
"theme": MessageLookupByLibrary.simpleMessage("Theme"),
|
||||
"themeEditor": MessageLookupByLibrary.simpleMessage("Theme Editor"),
|
||||
"thisAccountAlreadyExists": MessageLookupByLibrary.simpleMessage(
|
||||
|
@ -274,7 +299,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage("Unshielded Balance"),
|
||||
"unsignedTransactionFile":
|
||||
MessageLookupByLibrary.simpleMessage("Unsigned Transaction File"),
|
||||
"useSettingscurrency": m8,
|
||||
"useSettingscurrency": m11,
|
||||
"useTransparentBalance":
|
||||
MessageLookupByLibrary.simpleMessage("Use Transparent Balance"),
|
||||
"useUa": MessageLookupByLibrary.simpleMessage("Use UA"),
|
||||
|
|
|
@ -24,22 +24,27 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
static String m1(ticker) =>
|
||||
"Estás seguro de que quieres guardar tus contactos? Costará 0,01 mZEC ";
|
||||
|
||||
static String m2(ticker) =>
|
||||
static String m2(address, amount) =>
|
||||
"Do you want to sign a transaction to ${address} for ${amount}";
|
||||
|
||||
static String m3(ticker) =>
|
||||
"¿Quiere transferir su saldo transparente a su dirección blindada? ";
|
||||
|
||||
static String m3(ticker) => "Recibir ${ticker}";
|
||||
static String m5(ticker) => "Recibir ${ticker}";
|
||||
|
||||
static String m4(ticker) => "Enviar ${ticker}";
|
||||
static String m6(ticker) => "Enviar ${ticker}";
|
||||
|
||||
static String m5(ticker) => "Enviar ${ticker} a…";
|
||||
static String m7(ticker) => "Enviar ${ticker} a…";
|
||||
|
||||
static String m6(amount, ticker, count) =>
|
||||
static String m8(amount, ticker, count) =>
|
||||
"Enviando un total de ${amount} ${ticker} a ${count} direcciones";
|
||||
|
||||
static String m7(aZEC, ticker, address) =>
|
||||
static String m9(aZEC, ticker, address) =>
|
||||
"Enviado ${aZEC} ${ticker} a ${address}";
|
||||
|
||||
static String m8(currency) => "Utilizar ${currency}";
|
||||
static String m10(text) => "${text} copied to clipboard";
|
||||
|
||||
static String m11(currency) => "Utilizar ${currency}";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
|
@ -102,10 +107,14 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"color": MessageLookupByLibrary.simpleMessage("Color"),
|
||||
"confirmDeleteAccount": MessageLookupByLibrary.simpleMessage(
|
||||
"¿Está SEGURO de que desea BORRAR esta cuenta? DEBE tener una COPIA DE SEGURIDAD para recuperarla. Esta operación NO es reversible."),
|
||||
"confirmSignATransactionToAddressFor": m2,
|
||||
"confirmSigning":
|
||||
MessageLookupByLibrary.simpleMessage("Confirm Signing"),
|
||||
"confs": MessageLookupByLibrary.simpleMessage("Confs"),
|
||||
"contactName":
|
||||
MessageLookupByLibrary.simpleMessage("Nombre de contacto"),
|
||||
"contacts": MessageLookupByLibrary.simpleMessage("Contactos"),
|
||||
"copy": MessageLookupByLibrary.simpleMessage("Copy"),
|
||||
"createANewAccount": MessageLookupByLibrary.simpleMessage(
|
||||
"Crea una cuenta y aparecerá aquí."),
|
||||
"createANewContactAndItWillShowUpHere":
|
||||
|
@ -123,13 +132,17 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"doYouWantToDeleteTheSecretKeyAndConvert":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"¿Quiere BORRAR la clave secreta y convertir esta cuenta a solo lectura? Ya no podrá gastar desde este dispositivo. Esta operación NO es reversible."),
|
||||
"doYouWantToTransferYourEntireTransparentBalanceTo": m2,
|
||||
"doYouWantToTransferYourEntireTransparentBalanceTo": m3,
|
||||
"duplicateAccount":
|
||||
MessageLookupByLibrary.simpleMessage("Cuenta duplicada"),
|
||||
"enterSecretShareIfAccountIsMultisignature":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Enter secret share if account is multi-signature"),
|
||||
"enterSeed": MessageLookupByLibrary.simpleMessage(
|
||||
"Ingrese Semilla, Clave Secreta o Clave Lectura. Dejar en blanco para una nueva cuenta "),
|
||||
"excludedNotes":
|
||||
MessageLookupByLibrary.simpleMessage("Notas Excluidas"),
|
||||
"fileSaved": MessageLookupByLibrary.simpleMessage("File saved"),
|
||||
"gold": MessageLookupByLibrary.simpleMessage("Oro"),
|
||||
"height": MessageLookupByLibrary.simpleMessage("Altura"),
|
||||
"help": MessageLookupByLibrary.simpleMessage("Ayuda"),
|
||||
|
@ -151,6 +164,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"mm": MessageLookupByLibrary.simpleMessage("M/M"),
|
||||
"multiPay": MessageLookupByLibrary.simpleMessage("Multi Pagos"),
|
||||
"multipay": MessageLookupByLibrary.simpleMessage("MultiPagos"),
|
||||
"multipleAddresses":
|
||||
MessageLookupByLibrary.simpleMessage("multiple addresses"),
|
||||
"multisig": MessageLookupByLibrary.simpleMessage("Multisig"),
|
||||
"multisigShares":
|
||||
MessageLookupByLibrary.simpleMessage("Multisig Shares"),
|
||||
"na": MessageLookupByLibrary.simpleMessage("N/A"),
|
||||
"nameIsEmpty": MessageLookupByLibrary.simpleMessage("Nombre vacio"),
|
||||
"newSnapAddress":
|
||||
|
@ -192,7 +210,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"purple": MessageLookupByLibrary.simpleMessage("Morada"),
|
||||
"qty": MessageLookupByLibrary.simpleMessage("Cantidad"),
|
||||
"realized": MessageLookupByLibrary.simpleMessage("Dio Cuenta"),
|
||||
"receive": m3,
|
||||
"receive": m5,
|
||||
"receivePayment":
|
||||
MessageLookupByLibrary.simpleMessage("Recibir un pago"),
|
||||
"rescan": MessageLookupByLibrary.simpleMessage("Escanear"),
|
||||
|
@ -212,6 +230,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Escaneo comenzando momentáneamente "),
|
||||
"secondary": MessageLookupByLibrary.simpleMessage("Secundario"),
|
||||
"secretKey": MessageLookupByLibrary.simpleMessage("Llave Secreta"),
|
||||
"secretShare": MessageLookupByLibrary.simpleMessage("Secret Share"),
|
||||
"seed": MessageLookupByLibrary.simpleMessage("Semilla"),
|
||||
"selectAccount":
|
||||
MessageLookupByLibrary.simpleMessage("Seleccionar cuenta"),
|
||||
|
@ -219,10 +238,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage(
|
||||
"Seleccionar Notas a EXCLUIR de los pagos"),
|
||||
"send": MessageLookupByLibrary.simpleMessage("Enviar"),
|
||||
"sendCointicker": m4,
|
||||
"sendCointickerTo": m5,
|
||||
"sendingATotalOfAmountCointickerToCountRecipients": m6,
|
||||
"sendingAzecCointickerToAddress": m7,
|
||||
"sendCointicker": m6,
|
||||
"sendCointickerTo": m7,
|
||||
"sendingATotalOfAmountCointickerToCountRecipients": m8,
|
||||
"sendingAzecCointickerToAddress": m9,
|
||||
"server": MessageLookupByLibrary.simpleMessage("Servidor"),
|
||||
"settings": MessageLookupByLibrary.simpleMessage("Ajustes"),
|
||||
"shieldTranspBalance":
|
||||
|
@ -231,9 +250,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage("Blindar Saldo Transparente"),
|
||||
"shieldingInProgress":
|
||||
MessageLookupByLibrary.simpleMessage("Blindaje en progreso…"),
|
||||
"sign": MessageLookupByLibrary.simpleMessage("Sign"),
|
||||
"spendable": MessageLookupByLibrary.simpleMessage("Gastable"),
|
||||
"spendableBalance":
|
||||
MessageLookupByLibrary.simpleMessage("Saldo Gastable"),
|
||||
"splitAccount": MessageLookupByLibrary.simpleMessage("Split Account"),
|
||||
"synching": MessageLookupByLibrary.simpleMessage("Sincronizando"),
|
||||
"table": MessageLookupByLibrary.simpleMessage("Lista"),
|
||||
"tapAnIconToShowTheQrCode": MessageLookupByLibrary.simpleMessage(
|
||||
|
@ -247,6 +268,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Pinchar QR para Dirección Transparente"),
|
||||
"tapTransactionForDetails": MessageLookupByLibrary.simpleMessage(
|
||||
"Toque Transacción para detalles"),
|
||||
"textCopiedToClipboard": m10,
|
||||
"theme": MessageLookupByLibrary.simpleMessage("Tema"),
|
||||
"themeEditor": MessageLookupByLibrary.simpleMessage("Editora de temas"),
|
||||
"thisAccountAlreadyExists":
|
||||
|
@ -275,7 +297,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage("Saldo sin blindaje"),
|
||||
"unsignedTransactionFile": MessageLookupByLibrary.simpleMessage(
|
||||
"Archivo de transaccion sin firmar"),
|
||||
"useSettingscurrency": m8,
|
||||
"useSettingscurrency": m11,
|
||||
"useTransparentBalance":
|
||||
MessageLookupByLibrary.simpleMessage("Usar Saldo Transp"),
|
||||
"useUa": MessageLookupByLibrary.simpleMessage("Usar UA"),
|
||||
|
|
|
@ -24,22 +24,27 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
static String m1(ticker) =>
|
||||
"Voulez vous sauver vos contacts? Ceci coute 0.01 m${ticker}";
|
||||
|
||||
static String m2(ticker) =>
|
||||
static String m2(address, amount) =>
|
||||
"Do you want to sign a transaction to ${address} for ${amount}";
|
||||
|
||||
static String m3(ticker) =>
|
||||
"Voulez-vous transférer l\'intégralité de votre solde transparent à votre adresse protégée?";
|
||||
|
||||
static String m3(ticker) => "Recevoir ${ticker}";
|
||||
static String m5(ticker) => "Recevoir ${ticker}";
|
||||
|
||||
static String m4(ticker) => "Envoyer ${ticker}";
|
||||
static String m6(ticker) => "Envoyer ${ticker}";
|
||||
|
||||
static String m5(ticker) => "Envoyer ${ticker} à...";
|
||||
static String m7(ticker) => "Envoyer ${ticker} à...";
|
||||
|
||||
static String m6(amount, ticker, count) =>
|
||||
static String m8(amount, ticker, count) =>
|
||||
"Envoi d\'un total de ${amount} ${ticker} à ${count} destinataires";
|
||||
|
||||
static String m7(aZEC, ticker, address) =>
|
||||
static String m9(aZEC, ticker, address) =>
|
||||
"Envoi de ${aZEC} ${ticker} à ${address}";
|
||||
|
||||
static String m8(currency) => "Utiliser ${currency}";
|
||||
static String m10(text) => "${text} copied to clipboard";
|
||||
|
||||
static String m11(currency) => "Utiliser ${currency}";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
|
@ -104,9 +109,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"color": MessageLookupByLibrary.simpleMessage("Couleur"),
|
||||
"confirmDeleteAccount": MessageLookupByLibrary.simpleMessage(
|
||||
"Êtes-vous SUR de vouloir SUPPRIMER ce compte ? Vous DEVEZ avoir une SAUVEGARDE pour le récupérer. Cette opération n\'est PAS réversible."),
|
||||
"confirmSignATransactionToAddressFor": m2,
|
||||
"confirmSigning":
|
||||
MessageLookupByLibrary.simpleMessage("Confirm Signing"),
|
||||
"confs": MessageLookupByLibrary.simpleMessage("Confs"),
|
||||
"contactName": MessageLookupByLibrary.simpleMessage("Nom du Contact"),
|
||||
"contacts": MessageLookupByLibrary.simpleMessage("Mes Contacts"),
|
||||
"copy": MessageLookupByLibrary.simpleMessage("Copy"),
|
||||
"createANewAccount": MessageLookupByLibrary.simpleMessage(
|
||||
"Créez un nouveau compte et il apparaîtra ici"),
|
||||
"createANewContactAndItWillShowUpHere":
|
||||
|
@ -125,12 +134,16 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"doYouWantToDeleteTheSecretKeyAndConvert":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Voulez-vous SUPPRIMER la clé secrète et convertir ce compte en un compte d\'observation ? Vous ne pourrez plus dépenser depuis cet appareil. Cette opération n\'est PAS réversible."),
|
||||
"doYouWantToTransferYourEntireTransparentBalanceTo": m2,
|
||||
"doYouWantToTransferYourEntireTransparentBalanceTo": m3,
|
||||
"duplicateAccount":
|
||||
MessageLookupByLibrary.simpleMessage("Compte en double"),
|
||||
"enterSecretShareIfAccountIsMultisignature":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Enter secret share if account is multi-signature"),
|
||||
"enterSeed": MessageLookupByLibrary.simpleMessage(
|
||||
"Entrez la graine, la clé secrète ou la clé de visualisation. Laissez vide pour un nouveau compte"),
|
||||
"excludedNotes": MessageLookupByLibrary.simpleMessage("Billets exclus"),
|
||||
"fileSaved": MessageLookupByLibrary.simpleMessage("File saved"),
|
||||
"gold": MessageLookupByLibrary.simpleMessage("Or"),
|
||||
"height": MessageLookupByLibrary.simpleMessage("Hauteur"),
|
||||
"help": MessageLookupByLibrary.simpleMessage("Aide"),
|
||||
|
@ -152,6 +165,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"mm": MessageLookupByLibrary.simpleMessage("Virtuel"),
|
||||
"multiPay": MessageLookupByLibrary.simpleMessage("Envoyer à plusieurs"),
|
||||
"multipay": MessageLookupByLibrary.simpleMessage("Envoyer à plusieurs"),
|
||||
"multipleAddresses":
|
||||
MessageLookupByLibrary.simpleMessage("multiple addresses"),
|
||||
"multisig": MessageLookupByLibrary.simpleMessage("Multisig"),
|
||||
"multisigShares":
|
||||
MessageLookupByLibrary.simpleMessage("Multisig Shares"),
|
||||
"na": MessageLookupByLibrary.simpleMessage("N/D"),
|
||||
"nameIsEmpty": MessageLookupByLibrary.simpleMessage("Le nom est vide"),
|
||||
"newSnapAddress": MessageLookupByLibrary.simpleMessage(
|
||||
|
@ -194,7 +212,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"purple": MessageLookupByLibrary.simpleMessage("Violet"),
|
||||
"qty": MessageLookupByLibrary.simpleMessage("Quantité"),
|
||||
"realized": MessageLookupByLibrary.simpleMessage("Réalisé"),
|
||||
"receive": m3,
|
||||
"receive": m5,
|
||||
"receivePayment":
|
||||
MessageLookupByLibrary.simpleMessage("Recevoir un payment"),
|
||||
"rescan": MessageLookupByLibrary.simpleMessage("Parcourir à nouveau"),
|
||||
|
@ -213,6 +231,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Le scan démarre momentanément"),
|
||||
"secondary": MessageLookupByLibrary.simpleMessage("Secondaire"),
|
||||
"secretKey": MessageLookupByLibrary.simpleMessage("Clé secrète"),
|
||||
"secretShare": MessageLookupByLibrary.simpleMessage("Secret Share"),
|
||||
"seed": MessageLookupByLibrary.simpleMessage("Graine"),
|
||||
"selectAccount":
|
||||
MessageLookupByLibrary.simpleMessage("Choisissez un compte"),
|
||||
|
@ -220,10 +239,10 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage(
|
||||
"Sélectionnez les billets à EXCLURE des paiements"),
|
||||
"send": MessageLookupByLibrary.simpleMessage("Envoyer"),
|
||||
"sendCointicker": m4,
|
||||
"sendCointickerTo": m5,
|
||||
"sendingATotalOfAmountCointickerToCountRecipients": m6,
|
||||
"sendingAzecCointickerToAddress": m7,
|
||||
"sendCointicker": m6,
|
||||
"sendCointickerTo": m7,
|
||||
"sendingATotalOfAmountCointickerToCountRecipients": m8,
|
||||
"sendingAzecCointickerToAddress": m9,
|
||||
"server": MessageLookupByLibrary.simpleMessage("Serveur"),
|
||||
"settings": MessageLookupByLibrary.simpleMessage("Paramètres"),
|
||||
"shieldTranspBalance": MessageLookupByLibrary.simpleMessage(
|
||||
|
@ -232,9 +251,11 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Masquer le solde transparent"),
|
||||
"shieldingInProgress":
|
||||
MessageLookupByLibrary.simpleMessage("Masquage en cours..."),
|
||||
"sign": MessageLookupByLibrary.simpleMessage("Sign"),
|
||||
"spendable": MessageLookupByLibrary.simpleMessage("Dépensable"),
|
||||
"spendableBalance":
|
||||
MessageLookupByLibrary.simpleMessage("Montant dépensable"),
|
||||
"splitAccount": MessageLookupByLibrary.simpleMessage("Split Account"),
|
||||
"synching":
|
||||
MessageLookupByLibrary.simpleMessage("Synchronisation en cours"),
|
||||
"table": MessageLookupByLibrary.simpleMessage("Tableau"),
|
||||
|
@ -249,6 +270,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Appuyez sur le code QR pour l\'adresse transparente"),
|
||||
"tapTransactionForDetails": MessageLookupByLibrary.simpleMessage(
|
||||
"Presser sur une Transaction pour plus de details"),
|
||||
"textCopiedToClipboard": m10,
|
||||
"theme": MessageLookupByLibrary.simpleMessage("Thème"),
|
||||
"themeEditor": MessageLookupByLibrary.simpleMessage("Editeur de Thème"),
|
||||
"thisAccountAlreadyExists":
|
||||
|
@ -277,7 +299,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage("Solde Transparent"),
|
||||
"unsignedTransactionFile": MessageLookupByLibrary.simpleMessage(
|
||||
"Fichier de transaction non signée"),
|
||||
"useSettingscurrency": m8,
|
||||
"useSettingscurrency": m11,
|
||||
"useTransparentBalance": MessageLookupByLibrary.simpleMessage(
|
||||
"Utiliser le Solde Transparent"),
|
||||
"useUa": MessageLookupByLibrary.simpleMessage("Utiliser UA"),
|
||||
|
|
|
@ -1661,6 +1661,136 @@ class S {
|
|||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Multisig`
|
||||
String get multisig {
|
||||
return Intl.message(
|
||||
'Multisig',
|
||||
name: 'multisig',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Enter secret share if account is multi-signature`
|
||||
String get enterSecretShareIfAccountIsMultisignature {
|
||||
return Intl.message(
|
||||
'Enter secret share if account is multi-signature',
|
||||
name: 'enterSecretShareIfAccountIsMultisignature',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Secret Share`
|
||||
String get secretShare {
|
||||
return Intl.message(
|
||||
'Secret Share',
|
||||
name: 'secretShare',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `File saved`
|
||||
String get fileSaved {
|
||||
return Intl.message(
|
||||
'File saved',
|
||||
name: 'fileSaved',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `{num} more signers needed`
|
||||
String numMoreSignersNeeded(Object num) {
|
||||
return Intl.message(
|
||||
'$num more signers needed',
|
||||
name: 'numMoreSignersNeeded',
|
||||
desc: '',
|
||||
args: [num],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Sign Transaction`
|
||||
String get sign {
|
||||
return Intl.message(
|
||||
'Sign Transaction',
|
||||
name: 'sign',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Split Account`
|
||||
String get splitAccount {
|
||||
return Intl.message(
|
||||
'Split Account',
|
||||
name: 'splitAccount',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Confirm Signing`
|
||||
String get confirmSigning {
|
||||
return Intl.message(
|
||||
'Confirm Signing',
|
||||
name: 'confirmSigning',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Do you want to sign a transaction to {address} for {amount}`
|
||||
String confirmSignATransactionToAddressFor(Object address, Object amount) {
|
||||
return Intl.message(
|
||||
'Do you want to sign a transaction to $address for $amount',
|
||||
name: 'confirmSignATransactionToAddressFor',
|
||||
desc: '',
|
||||
args: [address, amount],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Multisig Shares`
|
||||
String get multisigShares {
|
||||
return Intl.message(
|
||||
'Multisig Shares',
|
||||
name: 'multisigShares',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Copy`
|
||||
String get copy {
|
||||
return Intl.message(
|
||||
'Copy',
|
||||
name: 'copy',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `{text} copied to clipboard`
|
||||
String textCopiedToClipboard(Object text) {
|
||||
return Intl.message(
|
||||
'$text copied to clipboard',
|
||||
name: 'textCopiedToClipboard',
|
||||
desc: '',
|
||||
args: [text],
|
||||
);
|
||||
}
|
||||
|
||||
/// `multiple addresses`
|
||||
String get multipleAddresses {
|
||||
return Intl.message(
|
||||
'multiple addresses',
|
||||
name: 'multipleAddresses',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
|
|
@ -159,5 +159,18 @@
|
|||
"color": "Color",
|
||||
"accentColor": "Accent Color",
|
||||
"primary": "Primary",
|
||||
"secondary": "Secondary"
|
||||
"secondary": "Secondary",
|
||||
"multisig": "Multisig",
|
||||
"enterSecretShareIfAccountIsMultisignature": "Enter secret share if account is multi-signature",
|
||||
"secretShare": "Secret Share",
|
||||
"fileSaved": "File saved",
|
||||
"numMoreSignersNeeded": "{num} more signers needed",
|
||||
"sign": "Sign Transaction",
|
||||
"splitAccount": "Split Account",
|
||||
"confirmSigning": "Confirm Signing",
|
||||
"confirmSignATransactionToAddressFor": "Do you want to sign a transaction to {address} for {amount}",
|
||||
"multisigShares": "Multisig Shares",
|
||||
"copy": "Copy",
|
||||
"textCopiedToClipboard": "{text} copied to clipboard",
|
||||
"multipleAddresses": "multiple addresses"
|
||||
}
|
||||
|
|
|
@ -159,5 +159,17 @@
|
|||
"color": "Color",
|
||||
"accentColor": "Acento Color",
|
||||
"primary": "Primario",
|
||||
"secondary": "Secundario"
|
||||
"secondary": "Secundario",
|
||||
"multisig": "Multisig",
|
||||
"enterSecretShareIfAccountIsMultisignature": "Enter secret share if account is multi-signature",
|
||||
"secretShare": "Secret Share",
|
||||
"fileSaved": "File saved",
|
||||
"sign": "Sign",
|
||||
"splitAccount": "Split Account",
|
||||
"confirmSigning": "Confirm Signing",
|
||||
"confirmSignATransactionToAddressFor": "Do you want to sign a transaction to {address} for {amount}",
|
||||
"multisigShares": "Multisig Shares",
|
||||
"copy": "Copy",
|
||||
"textCopiedToClipboard": "{text} copied to clipboard",
|
||||
"multipleAddresses": "multiple addresses"
|
||||
}
|
||||
|
|
|
@ -159,5 +159,17 @@
|
|||
"color": "Couleur",
|
||||
"accentColor": "Couleur d'accent",
|
||||
"primary": "Primaire",
|
||||
"secondary": "Secondaire"
|
||||
"secondary": "Secondaire",
|
||||
"multisig": "Multisig",
|
||||
"enterSecretShareIfAccountIsMultisignature": "Enter secret share if account is multi-signature",
|
||||
"secretShare": "Secret Share",
|
||||
"fileSaved": "File saved",
|
||||
"sign": "Sign",
|
||||
"splitAccount": "Split Account",
|
||||
"confirmSigning": "Confirm Signing",
|
||||
"confirmSignATransactionToAddressFor": "Do you want to sign a transaction to {address} for {amount}",
|
||||
"multisigShares": "Multisig Shares",
|
||||
"copy": "Copy",
|
||||
"textCopiedToClipboard": "{text} copied to clipboard",
|
||||
"multipleAddresses": "multiple addresses"
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import 'account_manager.dart';
|
|||
import 'backup.dart';
|
||||
import 'coin/coindef.dart';
|
||||
import 'multisend.dart';
|
||||
import 'multisign.dart';
|
||||
import 'payment_uri.dart';
|
||||
import 'settings.dart';
|
||||
import 'restore.dart';
|
||||
|
@ -92,6 +93,7 @@ void handleQuickAction(BuildContext context, String shortcut) {
|
|||
void main() {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final home = ZWalletApp();
|
||||
// final home = MultisigPage();
|
||||
runApp(FutureBuilder(
|
||||
future: settings.restore(),
|
||||
builder: (context, snapshot) {
|
||||
|
@ -127,6 +129,9 @@ void main() {
|
|||
TransactionPage(routeSettings.arguments as Tx),
|
||||
'/backup': (context) => BackupPage(routeSettings.arguments as int?),
|
||||
'/multipay': (context) => MultiPayPage(),
|
||||
'/multisig': (context) => MultisigPage(),
|
||||
'/multisign': (context) => MultisigAggregatorPage(routeSettings.arguments as TxSummary),
|
||||
'/multisig_shares': (context) => MultisigSharesPage(routeSettings.arguments as String),
|
||||
'/edit_theme': (context) => ThemeEditorPage(onSaved: settings.updateCustomThemeColors),
|
||||
};
|
||||
return MaterialPageRoute(builder: routes[routeSettings.name]!);
|
||||
|
@ -264,14 +269,26 @@ String unwrapUA(String address) {
|
|||
return zaddr.isNotEmpty ? zaddr : address;
|
||||
}
|
||||
|
||||
void showQR(BuildContext context, String text) {
|
||||
void showQR(BuildContext context, String text, String title) {
|
||||
final s = S.of(context);
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierColor: Colors.black,
|
||||
builder: (context) => AlertDialog(
|
||||
content: Container(
|
||||
width: double.maxFinite,
|
||||
child: QrImage(data: text, backgroundColor: Colors.white)),
|
||||
child: SingleChildScrollView(child: Column(children: [
|
||||
QrImage(data: text, backgroundColor: Colors.white),
|
||||
Padding(padding: EdgeInsets.all(8)),
|
||||
Text(title, style: Theme.of(context).textTheme.subtitle1),
|
||||
Padding(padding: EdgeInsets.all(4)),
|
||||
ElevatedButton.icon(onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
Clipboard.setData(ClipboardData(text: text));
|
||||
final snackBar = SnackBar(content: Text(s.textCopiedToClipboard(title)));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar);
|
||||
}, icon: Icon(Icons.copy), label: Text(s.copy))
|
||||
])))
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -2,17 +2,18 @@ import 'dart:convert';
|
|||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:warp/store.dart';
|
||||
import 'package:warp_api/warp_api.dart';
|
||||
import 'package:warp_api/types.dart';
|
||||
|
||||
import 'dualmoneyinput.dart';
|
||||
import 'main.dart';
|
||||
import 'generated/l10n.dart';
|
||||
import 'send.dart';
|
||||
|
||||
class MultiPayPage extends StatefulWidget {
|
||||
@override
|
||||
|
@ -51,14 +52,9 @@ class MultiPayState extends State<MultiPayPage> {
|
|||
}
|
||||
|
||||
_add() async {
|
||||
final r = await showDialog<Recipient>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => Dialog(
|
||||
child: PayRecipient(),
|
||||
));
|
||||
if (r != null) {
|
||||
multipayData.addRecipient(r);
|
||||
final recipient = await Navigator.of(context).pushNamed('/send', arguments: SendPageArgs(isMulti: true, recipients: multipayData.recipients)) as Recipient?;
|
||||
if (recipient != null) {
|
||||
multipayData.addRecipient(recipient);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,17 +84,7 @@ class MultiPayState extends State<MultiPayPage> {
|
|||
cancelValue: false)));
|
||||
|
||||
if (approved) {
|
||||
final s = S.of(context);
|
||||
Navigator.of(context).pop();
|
||||
|
||||
final snackBar1 = SnackBar(content: Text(s.preparingTransaction));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar1);
|
||||
|
||||
final recipientsJson = jsonEncode(multipayData.recipients);
|
||||
final tx = await WarpApi.sendMultiPayment(accountManager.active.id,
|
||||
recipientsJson, settings.anchorOffset, (p) {});
|
||||
final snackBar2 = SnackBar(content: Text("${s.txId}: $tx"));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar2);
|
||||
await send(context, multipayData.recipients, false);
|
||||
|
||||
multipayData.clear();
|
||||
await accountManager.fetchAccountData(true);
|
||||
|
@ -106,105 +92,6 @@ class MultiPayState extends State<MultiPayPage> {
|
|||
}
|
||||
}
|
||||
|
||||
class PayRecipient extends StatefulWidget {
|
||||
PayRecipient();
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => PayRecipientState();
|
||||
}
|
||||
|
||||
class PayRecipientState extends State<PayRecipient> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _addressController = TextEditingController();
|
||||
final _memoController = TextEditingController();
|
||||
final amountKey = GlobalKey<DualMoneyInputState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
}, child: Form(
|
||||
key: _formKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(children: <Widget>[
|
||||
Row(children: <Widget>[
|
||||
Expanded(
|
||||
child: TypeAheadFormField(
|
||||
textFieldConfiguration: TextFieldConfiguration(
|
||||
decoration: InputDecoration(
|
||||
labelText:
|
||||
S.of(context).sendCointickerTo(coin.ticker)),
|
||||
controller: _addressController,
|
||||
minLines: 4,
|
||||
maxLines: 10,
|
||||
keyboardType: TextInputType.multiline),
|
||||
validator: _checkAddress,
|
||||
onSuggestionSelected: (Contact contact) {
|
||||
_addressController.text = contact.name;
|
||||
},
|
||||
suggestionsCallback: (String pattern) {
|
||||
return contacts.contacts.where((c) =>
|
||||
c.name.toLowerCase().contains(pattern.toLowerCase()));
|
||||
},
|
||||
itemBuilder: (BuildContext context, Contact c) =>
|
||||
ListTile(title: Text(c.name)),
|
||||
noItemsFoundBuilder: (_) => SizedBox(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: new Icon(MdiIcons.qrcodeScan), onPressed: _onScan)
|
||||
]),
|
||||
DualMoneyInputWidget(key: amountKey),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(labelText: S.of(context).memo),
|
||||
minLines: 4,
|
||||
maxLines: null,
|
||||
keyboardType: TextInputType.multiline,
|
||||
controller: _memoController,
|
||||
),
|
||||
ButtonBar(
|
||||
children: confirmButtons(context, _onAdd,
|
||||
okLabel: S.of(context).add, okIcon: Icon(MdiIcons.plus)))
|
||||
]),
|
||||
)));
|
||||
}
|
||||
|
||||
void _onScan() async {
|
||||
final address = await scanCode(context);
|
||||
if (address != null)
|
||||
setState(() {
|
||||
_addressController.text = address;
|
||||
});
|
||||
}
|
||||
|
||||
void _onAdd() {
|
||||
final form = _formKey.currentState!;
|
||||
|
||||
if (form.validate()) {
|
||||
form.save();
|
||||
final amount = amountKey.currentState!.amount;
|
||||
final c =
|
||||
contacts.contacts.where((c) => c.name == _addressController.text);
|
||||
final address =
|
||||
c.isEmpty ? unwrapUA(_addressController.text) : c.first.address;
|
||||
final r = Recipient(
|
||||
address, amount, _memoController.text);
|
||||
Navigator.of(context).pop(r);
|
||||
}
|
||||
}
|
||||
|
||||
String? _checkAddress(String? v) {
|
||||
if (v == null || v.isEmpty) return S.of(context).addressIsEmpty;
|
||||
final c = contacts.contacts.where((c) => c.name == v);
|
||||
if (c.isNotEmpty) return null;
|
||||
final zaddr = WarpApi.getSaplingFromUA(v);
|
||||
if (zaddr.isNotEmpty) return null;
|
||||
if (!WarpApi.validAddress(v)) return S.of(context).invalidAddress;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class NoRecipient extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -0,0 +1,299 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:network_info_plus/network_info_plus.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
import 'package:warp/store.dart';
|
||||
import 'package:warp_api/warp_api.dart';
|
||||
import 'generated/l10n.dart';
|
||||
import 'package:convert/convert.dart';
|
||||
|
||||
import 'main.dart';
|
||||
|
||||
const PORT = 4000;
|
||||
|
||||
class MultisigAggregatorPage extends StatefulWidget {
|
||||
final TxSummary txSummary;
|
||||
|
||||
MultisigAggregatorPage(this.txSummary);
|
||||
|
||||
@override
|
||||
MultisigAggregatorState createState() => MultisigAggregatorState();
|
||||
}
|
||||
|
||||
class MultisigAggregatorState extends State<MultisigAggregatorPage> {
|
||||
String _wifiIP = '';
|
||||
ShareInfo? _shareInfo;
|
||||
int _peerCount = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Future.microtask(() async {
|
||||
var peerPort = ReceivePort();
|
||||
var peerStream = peerPort.asBroadcastStream();
|
||||
peerStream.listen((_) {
|
||||
print("Received a new peer");
|
||||
_peerCount += 1;
|
||||
});
|
||||
|
||||
final info = NetworkInfo();
|
||||
final wifiIP = await info.getWifiIP() ?? '';
|
||||
final shareInfo = await accountManager.getShareInfo(accountManager.active.id);
|
||||
_runAggregator(peerPort.sendPort);
|
||||
setState(() {
|
||||
_wifiIP = wifiIP;
|
||||
_shareInfo = shareInfo;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_stopAggregator();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final qrSize = getScreenSize(context) / 2.5;
|
||||
final shareInfo = _shareInfo;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Sign Multisig Transaction'),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Column(children: [
|
||||
QrImage(
|
||||
data: txSummaryString,
|
||||
size: qrSize,
|
||||
backgroundColor: Colors.white),
|
||||
Padding(padding: EdgeInsets.all(8)),
|
||||
Text('Scan this code on your other devices'),
|
||||
]),
|
||||
if (shareInfo != null)
|
||||
SignerPie(qrSize.toInt(), _peerCount + 1,
|
||||
shareInfo.threshold, shareInfo.participants),
|
||||
],
|
||||
)));
|
||||
}
|
||||
|
||||
void _runAggregator(SendPort port) async {
|
||||
final s = S.of(context);
|
||||
await WarpApi.runAggregator(accountManager.active.share!.value, PORT, port);
|
||||
// Need to wait a bit for the service to spin up
|
||||
await Future.delayed(Duration(seconds: 3));
|
||||
final tx = await WarpApi.submitTx(widget.txSummary.txJson, PORT);
|
||||
SnackBar snackBar;
|
||||
if (tx.startsWith("00")) { // first byte is success/error
|
||||
final txId = WarpApi.broadcastHex(tx.substring(2));
|
||||
snackBar = SnackBar(content: Text("${s.txId}: $txId"));
|
||||
}
|
||||
else {
|
||||
final msgHex = tx.substring(2);
|
||||
final s = hex.decode(msgHex);
|
||||
final dec = Utf8Decoder();
|
||||
final msg = dec.convert(s);
|
||||
snackBar = SnackBar(content: Text(msg));
|
||||
}
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
void _stopAggregator() {
|
||||
WarpApi.stopAggregator();
|
||||
}
|
||||
|
||||
String get txSummaryString =>
|
||||
"http://$_wifiIP:$PORT|${widget.txSummary.address}|${widget.txSummary.amount}";
|
||||
}
|
||||
|
||||
class SignerPie extends StatelessWidget {
|
||||
final int size;
|
||||
final int available;
|
||||
final int threshold;
|
||||
final int participants;
|
||||
|
||||
SignerPie(this.size, this.available, this.threshold, this.participants);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final remaining = threshold - available;
|
||||
return Column(children: [
|
||||
SizedBox(
|
||||
width: 150,
|
||||
height: 150,
|
||||
child: PieChart(PieChartData(
|
||||
sectionsSpace: 1,
|
||||
centerSpaceRadius: 0,
|
||||
startDegreeOffset: -90,
|
||||
sections: showingSections()))),
|
||||
Text(S.of(context).numMoreSignersNeeded(remaining)),
|
||||
]);
|
||||
}
|
||||
|
||||
List<PieChartSectionData> showingSections() {
|
||||
final value = 100 / participants;
|
||||
final size = this.size / 3;
|
||||
return List.generate(
|
||||
participants,
|
||||
(i) {
|
||||
if (i < available) {
|
||||
return PieChartSectionData(
|
||||
color: Colors.green, title: '', value: value, radius: size);
|
||||
} else if (i < threshold) {
|
||||
return PieChartSectionData(
|
||||
color: Colors.red, title: '', value: value, radius: size);
|
||||
}
|
||||
return PieChartSectionData(
|
||||
color: Colors.green, title: '', value: value, radius: size);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const SIGNER_PORT = 4001;
|
||||
|
||||
class MultisigPage extends StatefulWidget {
|
||||
@override
|
||||
MultisigState createState() => MultisigState();
|
||||
}
|
||||
|
||||
class MultisigState extends State<MultisigPage> {
|
||||
String _aggregatorUrl = "";
|
||||
String _address = "";
|
||||
int _amount = 0;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
int _participants = 2;
|
||||
int _threshold = 2;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final canMultisign = accountManager.active.share != null;
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(S.of(context).multisig)),
|
||||
body: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(children: [
|
||||
if (canMultisign) Card(
|
||||
elevation: 1,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(32),
|
||||
child: Center(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: _scan,
|
||||
icon: Icon(MdiIcons.signatureFreehand),
|
||||
label: Text(S.of(context).sign))))),
|
||||
if (accountManager.canPay) Card(
|
||||
elevation: 1,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(32),
|
||||
child: Center(
|
||||
child: Column(children: [
|
||||
Text('Number of Participants'),
|
||||
Slider(min: 2, max: 10, divisions: 8, onChanged: _onChangedParticipants, value: _participants.toDouble()),
|
||||
Padding(padding: EdgeInsets.all(4)),
|
||||
Text('Threshold (Number of Signers Required)'),
|
||||
Slider(min: 2, max: 10, divisions: 8, onChanged: _onChangedThreshold, value: _threshold.toDouble()),
|
||||
Padding(padding: EdgeInsets.all(8)),
|
||||
Text('$_threshold / $_participants', style: Theme.of(context).textTheme.headline5),
|
||||
Padding(padding: EdgeInsets.all(8)),
|
||||
ElevatedButton.icon(onPressed: _split, icon: Icon(MdiIcons.rhombusSplit), label: Text(S.of(context).splitAccount))
|
||||
])
|
||||
)))
|
||||
]))));
|
||||
}
|
||||
|
||||
_onChangedParticipants(v) {
|
||||
setState(() {
|
||||
_participants = v.toInt();
|
||||
if (_threshold > _participants)
|
||||
_threshold = _participants;
|
||||
});
|
||||
}
|
||||
|
||||
_onChangedThreshold(v) {
|
||||
setState(() {
|
||||
_threshold = v.toInt();
|
||||
if (_threshold > _participants)
|
||||
_threshold = _participants;
|
||||
});
|
||||
}
|
||||
|
||||
_scan() async {
|
||||
final s = S.of(context);
|
||||
final txSummaryString = await scanCode(context);
|
||||
if (txSummaryString == null) return;
|
||||
final txParts = txSummaryString.split('|');
|
||||
_aggregatorUrl = txParts[0];
|
||||
_address = txParts[1];
|
||||
_amount = int.parse(txParts[2]);
|
||||
final amount = amountToString(_amount);
|
||||
final approved = await showMessageBox(
|
||||
context,
|
||||
s.confirmSigning,
|
||||
s.confirmSignATransactionToAddressFor(_address, amount),
|
||||
s.approve);
|
||||
if (approved) await sign();
|
||||
}
|
||||
|
||||
_split() async {
|
||||
final s = S.of(context);
|
||||
final shareString = WarpApi.splitAccount(_threshold, _participants, accountManager.active.id);
|
||||
Navigator.of(context).pushNamed('/multisig_shares', arguments: shareString);
|
||||
}
|
||||
|
||||
sign() async {
|
||||
final info = NetworkInfo();
|
||||
final wifiIP = await info.getWifiIP();
|
||||
final myUrl = 'http://$wifiIP:$SIGNER_PORT';
|
||||
|
||||
final share = accountManager.active.share;
|
||||
if (share != null && _aggregatorUrl != null) {
|
||||
final errorCode = await WarpApi.runMultiSigner(
|
||||
share.value, _aggregatorUrl, myUrl, SIGNER_PORT);
|
||||
String? msg;
|
||||
switch (errorCode) {
|
||||
case 0:
|
||||
msg = "Transaction signed";
|
||||
break;
|
||||
case 1:
|
||||
msg = "Duplicate signer";
|
||||
break;
|
||||
}
|
||||
if (msg != null) {
|
||||
final snackBar = SnackBar(content: Text(msg));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar);
|
||||
}
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
|
||||
class MultisigSharesPage extends StatelessWidget {
|
||||
final String shareString;
|
||||
MultisigSharesPage(this.shareString);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final shares = shareString.split('|').asMap().entries.toList();
|
||||
final account = accountManager.active;
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(S.of(context).multisigShares)),
|
||||
body: ListView(
|
||||
padding: EdgeInsets.all(8),
|
||||
children: ListTile.divideTiles(context: context, tiles: [
|
||||
for (var share in shares)
|
||||
ListTile(title: Text(share.value), trailing: Icon(MdiIcons.qrcode),
|
||||
onTap: () => showQR(context, share.value, "${account.name} - ms ${share.key+1}/${shares.length}"))
|
||||
]).toList())
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
import 'main.dart';
|
||||
import 'store.dart';
|
||||
|
@ -25,6 +25,7 @@ class _NoteState extends State<NoteWidget> with AutomaticKeepAliveClientMixin {
|
|||
padding: EdgeInsets.all(8),
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Observer(builder: (context) {
|
||||
accountManager.sortedNotes;
|
||||
return PaginatedDataTable(
|
||||
columns: [
|
||||
DataColumn(
|
||||
|
@ -58,6 +59,9 @@ class _NoteState extends State<NoteWidget> with AutomaticKeepAliveClientMixin {
|
|||
],
|
||||
header: Text(S.of(context).selectNotesToExcludeFromPayments,
|
||||
style: Theme.of(context).textTheme.bodyText2),
|
||||
actions: [
|
||||
IconButton(onPressed: _selectInverse, icon: Icon(MdiIcons.selectInverse)),
|
||||
],
|
||||
columnSpacing: 16,
|
||||
showCheckboxColumn: false,
|
||||
availableRowsPerPage: [5, 10, 25, 100],
|
||||
|
@ -74,6 +78,10 @@ class _NoteState extends State<NoteWidget> with AutomaticKeepAliveClientMixin {
|
|||
_onRowSelected(Note note) {
|
||||
accountManager.excludeNote(note);
|
||||
}
|
||||
|
||||
_selectInverse() {
|
||||
accountManager.invertExcludedNotes();
|
||||
}
|
||||
}
|
||||
|
||||
class NotesDataSource extends DataTableSource {
|
||||
|
|
|
@ -16,25 +16,30 @@ class _RestorePageState extends State<RestorePage> {
|
|||
final _formKey = GlobalKey<FormState>();
|
||||
final _keyController = TextEditingController();
|
||||
final _nameController = TextEditingController();
|
||||
final _shareController = TextEditingController();
|
||||
var _validKey = true;
|
||||
var _isVK = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("${coin.symbol} Wallet"),
|
||||
),
|
||||
body: Form(
|
||||
body: GestureDetector(
|
||||
onTap: () { FocusScope.of(context).unfocus(); },
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(children: [
|
||||
TextFormField(
|
||||
decoration: InputDecoration(labelText: S.of(context).accountName),
|
||||
decoration: InputDecoration(labelText: s.accountName),
|
||||
controller: _nameController,
|
||||
validator: (String? name) {
|
||||
if (name == null || name.isEmpty)
|
||||
return S.of(context).accountNameIsRequired;
|
||||
return s.accountNameIsRequired;
|
||||
return null;
|
||||
},
|
||||
),
|
||||
|
@ -43,9 +48,9 @@ class _RestorePageState extends State<RestorePage> {
|
|||
Expanded(
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: S.of(context).key,
|
||||
labelText: s.key,
|
||||
hintText:
|
||||
S.of(context).enterSeed),
|
||||
s.enterSeed),
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: _keyController,
|
||||
|
@ -55,12 +60,29 @@ class _RestorePageState extends State<RestorePage> {
|
|||
icon: new Icon(MdiIcons.qrcodeScan), onPressed: _onScan)
|
||||
],
|
||||
),
|
||||
if (_isVK) Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: s.secretShare,
|
||||
hintText: s.enterSecretShareIfAccountIsMultisignature),
|
||||
minLines: 4,
|
||||
maxLines: 4,
|
||||
controller: _shareController,
|
||||
// TODO: Check share
|
||||
)),
|
||||
IconButton(
|
||||
icon: new Icon(MdiIcons.qrcodeScan), onPressed: _onScanShare)
|
||||
],
|
||||
),
|
||||
ButtonBar(children:
|
||||
confirmButtons(context, _validKey ? _onOK : null, okLabel: S.of(context).add, okIcon: Icon(Icons.add)))
|
||||
]))));
|
||||
confirmButtons(context, _validKey ? _onOK : null, okLabel: s.add, okIcon: Icon(Icons.add)))
|
||||
])))));
|
||||
}
|
||||
|
||||
_onOK() async {
|
||||
final s = S.of(context);
|
||||
if (_formKey.currentState!.validate()) {
|
||||
final account =
|
||||
WarpApi.newAccount(_nameController.text, _keyController.text);
|
||||
|
@ -69,18 +91,20 @@ class _RestorePageState extends State<RestorePage> {
|
|||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(S.of(context).duplicateAccount),
|
||||
content: Text(S.of(context).thisAccountAlreadyExists),
|
||||
title: Text(s.duplicateAccount),
|
||||
content: Text(s.thisAccountAlreadyExists),
|
||||
actions: [
|
||||
ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
label: Text(S.of(context).ok),
|
||||
label: Text(s.ok),
|
||||
icon: Icon(Icons.done))
|
||||
]));
|
||||
}
|
||||
else {
|
||||
if (_shareController.text.isNotEmpty)
|
||||
accountManager.storeShareSecret(account, _shareController.text);
|
||||
await accountManager.refresh();
|
||||
if (_keyController.text != "") {
|
||||
syncStatus.setAccountRestored(true);
|
||||
|
@ -97,7 +121,9 @@ class _RestorePageState extends State<RestorePage> {
|
|||
|
||||
_checkKey(key) {
|
||||
setState(() {
|
||||
_validKey = key == "" || WarpApi.validKey(key);
|
||||
final keyType = WarpApi.validKey(key);
|
||||
_validKey = key == "" || keyType >= 0;
|
||||
_isVK = keyType == 2;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -106,7 +132,15 @@ class _RestorePageState extends State<RestorePage> {
|
|||
if (key != null)
|
||||
setState(() {
|
||||
_keyController.text = key;
|
||||
_validKey = key == "" || WarpApi.validKey(key);
|
||||
_checkKey(key);
|
||||
});
|
||||
}
|
||||
|
||||
void _onScanShare() async {
|
||||
final key = await scanCode(context);
|
||||
if (key != null)
|
||||
setState(() {
|
||||
_shareController.text = key;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
212
lib/send.dart
212
lib/send.dart
|
@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:mobx/mobx.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:warp/dualmoneyinput.dart';
|
||||
import 'package:warp_api/types.dart';
|
||||
import 'package:warp_api/warp_api.dart';
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
@ -25,6 +26,8 @@ class SendPage extends StatefulWidget {
|
|||
|
||||
@override
|
||||
SendState createState() => SendState();
|
||||
|
||||
bool get isMulti => args?.isMulti ?? false;
|
||||
}
|
||||
|
||||
class SendState extends State<SendPage> {
|
||||
|
@ -46,11 +49,15 @@ class SendState extends State<SendPage> {
|
|||
var _useMillis = true;
|
||||
var _useTransparent = settings.shieldBalance;
|
||||
ReactionDisposer? _newBlockAutorunDispose;
|
||||
final _fee = DEFAULT_FEE;
|
||||
var _usedBalance = 0;
|
||||
|
||||
@override
|
||||
initState() {
|
||||
if (widget.args?.contact != null)
|
||||
_addressController.text = widget.args!.contact!.address;
|
||||
final recipients = widget.args?.recipients ?? [];
|
||||
_usedBalance = recipients.fold(0, (acc, r) => acc + r.amount);
|
||||
|
||||
final uri = widget.args?.uri;
|
||||
if (uri != null)
|
||||
|
@ -67,7 +74,8 @@ class SendState extends State<SendPage> {
|
|||
final excludedBalance = await accountManager.getExcludedBalance();
|
||||
final underConfirmedBalance =
|
||||
await accountManager.getUnderConfirmedBalance();
|
||||
final unconfirmedSpentBalance = await accountManager.getUnconfirmedSpentBalance();
|
||||
final unconfirmedSpentBalance =
|
||||
await accountManager.getUnconfirmedSpentBalance();
|
||||
final unconfirmedBalance = accountManager.unconfirmedBalance;
|
||||
setState(() {
|
||||
_sBalance = sBalance;
|
||||
|
@ -129,9 +137,13 @@ class SendState extends State<SendPage> {
|
|||
icon: new Icon(MdiIcons.qrcodeScan),
|
||||
onPressed: _onScan)
|
||||
]),
|
||||
DualMoneyInputWidget(key: _amountKey, child: TextButton(child: Text(s.max), onPressed: _onMax), spendable: spendable),
|
||||
BalanceTable(_sBalance, _tBalance, _useTransparent, _excludedBalance,
|
||||
_underConfirmedBalance, change),
|
||||
DualMoneyInputWidget(
|
||||
key: _amountKey,
|
||||
child:
|
||||
TextButton(child: Text(s.max), onPressed: _onMax),
|
||||
spendable: spendable),
|
||||
BalanceTable(_sBalance, _tBalance, _useTransparent,
|
||||
_excludedBalance, _underConfirmedBalance, change, _usedBalance, _fee),
|
||||
ExpansionPanelList(
|
||||
expansionCallback: (_, isExpanded) {
|
||||
setState(() {
|
||||
|
@ -157,7 +169,7 @@ class SendState extends State<SendPage> {
|
|||
title: Text(s.roundToMillis),
|
||||
value: _useMillis,
|
||||
onChanged: _setUseMillis),
|
||||
if (accountManager.canPay)
|
||||
if (accountManager.canPay && !widget.isMulti)
|
||||
CheckboxListTile(
|
||||
title: Text(s.useTransparentBalance),
|
||||
value: _useTransparent,
|
||||
|
@ -169,7 +181,9 @@ class SendState extends State<SendPage> {
|
|||
labelText: s.maxAmountPerNote),
|
||||
keyboardType: TextInputType.number,
|
||||
controller: _maxAmountController,
|
||||
inputFormatters: [makeInputFormatter(amountInput?.useMillis)],
|
||||
inputFormatters: [
|
||||
makeInputFormatter(amountInput?.useMillis)
|
||||
],
|
||||
validator: _checkMaxAmountPerNote,
|
||||
onSaved: _onSavedMaxAmountPerNote,
|
||||
)),
|
||||
|
@ -180,7 +194,8 @@ class SendState extends State<SendPage> {
|
|||
Padding(padding: EdgeInsets.all(8)),
|
||||
ButtonBar(
|
||||
children: confirmButtons(context, _onSend,
|
||||
okLabel: s.send, okIcon: Icon(MdiIcons.send)))
|
||||
okLabel: widget.isMulti ? s.add : s.send,
|
||||
okIcon: Icon(MdiIcons.send)))
|
||||
])))));
|
||||
}
|
||||
|
||||
|
@ -276,68 +291,52 @@ class SendState extends State<SendPage> {
|
|||
form.save();
|
||||
final amount = amountInput?.amount ?? 0;
|
||||
final aZEC = amountToString(amount);
|
||||
final approved = await showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
title: Text(s.pleaseConfirm),
|
||||
content: SingleChildScrollView(
|
||||
child: Text(s.sendingAzecCointickerToAddress(
|
||||
aZEC, coin.ticker, _address))),
|
||||
actions: confirmButtons(
|
||||
context, () => Navigator.of(context).pop(true),
|
||||
okLabel: s.approve, cancelValue: false)));
|
||||
final approved = widget.isMulti ||
|
||||
await showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
title: Text(s.pleaseConfirm),
|
||||
content: SingleChildScrollView(
|
||||
child: Text(s.sendingAzecCointickerToAddress(
|
||||
aZEC, coin.ticker, _address))),
|
||||
actions: confirmButtons(
|
||||
context, () => Navigator.of(context).pop(true),
|
||||
okLabel: s.approve, cancelValue: false)));
|
||||
if (approved) {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
final snackBar1 = SnackBar(content: Text(s.preparingTransaction));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar1);
|
||||
|
||||
int maxAmountPerNote = (_maxAmountPerNote * ZECUNIT_DECIMAL).toInt();
|
||||
final memo = _memoController.text;
|
||||
final address = unwrapUA(_address);
|
||||
final recipient = Recipient(
|
||||
address,
|
||||
amount,
|
||||
memo,
|
||||
maxAmountPerNote,
|
||||
);
|
||||
|
||||
if (accountManager.canPay) {
|
||||
if (settings.protectSend &&
|
||||
!await authenticate(context, s.pleaseAuthenticateToSend)) return;
|
||||
final tx = await compute(
|
||||
sendPayment,
|
||||
PaymentParams(
|
||||
accountManager.active.id,
|
||||
address,
|
||||
amount,
|
||||
memo,
|
||||
maxAmountPerNote,
|
||||
settings.anchorOffset,
|
||||
_useTransparent,
|
||||
progressPort.sendPort));
|
||||
|
||||
final snackBar2 = SnackBar(content: Text("${s.txId}: $tx"));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar2);
|
||||
await accountManager.fetchAccountData(true);
|
||||
} else {
|
||||
Directory tempDir = await getTemporaryDirectory();
|
||||
String filename = "${tempDir.path}/tx.json";
|
||||
|
||||
final msg = WarpApi.prepareTx(accountManager.active.id, address,
|
||||
amountInput?.amount ?? 0, memo, maxAmountPerNote, settings.anchorOffset, filename);
|
||||
|
||||
Share.shareFiles([filename], subject: s.unsignedTransactionFile);
|
||||
|
||||
final snackBar2 = SnackBar(content: Text(msg));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar2);
|
||||
}
|
||||
if (!widget.isMulti)
|
||||
// send closes the page
|
||||
await send(context, [recipient], _useTransparent);
|
||||
else
|
||||
Navigator.of(context).pop(recipient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int amountInZAT(Decimal v) => (v * ZECUNIT_DECIMAL).toInt();
|
||||
|
||||
String amountFromZAT(int v) =>
|
||||
(Decimal.fromInt(v) / ZECUNIT_DECIMAL).toString();
|
||||
|
||||
get spendable => math.max((_useTransparent ? _tBalance : 0) +
|
||||
_sBalance - _excludedBalance - _underConfirmedBalance - DEFAULT_FEE, 0);
|
||||
get spendable => math.max(
|
||||
(_useTransparent ? _tBalance : 0) +
|
||||
_sBalance -
|
||||
_excludedBalance -
|
||||
_underConfirmedBalance -
|
||||
_usedBalance -
|
||||
_fee,
|
||||
0);
|
||||
|
||||
get change => _unconfirmedSpentBalance + _unconfirmedBalance;
|
||||
|
||||
|
@ -351,9 +350,11 @@ class BalanceTable extends StatelessWidget {
|
|||
final int excludedBalance;
|
||||
final int underConfirmedBalance;
|
||||
final int change;
|
||||
final int used;
|
||||
final int fee;
|
||||
|
||||
BalanceTable(this.sBalance, this.tBalance, this.useTBalance, this.excludedBalance,
|
||||
this.underConfirmedBalance, this.change);
|
||||
BalanceTable(this.sBalance, this.tBalance, this.useTBalance,
|
||||
this.excludedBalance, this.underConfirmedBalance, this.change, this.used, this.fee);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -371,23 +372,31 @@ class BalanceTable extends StatelessWidget {
|
|||
]));
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(border: Border.all(color: theme.dividerColor, width: 1),
|
||||
borderRadius: BorderRadius.circular(8)),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: theme.dividerColor, width: 1),
|
||||
borderRadius: BorderRadius.circular(8)),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
|
||||
BalanceRow(Text(S.of(context).totalBalance), totalBalance),
|
||||
BalanceRow(Text(S.of(context).underConfirmed), -underConfirmed),
|
||||
BalanceRow(Text(S.of(context).excludedNotes), -excludedBalance),
|
||||
if (!useTBalance) BalanceRow(tBalanceLabel, -tBalance),
|
||||
BalanceRow(Text(S.of(context).spendableBalance), spendable,
|
||||
style: TextStyle(color: Theme.of(context).primaryColor)),
|
||||
]));
|
||||
BalanceRow(Text(S.of(context).totalBalance), totalBalance),
|
||||
BalanceRow(Text(S.of(context).underConfirmed), -underConfirmed),
|
||||
BalanceRow(Text(S.of(context).excludedNotes), -excludedBalance),
|
||||
if (!useTBalance) BalanceRow(tBalanceLabel, -tBalance),
|
||||
BalanceRow(Text(S.of(context).spendableBalance), spendable,
|
||||
style: TextStyle(color: Theme.of(context).primaryColor)),
|
||||
]));
|
||||
}
|
||||
|
||||
get totalBalance => sBalance + tBalance + change;
|
||||
get totalBalance => sBalance + tBalance + change - used - fee;
|
||||
|
||||
get underConfirmed => -underConfirmedBalance - change;
|
||||
|
||||
get spendable => math.max(
|
||||
sBalance + (useTBalance ? tBalance : 0) - excludedBalance - underConfirmedBalance - DEFAULT_FEE, 0);
|
||||
sBalance +
|
||||
(useTBalance ? tBalance : 0) -
|
||||
excludedBalance -
|
||||
underConfirmedBalance -
|
||||
used -
|
||||
fee,
|
||||
0);
|
||||
}
|
||||
|
||||
class BalanceRow extends StatelessWidget {
|
||||
|
@ -402,23 +411,60 @@ class BalanceRow extends StatelessWidget {
|
|||
return ListTile(
|
||||
title: label,
|
||||
trailing: Text(amountToString(amount),
|
||||
style: TextStyle(fontFeatures: [FontFeature.tabularFigures()]).merge(style)),
|
||||
style: TextStyle(fontFeatures: [FontFeature.tabularFigures()])
|
||||
.merge(style)),
|
||||
visualDensity: VisualDensity(horizontal: 0, vertical: -4));
|
||||
}
|
||||
}
|
||||
|
||||
sendPayment(PaymentParams param) async {
|
||||
param.port.send(0);
|
||||
final tx = await WarpApi.sendPayment(
|
||||
param.account,
|
||||
param.address,
|
||||
param.amount,
|
||||
param.memo,
|
||||
param.maxAmountPerNote,
|
||||
param.anchorOffset,
|
||||
param.useTransparent, (percent) {
|
||||
param.port.send(percent);
|
||||
});
|
||||
param.port.send(0);
|
||||
return tx;
|
||||
Future<void> send(BuildContext context, List<Recipient> recipients, bool useTransparent) async {
|
||||
final s = S.of(context);
|
||||
|
||||
String address = "";
|
||||
int amount = 0;
|
||||
for (var r in recipients) {
|
||||
amount += r.amount;
|
||||
if (address.isEmpty)
|
||||
address = r.address;
|
||||
else
|
||||
address = s.multipleAddresses;
|
||||
}
|
||||
|
||||
final snackBar1 = SnackBar(content: Text(s.preparingTransaction));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar1);
|
||||
|
||||
if (accountManager.canPay) {
|
||||
if (settings.protectSend &&
|
||||
!await authenticate(context, s.pleaseAuthenticateToSend)) return;
|
||||
|
||||
Navigator.of(context).pop();
|
||||
final tx = await WarpApi.sendPayment(accountManager.active.id, recipients,
|
||||
useTransparent, settings.anchorOffset, (progress) {
|
||||
progressPort.sendPort.send(progress);
|
||||
});
|
||||
progressPort.sendPort.send(0);
|
||||
|
||||
final snackBar2 = SnackBar(content: Text("${s.txId}: $tx"));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar2);
|
||||
await accountManager.fetchAccountData(true);
|
||||
} else {
|
||||
Directory tempDir = await getTemporaryDirectory();
|
||||
String filename = "${tempDir.path}/tx.json";
|
||||
|
||||
final txjson = WarpApi.prepareTx(accountManager.active.id, recipients,
|
||||
useTransparent, settings.anchorOffset, filename);
|
||||
|
||||
if (coin.supportsMultisig && accountManager.active.share != null) {
|
||||
final txSummary = TxSummary(address, amount, txjson);
|
||||
Navigator.of(context).pushReplacementNamed('/multisign', arguments: txSummary);
|
||||
} else {
|
||||
final file = File(filename);
|
||||
await file.writeAsString(txjson);
|
||||
Share.shareFiles([filename], subject: s.unsignedTransactionFile);
|
||||
|
||||
final snackBar2 = SnackBar(content: Text(s.fileSaved));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar2);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,7 +237,6 @@ class SettingsState extends State<SettingsPage> {
|
|||
_onSave() async {
|
||||
final form = _settingsFormKey.currentState!;
|
||||
if (form.validate()) {
|
||||
print(_needAuth);
|
||||
if (_needAuth && !await authenticate(context, S.of(context).protectSendSettingChanged)) return;
|
||||
form.save();
|
||||
Navigator.of(context).pop();
|
||||
|
|
248
lib/store.dart
248
lib/store.dart
|
@ -10,6 +10,7 @@ import 'package:mobx/mobx.dart';
|
|||
import 'package:path/path.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'package:warp_api/warp_api.dart';
|
||||
import 'package:warp_api/types.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert' as convert;
|
||||
|
@ -111,9 +112,11 @@ abstract class _Settings with Store {
|
|||
protectSend = prefs.getBool('protect_send') ?? false;
|
||||
|
||||
primaryColorValue = prefs.getInt('primary') ?? Colors.blue.value;
|
||||
primaryVariantColorValue = prefs.getInt('primary.variant') ?? Colors.blueAccent.value;
|
||||
primaryVariantColorValue =
|
||||
prefs.getInt('primary.variant') ?? Colors.blueAccent.value;
|
||||
secondaryColorValue = prefs.getInt('secondary') ?? Colors.green.value;
|
||||
secondaryVariantColorValue = prefs.getInt('secondary.variant') ?? Colors.greenAccent.value;
|
||||
secondaryVariantColorValue =
|
||||
prefs.getInt('secondary.variant') ?? Colors.greenAccent.value;
|
||||
|
||||
_updateThemeData();
|
||||
Future.microtask(_loadCurrencies); // lazily
|
||||
|
@ -168,28 +171,25 @@ abstract class _Settings with Store {
|
|||
|
||||
void _updateThemeData() {
|
||||
if (theme == 'custom') {
|
||||
final colors = FlexSchemeColor(primary: Color(primaryColorValue),
|
||||
final colors = FlexSchemeColor(
|
||||
primary: Color(primaryColorValue),
|
||||
primaryVariant: Color(primaryVariantColorValue),
|
||||
secondary: Color(secondaryColorValue),
|
||||
secondaryVariant: Color(secondaryVariantColorValue));
|
||||
final scheme = FlexSchemeData(name: 'custom',
|
||||
final scheme = FlexSchemeData(
|
||||
name: 'custom',
|
||||
description: 'Custom Theme',
|
||||
light: colors,
|
||||
dark: colors);
|
||||
switch (themeBrightness) {
|
||||
case 'light':
|
||||
themeData = FlexColorScheme
|
||||
.light(colors: scheme.light)
|
||||
.toTheme;
|
||||
themeData = FlexColorScheme.light(colors: scheme.light).toTheme;
|
||||
break;
|
||||
case 'dark':
|
||||
themeData = FlexColorScheme
|
||||
.dark(colors: scheme.dark)
|
||||
.toTheme;
|
||||
themeData = FlexColorScheme.dark(colors: scheme.dark).toTheme;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
FlexScheme scheme;
|
||||
switch (theme) {
|
||||
case 'gold':
|
||||
|
@ -209,21 +209,18 @@ abstract class _Settings with Store {
|
|||
}
|
||||
switch (themeBrightness) {
|
||||
case 'light':
|
||||
themeData = FlexColorScheme
|
||||
.light(scheme: scheme)
|
||||
.toTheme;
|
||||
themeData = FlexColorScheme.light(scheme: scheme).toTheme;
|
||||
break;
|
||||
case 'dark':
|
||||
themeData = FlexColorScheme
|
||||
.dark(scheme: scheme)
|
||||
.toTheme;
|
||||
themeData = FlexColorScheme.dark(scheme: scheme).toTheme;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> updateCustomThemeColors(Color primary, Color primaryVariant, Color secondary, Color secondaryVariant) async {
|
||||
Future<void> updateCustomThemeColors(Color primary, Color primaryVariant,
|
||||
Color secondary, Color secondaryVariant) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
primaryColorValue = primary.value;
|
||||
primaryVariantColorValue = primaryVariant.value;
|
||||
|
@ -347,7 +344,7 @@ abstract class _AccountManager with Store {
|
|||
late Database db;
|
||||
|
||||
@observable
|
||||
Account active = Account(0, "", "", 0);
|
||||
Account active = Account(0, "", "", 0, null);
|
||||
|
||||
@observable
|
||||
bool canPay = false;
|
||||
|
@ -454,10 +451,12 @@ abstract class _AccountManager with Store {
|
|||
|
||||
Future<Backup> getBackup(int account) async {
|
||||
final List<Map> res = await db.rawQuery(
|
||||
"SELECT seed, sk, ivk FROM accounts WHERE id_account = ?1",
|
||||
"SELECT name, seed, sk, ivk FROM accounts WHERE id_account = ?1",
|
||||
[account]);
|
||||
if (res.isEmpty) throw Exception("Account N/A");
|
||||
final share = await getShareInfo(account);
|
||||
final row = res[0];
|
||||
final name = row['name'];
|
||||
final seed = row['seed'];
|
||||
final sk = row['sk'];
|
||||
final ivk = row['ivk'];
|
||||
|
@ -467,7 +466,7 @@ abstract class _AccountManager with Store {
|
|||
else if (sk != null)
|
||||
type = 1;
|
||||
else if (ivk != null) type = 2;
|
||||
return Backup(type, seed, sk, ivk);
|
||||
return Backup(type, name, seed, sk, ivk, share);
|
||||
}
|
||||
|
||||
Future<int> _getBalance(int accountId) async {
|
||||
|
@ -480,29 +479,33 @@ abstract class _AccountManager with Store {
|
|||
|
||||
Future<int> getShieldedBalance() async {
|
||||
return Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent IS NULL",
|
||||
[active.id])) ?? 0;
|
||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent IS NULL",
|
||||
[active.id])) ??
|
||||
0;
|
||||
}
|
||||
|
||||
Future<int> getUnconfirmedSpentBalance() async {
|
||||
return Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent = 0",
|
||||
[active.id])) ?? 0;
|
||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent = 0",
|
||||
[active.id])) ??
|
||||
0;
|
||||
}
|
||||
|
||||
Future<int> getUnderConfirmedBalance() async {
|
||||
final height = syncStatus.latestHeight - settings.anchorOffset;
|
||||
return Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND height > ?2",
|
||||
[active.id, height])) ?? 0;
|
||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND height > ?2",
|
||||
[active.id, height])) ??
|
||||
0;
|
||||
}
|
||||
|
||||
Future<int> getExcludedBalance() async {
|
||||
final height = syncStatus.latestHeight - settings.anchorOffset;
|
||||
final amount = Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL "
|
||||
"AND height <= ?2 AND excluded",
|
||||
[active.id, height])) ?? 0;
|
||||
"SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL "
|
||||
"AND height <= ?2 AND excluded",
|
||||
[active.id, height])) ??
|
||||
0;
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
@ -518,28 +521,45 @@ abstract class _AccountManager with Store {
|
|||
|
||||
Future<List<Account>> _list() async {
|
||||
final List<Map> res = await db.rawQuery(
|
||||
"WITH notes AS (SELECT a.id_account, a.name, a.address, CASE WHEN r.spent IS NULL THEN r.value ELSE 0 END AS nv FROM accounts a LEFT JOIN received_notes r ON a.id_account = r.account) "
|
||||
"SELECT id_account, name, address, COALESCE(sum(nv), 0) AS balance FROM notes GROUP by id_account",
|
||||
"WITH notes AS (SELECT a.id_account, a.name, a.address, CASE WHEN r.spent IS NULL THEN r.value ELSE 0 END AS nv FROM accounts a LEFT JOIN received_notes r ON a.id_account = r.account),"
|
||||
"accounts2 AS (SELECT id_account, name, address, COALESCE(sum(nv), 0) AS balance FROM notes GROUP by id_account) "
|
||||
"SELECT a.id_account, a.name, a.address, a.balance, ss.idx, ss.secret, ss.participants, ss.threshold FROM accounts2 a LEFT JOIN secret_shares ss ON a.id_account = ss.account",
|
||||
[]);
|
||||
return res
|
||||
.map((r) =>
|
||||
Account(r['id_account'], r['name'], r['address'], r['balance']))
|
||||
.toList();
|
||||
return res.map((r) {
|
||||
final shareInfo = r['secret'] != null
|
||||
? ShareInfo(r['idx'], r['threshold'], r['participants'], r['secret'])
|
||||
: null;
|
||||
return Account(
|
||||
r['id_account'], r['name'], r['address'], r['balance'], shareInfo);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> delete(int account) async {
|
||||
WarpApi.deleteAccount(account);
|
||||
if (account == active.id)
|
||||
resetToDefaultAccount();
|
||||
if (account == active.id) resetToDefaultAccount();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> changeAccountName(String name) async {
|
||||
Future<void> changeAccountName(Account account, String name) async {
|
||||
await db.execute("UPDATE accounts SET name = ?2 WHERE id_account = ?1",
|
||||
[active.id, name]);
|
||||
[account.id, name]);
|
||||
await refresh();
|
||||
await setActiveAccountId(active.id);
|
||||
}
|
||||
|
||||
@action
|
||||
void storeShareSecret(int account, String secretKey) {
|
||||
WarpApi.storeShareSecret(account, secretKey);
|
||||
}
|
||||
|
||||
Future<ShareInfo?> getShareInfo(int accountId) async {
|
||||
final List<Map> res = await db.rawQuery(
|
||||
"SELECT idx, threshold, participants, secret FROM secret_shares WHERE account = ?1",
|
||||
[accountId]);
|
||||
if (res.isEmpty) return null;
|
||||
final row = res[0];
|
||||
return ShareInfo(
|
||||
row['idx'], row['threshold'], row['participants'], row['secret']);
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -617,8 +637,16 @@ abstract class _AccountManager with Store {
|
|||
final shortTxid = fullTxId.substring(0, 8);
|
||||
final timestamp = txDateFormat
|
||||
.format(DateTime.fromMillisecondsSinceEpoch(row['timestamp'] * 1000));
|
||||
return Tx(row['id_tx'], row['height'], timestamp, shortTxid, fullTxId,
|
||||
row['value'] / ZECUNIT, row['address'] ?? "", row['name'], row['memo'] ?? "");
|
||||
return Tx(
|
||||
row['id_tx'],
|
||||
row['height'],
|
||||
timestamp,
|
||||
shortTxid,
|
||||
fullTxId,
|
||||
row['value'] / ZECUNIT,
|
||||
row['address'] ?? "",
|
||||
row['name'],
|
||||
row['memo'] ?? "");
|
||||
}).toList();
|
||||
|
||||
dataEpoch = DateTime.now().millisecondsSinceEpoch;
|
||||
|
@ -629,36 +657,45 @@ abstract class _AccountManager with Store {
|
|||
List<Note> get sortedNotes {
|
||||
var notes2 = [...notes];
|
||||
switch (noteSortConfig.field) {
|
||||
case "time": return _sort(notes2, (Note note) => note.height, noteSortConfig.order);
|
||||
case "amount": return _sort(notes2, (Note note) => note.value, noteSortConfig.order);
|
||||
case "time":
|
||||
return _sort(notes2, (Note note) => note.height, noteSortConfig.order);
|
||||
case "amount":
|
||||
return _sort(notes2, (Note note) => note.value, noteSortConfig.order);
|
||||
}
|
||||
return notes2;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> sortNotes(String field) async {
|
||||
noteSortConfig.sortOn(field);
|
||||
void sortNotes(String field) {
|
||||
noteSortConfig = noteSortConfig.sortOn(field);
|
||||
}
|
||||
|
||||
@computed
|
||||
List<Tx> get sortedTxs {
|
||||
var txs2 = [...txs];
|
||||
switch (txSortConfig.field) {
|
||||
case "time": return _sort(txs2, (Tx tx) => tx.height, txSortConfig.order);
|
||||
case "amount": return _sort(txs2, (Tx tx) => tx.value, txSortConfig.order);
|
||||
case "txid": return _sort(txs2, (Tx tx) => tx.txid, txSortConfig.order);
|
||||
case "address": return _sort(txs2, (Tx tx) => tx.contact ?? tx.address, txSortConfig.order);
|
||||
case "memo": return _sort(txs2, (Tx tx) => tx.memo, txSortConfig.order);
|
||||
case "time":
|
||||
return _sort(txs2, (Tx tx) => tx.height, txSortConfig.order);
|
||||
case "amount":
|
||||
return _sort(txs2, (Tx tx) => tx.value, txSortConfig.order);
|
||||
case "txid":
|
||||
return _sort(txs2, (Tx tx) => tx.txid, txSortConfig.order);
|
||||
case "address":
|
||||
return _sort(
|
||||
txs2, (Tx tx) => tx.contact ?? tx.address, txSortConfig.order);
|
||||
case "memo":
|
||||
return _sort(txs2, (Tx tx) => tx.memo, txSortConfig.order);
|
||||
}
|
||||
return txs2;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> sortTx(String field) async {
|
||||
txSortConfig.sortOn(field);
|
||||
void sortTx(String field) {
|
||||
txSortConfig = txSortConfig.sortOn(field);
|
||||
}
|
||||
|
||||
List<C> _sort<C extends HasHeight, T extends Comparable>(List<C> txs, T Function(C) project, SortOrder order) {
|
||||
List<C> _sort<C extends HasHeight, T extends Comparable>(
|
||||
List<C> txs, T Function(C) project, SortOrder order) {
|
||||
switch (order) {
|
||||
case SortOrder.Ascending:
|
||||
txs.sort((a, b) => project(a).compareTo(project(b)));
|
||||
|
@ -711,7 +748,8 @@ abstract class _AccountManager with Store {
|
|||
_accountBalances.add(ab);
|
||||
b -= value;
|
||||
}
|
||||
_accountBalances.add(AccountBalance(DateTime.fromMillisecondsSinceEpoch(range.start), b / ZECUNIT));
|
||||
_accountBalances.add(AccountBalance(
|
||||
DateTime.fromMillisecondsSinceEpoch(range.start), b / ZECUNIT));
|
||||
_accountBalances = _accountBalances.reversed.toList();
|
||||
accountBalances = sampleDaily<AccountBalance, double, double>(
|
||||
_accountBalances,
|
||||
|
@ -814,7 +852,7 @@ abstract class _AccountManager with Store {
|
|||
var _pnls = [...pnls.reversed];
|
||||
return _pnls;
|
||||
}
|
||||
return pnls;
|
||||
return pnls;
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -832,6 +870,14 @@ abstract class _AccountManager with Store {
|
|||
[note.id, note.excluded]);
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> invertExcludedNotes() async {
|
||||
await db.execute(
|
||||
"UPDATE received_notes SET excluded = NOT(COALESCE(excluded, 0)) WHERE account = ?1",
|
||||
[active.id]);
|
||||
notes = notes.map((n) => n.invertExcluded).toList();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> updateTBalance() async {
|
||||
_updateTBalance(active.id);
|
||||
|
@ -843,7 +889,8 @@ abstract class _AccountManager with Store {
|
|||
}
|
||||
|
||||
void autoshield() {
|
||||
if (settings.autoShieldThreshold != 0.0 && tbalance / ZECUNIT >= settings.autoShieldThreshold) {
|
||||
if (settings.autoShieldThreshold != 0.0 &&
|
||||
tbalance / ZECUNIT >= settings.autoShieldThreshold) {
|
||||
WarpApi.shieldTAddr(active.id);
|
||||
}
|
||||
}
|
||||
|
@ -869,8 +916,9 @@ class Account {
|
|||
final String name;
|
||||
final String address;
|
||||
final int balance;
|
||||
final ShareInfo? share;
|
||||
|
||||
Account(this.id, this.name, this.address, this.balance);
|
||||
Account(this.id, this.name, this.address, this.balance, this.share);
|
||||
}
|
||||
|
||||
class PriceStore = _PriceStore with _$PriceStore;
|
||||
|
@ -941,17 +989,15 @@ abstract class _SyncStatus with Store {
|
|||
Future<void> sync(BuildContext context) async {
|
||||
eta.reset();
|
||||
syncing = true;
|
||||
final snackBar =
|
||||
SnackBar(content: Text(S
|
||||
.of(context)
|
||||
.rescanRequested));
|
||||
final snackBar = SnackBar(content: Text(S.of(context).rescanRequested));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar);
|
||||
setSyncHeight(0);
|
||||
WarpApi.rewindToHeight(0);
|
||||
WarpApi.truncateData();
|
||||
contacts.markContactsDirty(false);
|
||||
await syncStatus.update();
|
||||
final params = SyncParams(settings.getTx, settings.anchorOffset, syncPort.sendPort);
|
||||
final params =
|
||||
SyncParams(settings.getTx, settings.anchorOffset, syncPort.sendPort);
|
||||
await compute(WarpApi.warpSync, params);
|
||||
syncing = false;
|
||||
eta.reset();
|
||||
|
@ -1017,12 +1063,16 @@ abstract class _ETAStore with Store {
|
|||
final p = prev;
|
||||
final c = current;
|
||||
if (p == null || c == null) return "";
|
||||
if (c.timestamp.millisecondsSinceEpoch == p.timestamp.millisecondsSinceEpoch) return "";
|
||||
final speed = (c.height - p.height) / (c.timestamp.millisecondsSinceEpoch - p.timestamp.millisecondsSinceEpoch);
|
||||
if (c.timestamp.millisecondsSinceEpoch ==
|
||||
p.timestamp.millisecondsSinceEpoch) return "";
|
||||
final speed = (c.height - p.height) /
|
||||
(c.timestamp.millisecondsSinceEpoch -
|
||||
p.timestamp.millisecondsSinceEpoch);
|
||||
if (speed == 0) return "";
|
||||
final eta = (syncStatus.latestHeight - c.height) / speed;
|
||||
if (eta <= 0) return "";
|
||||
final duration = Duration(milliseconds: eta.floor()).toString().split('.')[0];
|
||||
final duration =
|
||||
Duration(milliseconds: eta.floor()).toString().split('.')[0];
|
||||
return "(ETA: $duration)";
|
||||
}
|
||||
}
|
||||
|
@ -1109,6 +1159,9 @@ class Note extends HasHeight {
|
|||
|
||||
Note(this.id, this.height, this.timestamp, this.value, this.excluded,
|
||||
this.spent);
|
||||
|
||||
Note get invertExcluded =>
|
||||
Note(id, height, timestamp, value, !excluded, spent);
|
||||
}
|
||||
|
||||
class Tx extends HasHeight {
|
||||
|
@ -1142,12 +1195,14 @@ class AccountBalance {
|
|||
}
|
||||
|
||||
class Backup {
|
||||
int type;
|
||||
final int type;
|
||||
final String name;
|
||||
final String? seed;
|
||||
final String? sk;
|
||||
final String ivk;
|
||||
final ShareInfo? share;
|
||||
|
||||
Backup(this.type, this.seed, this.sk, this.ivk);
|
||||
Backup(this.type, this.name, this.seed, this.sk, this.ivk, this.share);
|
||||
|
||||
String value() {
|
||||
switch (type) {
|
||||
|
@ -1181,20 +1236,6 @@ enum SortOrder {
|
|||
SortOrder nextSortOrder(SortOrder order) =>
|
||||
SortOrder.values[(order.index + 1) % 3];
|
||||
|
||||
@JsonSerializable()
|
||||
class Recipient {
|
||||
final String address;
|
||||
final int amount;
|
||||
final String memo;
|
||||
|
||||
Recipient(this.address, this.amount, this.memo);
|
||||
|
||||
factory Recipient.fromJson(Map<String, dynamic> json) =>
|
||||
_$RecipientFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$RecipientToJson(this);
|
||||
}
|
||||
|
||||
class PnL {
|
||||
final DateTime timestamp;
|
||||
final double price;
|
||||
|
@ -1246,29 +1287,21 @@ class TimeRange {
|
|||
}
|
||||
|
||||
class SortConfig {
|
||||
@observable
|
||||
String field;
|
||||
|
||||
@observable
|
||||
SortOrder order;
|
||||
|
||||
SortConfig(this.field, this.order);
|
||||
|
||||
@action
|
||||
void sortOn(String field) {
|
||||
if (field != this.field)
|
||||
order = SortOrder.Ascending;
|
||||
else
|
||||
order = nextSortOrder(order);
|
||||
this.field = field;
|
||||
SortConfig sortOn(String field) {
|
||||
final order = field != this.field ? SortOrder.Ascending : nextSortOrder(this.order);
|
||||
return SortConfig(field, order);
|
||||
}
|
||||
|
||||
String getIndicator(String field) {
|
||||
if (this.field != field) return '';
|
||||
if (order == SortOrder.Ascending)
|
||||
return ' \u2191';
|
||||
if (order == SortOrder.Descending)
|
||||
return ' \u2193';
|
||||
if (order == SortOrder.Ascending) return ' \u2191';
|
||||
if (order == SortOrder.Descending) return ' \u2193';
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
@ -1288,8 +1321,27 @@ class DecodedPaymentURI {
|
|||
}
|
||||
|
||||
class SendPageArgs {
|
||||
final bool isMulti;
|
||||
final Contact? contact;
|
||||
final String? uri;
|
||||
final List<Recipient> recipients;
|
||||
|
||||
SendPageArgs({this.contact, this.uri});
|
||||
SendPageArgs({this.isMulti = false, this.contact, this.uri, this.recipients = const[]});
|
||||
}
|
||||
|
||||
class ShareInfo {
|
||||
final int index;
|
||||
final int threshold;
|
||||
final int participants;
|
||||
final String value;
|
||||
|
||||
ShareInfo(this.index, this.threshold, this.participants, this.value);
|
||||
}
|
||||
|
||||
class TxSummary {
|
||||
final String address;
|
||||
final int amount;
|
||||
final String txJson;
|
||||
|
||||
TxSummary(this.address, this.amount, this.txJson);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,11 @@ hex = "0.4.3"
|
|||
|
||||
[dependencies.zcash_primitives]
|
||||
git = "https://github.com/hhanh00/librustzcash.git"
|
||||
rev = "6baf1ba63261dda09e5b1d4b476977842a1f61c8"
|
||||
rev = "1518b145f8ee67e144fa8337c7dfd4c8cff899c9"
|
||||
|
||||
[dependencies.zcash_multisig]
|
||||
git = "https://github.com/hhanh00/zcash-multisig.git"
|
||||
rev = "ce5baab5a25021950f51a9d53dc6c39ea9fe2997"
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "0.19.0"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef __APPLE__
|
||||
typedef char int8_t;
|
||||
typedef short int uint16_t;
|
||||
typedef long long int int64_t;
|
||||
typedef long long int uint64_t;
|
||||
typedef long long int uintptr_t;
|
||||
|
@ -17,7 +18,7 @@ void dart_post_cobject(DartPostCObjectFnType ptr);
|
|||
|
||||
uint32_t get_latest_height(void);
|
||||
|
||||
bool is_valid_key(char *seed);
|
||||
int8_t is_valid_key(char *seed);
|
||||
|
||||
bool valid_address(char *address);
|
||||
|
||||
|
@ -29,18 +30,10 @@ int32_t new_account(char *name, char *data);
|
|||
|
||||
int64_t get_mempool_balance(void);
|
||||
|
||||
const char *send_payment(uint32_t account,
|
||||
char *address,
|
||||
uint64_t amount,
|
||||
char *memo,
|
||||
uint64_t max_amount_per_note,
|
||||
uint32_t anchor_offset,
|
||||
bool shield_transparent_balance,
|
||||
int64_t port);
|
||||
|
||||
const char *send_multi_payment(uint32_t account,
|
||||
char *recipients_json,
|
||||
uint32_t anchor_offset,
|
||||
bool use_transparent,
|
||||
int64_t port);
|
||||
|
||||
int8_t try_warp_sync(bool get_tx, uint32_t anchor_offset);
|
||||
|
@ -59,16 +52,15 @@ char *shield_taddr(uint32_t account);
|
|||
|
||||
void set_lwd_url(char *url);
|
||||
|
||||
char *prepare_offline_tx(uint32_t account,
|
||||
char *to_address,
|
||||
uint64_t amount,
|
||||
char *memo,
|
||||
uint64_t max_amount_per_note,
|
||||
uint32_t anchor_offset,
|
||||
char *tx_filename);
|
||||
char *prepare_multi_payment(uint32_t account,
|
||||
char *recipients_json,
|
||||
bool use_transparent,
|
||||
uint32_t anchor_offset);
|
||||
|
||||
char *broadcast(char *tx_filename);
|
||||
|
||||
char *broadcast_txhex(char *txhex);
|
||||
|
||||
uint32_t sync_historical_prices(int64_t now, uint32_t days, char *currency);
|
||||
|
||||
char *get_ua(char *sapling_addr, char *transparent_addr);
|
||||
|
@ -87,4 +79,18 @@ char *make_payment_uri(char *address, uint64_t amount, char *memo);
|
|||
|
||||
char *parse_payment_uri(char *uri);
|
||||
|
||||
void store_share_secret(uint32_t account, char *secret);
|
||||
|
||||
char *get_share_secret(uint32_t account);
|
||||
|
||||
void run_aggregator(char *secret_share, uint16_t port, int64_t send_port);
|
||||
|
||||
void shutdown_aggregator(void);
|
||||
|
||||
char *submit_multisig_tx(char *tx_json, uint16_t port);
|
||||
|
||||
uint32_t run_multi_signer(char *secret_share, char *aggregator_url, char *my_url, uint16_t port);
|
||||
|
||||
char *split_account(uint32_t threshold, uint32_t participants, uint32_t account);
|
||||
|
||||
void dummy_export(void);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef __APPLE__
|
||||
typedef char int8_t;
|
||||
typedef short int uint16_t;
|
||||
typedef long long int int64_t;
|
||||
typedef long long int uint64_t;
|
||||
typedef long long int uintptr_t;
|
||||
|
|
|
@ -4,15 +4,23 @@ use android_logger::Config;
|
|||
use log::{error, info, Level};
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::io::Read;
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
use sync::{broadcast_tx, ChainError, MemPool, Wallet};
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::time::Duration;
|
||||
use zcash_multisig::{
|
||||
run_aggregator_service, run_signer_service, signer_connect_to_aggregator, submit_tx,
|
||||
SecretShare,
|
||||
};
|
||||
use zcash_primitives::transaction::builder::Progress;
|
||||
|
||||
static RUNTIME: OnceCell<Mutex<Runtime>> = OnceCell::new();
|
||||
static WALLET: OnceCell<Mutex<Wallet>> = OnceCell::new();
|
||||
static MEMPOOL: OnceCell<Mutex<MemPool>> = OnceCell::new();
|
||||
static SYNCLOCK: OnceCell<Mutex<()>> = OnceCell::new();
|
||||
static MULTISIG_AGG_LOCK: OnceCell<Mutex<MultisigAggregator>> = OnceCell::new();
|
||||
static MULTISIG_SIGN_LOCK: OnceCell<Mutex<MultisigClient>> = OnceCell::new();
|
||||
|
||||
fn get_lock<T>(cell: &OnceCell<Mutex<T>>) -> anyhow::Result<MutexGuard<T>> {
|
||||
cell.get()
|
||||
|
@ -48,6 +56,7 @@ fn log_result_string(result: anyhow::Result<String>) -> String {
|
|||
pub fn init_wallet(db_path: &str, ld_url: &str) {
|
||||
android_logger::init_once(Config::default().with_min_level(Level::Info));
|
||||
info!("Init");
|
||||
RUNTIME.get_or_init(|| Mutex::new(Runtime::new().unwrap()));
|
||||
WALLET.get_or_init(|| {
|
||||
info!("Wallet Init");
|
||||
let wallet = Wallet::new(db_path, ld_url);
|
||||
|
@ -59,6 +68,8 @@ pub fn init_wallet(db_path: &str, ld_url: &str) {
|
|||
Mutex::new(mempool)
|
||||
});
|
||||
SYNCLOCK.get_or_init(|| Mutex::new(()));
|
||||
MULTISIG_AGG_LOCK.get_or_init(|| Mutex::new(MultisigAggregator::new()));
|
||||
MULTISIG_SIGN_LOCK.get_or_init(|| Mutex::new(MultisigClient::new()));
|
||||
}
|
||||
|
||||
pub fn new_account(name: &str, data: &str) -> i32 {
|
||||
|
@ -192,28 +203,25 @@ fn report_progress(progress: Progress, port: i64) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn send_payment(
|
||||
pub fn send_multi_payment(
|
||||
account: u32,
|
||||
address: &str,
|
||||
amount: u64,
|
||||
memo: &str,
|
||||
max_amount_per_note: u64,
|
||||
anchor_offset: u32,
|
||||
recipients_json: &str,
|
||||
use_transparent: bool,
|
||||
anchor_offset: u32,
|
||||
port: i64,
|
||||
) -> String {
|
||||
let r = get_runtime();
|
||||
let res = r.block_on(async {
|
||||
let mut wallet = get_lock(&WALLET)?;
|
||||
let height = sync::latest_height(&wallet.ld_url).await?;
|
||||
let recipients = Wallet::parse_recipients(recipients_json)?;
|
||||
let res = wallet
|
||||
.send_payment(
|
||||
.build_sign_send_multi_payment(
|
||||
account,
|
||||
address,
|
||||
amount,
|
||||
memo,
|
||||
max_amount_per_note,
|
||||
anchor_offset,
|
||||
height,
|
||||
&recipients,
|
||||
use_transparent,
|
||||
anchor_offset,
|
||||
move |progress| {
|
||||
report_progress(progress, port);
|
||||
},
|
||||
|
@ -224,25 +232,6 @@ pub fn send_payment(
|
|||
log_result_string(res)
|
||||
}
|
||||
|
||||
pub fn send_multi_payment(
|
||||
account: u32,
|
||||
recipients_json: &str,
|
||||
anchor_offset: u32,
|
||||
port: i64,
|
||||
) -> String {
|
||||
let r = get_runtime();
|
||||
let res = r.block_on(async {
|
||||
let mut wallet = get_lock(&WALLET)?;
|
||||
let res = wallet
|
||||
.send_multi_payment(account, recipients_json, anchor_offset, move |progress| {
|
||||
report_progress(progress, port);
|
||||
})
|
||||
.await?;
|
||||
Ok(res)
|
||||
});
|
||||
log_result_string(res)
|
||||
}
|
||||
|
||||
pub fn skip_to_last_height() {
|
||||
let r = get_runtime();
|
||||
let res = r.block_on(async {
|
||||
|
@ -306,7 +295,8 @@ pub fn shield_taddr(account: u32) -> String {
|
|||
let r = get_runtime();
|
||||
let res = r.block_on(async {
|
||||
let mut wallet = get_lock(&WALLET)?;
|
||||
wallet.shield_taddr(account).await
|
||||
let height = sync::latest_height(&wallet.ld_url).await?;
|
||||
wallet.shield_taddr(account, height).await
|
||||
});
|
||||
log_result(res)
|
||||
}
|
||||
|
@ -319,48 +309,50 @@ pub fn set_lwd_url(url: &str) {
|
|||
log_result(res())
|
||||
}
|
||||
|
||||
pub fn prepare_offline_tx(
|
||||
pub fn prepare_multi_payment(
|
||||
account: u32,
|
||||
to_address: &str,
|
||||
amount: u64,
|
||||
memo: &str,
|
||||
max_amount_per_note: u64,
|
||||
recipients_json: &str,
|
||||
use_transparent: bool,
|
||||
anchor_offset: u32,
|
||||
tx_filename: &str,
|
||||
) -> String {
|
||||
let r = get_runtime();
|
||||
let res = r.block_on(async {
|
||||
let wallet = get_lock(&WALLET)?;
|
||||
let mut wallet = get_lock(&WALLET)?;
|
||||
let last_height = sync::latest_height(&wallet.ld_url).await?;
|
||||
let recipients = Wallet::parse_recipients(recipients_json)?;
|
||||
let tx = wallet
|
||||
.prepare_payment(
|
||||
.build_only_multi_payment(
|
||||
account,
|
||||
to_address,
|
||||
amount,
|
||||
memo,
|
||||
max_amount_per_note,
|
||||
last_height,
|
||||
&recipients,
|
||||
use_transparent,
|
||||
anchor_offset,
|
||||
)
|
||||
.await?;
|
||||
let mut file = File::create(tx_filename)?;
|
||||
writeln!(file, "{}", tx)?;
|
||||
Ok("File saved".to_string())
|
||||
Ok(tx)
|
||||
});
|
||||
log_result_string(res)
|
||||
}
|
||||
|
||||
async fn _broadcast(tx_filename: &str, ld_url: &str) -> anyhow::Result<String> {
|
||||
let mut file = File::open(&tx_filename)?;
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s)?;
|
||||
let tx = hex::decode(s.trim_end())?;
|
||||
broadcast_tx(&tx, ld_url).await
|
||||
}
|
||||
|
||||
pub fn broadcast(tx_filename: &str) -> String {
|
||||
let r = get_runtime();
|
||||
let res = r.block_on(async {
|
||||
let wallet = get_lock(&WALLET)?;
|
||||
_broadcast(tx_filename, &wallet.ld_url).await
|
||||
let mut file = File::open(&tx_filename)?;
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s)?;
|
||||
let tx = hex::decode(s.trim_end())?;
|
||||
broadcast_tx(&tx, &wallet.ld_url).await
|
||||
});
|
||||
log_result_string(res)
|
||||
}
|
||||
|
||||
pub fn broadcast_txhex(txhex: &str) -> String {
|
||||
let r = get_runtime();
|
||||
let res = r.block_on(async {
|
||||
let wallet = get_lock(&WALLET)?;
|
||||
let tx = hex::decode(txhex)?;
|
||||
broadcast_tx(&tx, &wallet.ld_url).await
|
||||
});
|
||||
log_result_string(res)
|
||||
}
|
||||
|
@ -441,3 +433,116 @@ pub fn parse_payment_uri(uri: &str) -> String {
|
|||
};
|
||||
log_result(res())
|
||||
}
|
||||
|
||||
pub fn store_share_secret(account: u32, secret: &str) {
|
||||
let res = || {
|
||||
let wallet = get_lock(&WALLET)?;
|
||||
wallet.store_share_secret(account, secret)?;
|
||||
Ok(())
|
||||
};
|
||||
log_result(res())
|
||||
}
|
||||
|
||||
pub fn get_share_secret(account: u32) -> String {
|
||||
let res = || {
|
||||
let wallet = get_lock(&WALLET)?;
|
||||
let secret = wallet.get_share_secret(account)?;
|
||||
Ok(secret)
|
||||
};
|
||||
log_result(res())
|
||||
}
|
||||
|
||||
struct MultisigAggregator {
|
||||
shutdown_signal: Option<tokio::sync::oneshot::Sender<()>>,
|
||||
}
|
||||
|
||||
impl MultisigAggregator {
|
||||
pub fn new() -> Self {
|
||||
MultisigAggregator {
|
||||
shutdown_signal: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_aggregator(secret_share: &str, port: u16, send_port: i64) {
|
||||
let runtime = get_lock(&RUNTIME).unwrap();
|
||||
let res = runtime.block_on(async {
|
||||
let mut aggregator = get_lock(&MULTISIG_AGG_LOCK)?;
|
||||
let (shutdown, _jh) = run_aggregator_service(
|
||||
port,
|
||||
secret_share,
|
||||
Box::new(move || {
|
||||
let mut null = ().into_dart();
|
||||
unsafe {
|
||||
POST_COBJ.map(|p| {
|
||||
p(send_port, &mut null);
|
||||
});
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
aggregator.shutdown_signal = Some(shutdown);
|
||||
Ok(())
|
||||
});
|
||||
log_result(res)
|
||||
}
|
||||
|
||||
pub fn shutdown_aggregator() {
|
||||
let res = || {
|
||||
let mut aggregator = get_lock(&MULTISIG_AGG_LOCK)?;
|
||||
let shutdown_signal = aggregator.shutdown_signal.take();
|
||||
if let Some(shutdown_signal) = shutdown_signal {
|
||||
let _ = shutdown_signal.send(());
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
log_result(res())
|
||||
}
|
||||
|
||||
pub fn submit_multisig_tx(tx_str: &str, port: u16) -> Vec<u8> {
|
||||
let r = get_runtime();
|
||||
let res: anyhow::Result<_> = r.block_on(async {
|
||||
let raw_tx = submit_tx(port, tx_str).await?;
|
||||
Ok(raw_tx)
|
||||
});
|
||||
let mut v: Vec<u8> = vec![];
|
||||
match res {
|
||||
Ok(raw_tx) => {
|
||||
v.push(0x00);
|
||||
v.extend(raw_tx);
|
||||
}
|
||||
Err(e) => {
|
||||
v.push(0x01);
|
||||
v.extend(e.to_string().as_bytes());
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
struct MultisigClient {}
|
||||
|
||||
impl MultisigClient {
|
||||
pub fn new() -> Self {
|
||||
MultisigClient {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_multi_signer(secret_share: &str, aggregator_url: &str, my_url: &str, port: u16) -> u32 {
|
||||
let runtime = get_lock(&RUNTIME).unwrap();
|
||||
let res = runtime.block_on(async {
|
||||
let _jh = run_signer_service(port, secret_share).await?;
|
||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||
let share = SecretShare::decode(secret_share)?;
|
||||
let error_code = signer_connect_to_aggregator(aggregator_url, my_url, share.index).await?;
|
||||
Ok(error_code)
|
||||
});
|
||||
log_result(res)
|
||||
}
|
||||
|
||||
pub fn split_account(threshold: u32, participants: u32, account: u32) -> String {
|
||||
let res = || {
|
||||
let wallet = get_lock(&WALLET)?;
|
||||
wallet.split_account(threshold as usize, participants as usize, account)
|
||||
};
|
||||
log_result(res())
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ pub unsafe extern "C" fn get_latest_height() -> u32 {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn is_valid_key(seed: *mut c_char) -> bool {
|
||||
pub unsafe extern "C" fn is_valid_key(seed: *mut c_char) -> i8 {
|
||||
let seed = CStr::from_ptr(seed).to_string_lossy();
|
||||
sync::is_valid_key(&seed)
|
||||
}
|
||||
|
@ -63,41 +63,22 @@ pub unsafe extern "C" fn get_mempool_balance() -> i64 {
|
|||
api::get_mempool_balance()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn send_payment(
|
||||
account: u32,
|
||||
address: *mut c_char,
|
||||
amount: u64,
|
||||
memo: *mut c_char,
|
||||
max_amount_per_note: u64,
|
||||
anchor_offset: u32,
|
||||
use_transparent: bool,
|
||||
port: i64,
|
||||
) -> *const c_char {
|
||||
let address = CStr::from_ptr(address).to_string_lossy();
|
||||
let memo = CStr::from_ptr(memo).to_string_lossy();
|
||||
let tx_id = api::send_payment(
|
||||
account,
|
||||
&address,
|
||||
amount,
|
||||
&memo,
|
||||
max_amount_per_note,
|
||||
anchor_offset,
|
||||
use_transparent,
|
||||
port,
|
||||
);
|
||||
CString::new(tx_id).unwrap().into_raw()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn send_multi_payment(
|
||||
account: u32,
|
||||
recipients_json: *mut c_char,
|
||||
anchor_offset: u32,
|
||||
use_transparent: bool,
|
||||
port: i64,
|
||||
) -> *const c_char {
|
||||
let recipients_json = CStr::from_ptr(recipients_json).to_string_lossy();
|
||||
let tx_id = api::send_multi_payment(account, &recipients_json, anchor_offset, port);
|
||||
let tx_id = api::send_multi_payment(
|
||||
account,
|
||||
&recipients_json,
|
||||
use_transparent,
|
||||
anchor_offset,
|
||||
port,
|
||||
);
|
||||
CString::new(tx_id).unwrap().into_raw()
|
||||
}
|
||||
|
||||
|
@ -144,28 +125,15 @@ pub unsafe extern "C" fn set_lwd_url(url: *mut c_char) {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn prepare_offline_tx(
|
||||
pub unsafe extern "C" fn prepare_multi_payment(
|
||||
account: u32,
|
||||
to_address: *mut c_char,
|
||||
amount: u64,
|
||||
memo: *mut c_char,
|
||||
max_amount_per_note: u64,
|
||||
recipients_json: *mut c_char,
|
||||
use_transparent: bool,
|
||||
anchor_offset: u32,
|
||||
tx_filename: *mut c_char,
|
||||
) -> *mut c_char {
|
||||
let to_address = CStr::from_ptr(to_address).to_string_lossy();
|
||||
let memo = CStr::from_ptr(memo).to_string_lossy();
|
||||
let tx_filename = CStr::from_ptr(tx_filename).to_string_lossy();
|
||||
let res = api::prepare_offline_tx(
|
||||
account,
|
||||
&to_address,
|
||||
amount,
|
||||
&memo,
|
||||
max_amount_per_note,
|
||||
anchor_offset,
|
||||
&tx_filename,
|
||||
);
|
||||
CString::new(res).unwrap().into_raw()
|
||||
let recipients_json = CStr::from_ptr(recipients_json).to_string_lossy();
|
||||
let tx = api::prepare_multi_payment(account, &recipients_json, use_transparent, anchor_offset);
|
||||
CString::new(tx).unwrap().into_raw()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -175,6 +143,13 @@ 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 broadcast_txhex(txhex: *mut c_char) -> *mut c_char {
|
||||
let txhex = CStr::from_ptr(txhex).to_string_lossy();
|
||||
let res = api::broadcast_txhex(&txhex);
|
||||
CString::new(res).unwrap().into_raw()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sync_historical_prices(now: i64, days: u32, currency: *mut c_char) -> u32 {
|
||||
let currency = CStr::from_ptr(currency).to_string_lossy();
|
||||
|
@ -246,5 +221,59 @@ pub unsafe extern "C" fn parse_payment_uri(uri: *mut c_char) -> *mut c_char {
|
|||
CString::new(payment_json).unwrap().into_raw()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn store_share_secret(account: u32, secret: *mut c_char) {
|
||||
let secret = CStr::from_ptr(secret).to_string_lossy();
|
||||
api::store_share_secret(account, &secret);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_share_secret(account: u32) -> *mut c_char {
|
||||
let secret = api::get_share_secret(account);
|
||||
CString::new(secret).unwrap().into_raw()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn run_aggregator(secret_share: *mut c_char, port: u16, send_port: i64) {
|
||||
let secret_share = CStr::from_ptr(secret_share).to_string_lossy();
|
||||
api::run_aggregator(&secret_share, port, send_port);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn shutdown_aggregator() {
|
||||
api::shutdown_aggregator();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn submit_multisig_tx(tx_json: *mut c_char, port: u16) -> *mut c_char {
|
||||
let tx_json = CStr::from_ptr(tx_json).to_string_lossy();
|
||||
let raw_tx = api::submit_multisig_tx(&tx_json, port);
|
||||
let raw_tx = hex::encode(raw_tx);
|
||||
CString::new(raw_tx).unwrap().into_raw()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn run_multi_signer(
|
||||
secret_share: *mut c_char,
|
||||
aggregator_url: *mut c_char,
|
||||
my_url: *mut c_char,
|
||||
port: u16,
|
||||
) -> u32 {
|
||||
let secret_share = CStr::from_ptr(secret_share).to_string_lossy();
|
||||
let aggregator_url = CStr::from_ptr(aggregator_url).to_string_lossy();
|
||||
let my_url = CStr::from_ptr(my_url).to_string_lossy();
|
||||
api::run_multi_signer(&secret_share, &aggregator_url, &my_url, port)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn split_account(
|
||||
threshold: u32,
|
||||
participants: u32,
|
||||
account: u32,
|
||||
) -> *mut c_char {
|
||||
let r = api::split_account(threshold, participants, account);
|
||||
CString::new(r).unwrap().into_raw()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dummy_export() {}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ce5baab5a25021950f51a9d53dc6c39ea9fe2997
|
|
@ -1 +1 @@
|
|||
Subproject commit f8eb2641dd7c4f3e57cd8c928334c1ae4e4284a4
|
||||
Subproject commit f54214d0a6752188efd1404e39b10be58a27ea0f
|
|
@ -1 +1 @@
|
|||
Subproject commit 2470a4e6af618aa6a5c85948b1c558d265d54484
|
||||
Subproject commit ccb25c61f9349c1d4142bbf58ed1bb57f1b9cfeb
|
|
@ -7,7 +7,7 @@ packages:
|
|||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.6.1"
|
||||
version: "2.8.1"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -28,7 +28,7 @@ packages:
|
|||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -43,6 +43,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -64,6 +71,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -74,6 +88,13 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: json_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.3.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -87,7 +108,7 @@ packages:
|
|||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.7.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -95,6 +116,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
protobuf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: protobuf
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -141,7 +169,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
version: "0.4.2"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -164,5 +192,5 @@ packages:
|
|||
source: path
|
||||
version: "0.0.1"
|
||||
sdks:
|
||||
dart: ">=2.12.0 <3.0.0"
|
||||
dart: ">=2.14.0 <3.0.0"
|
||||
flutter: ">=1.20.0"
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'types.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Recipient {
|
||||
// ignore: non_constant_identifier_names
|
||||
final String address;
|
||||
final int amount;
|
||||
final String memo;
|
||||
// ignore: non_constant_identifier_names
|
||||
final int max_amount_per_note;
|
||||
|
||||
Recipient(this.address, this.amount, this.memo, this.max_amount_per_note);
|
||||
|
||||
factory Recipient.fromJson(Map<String, dynamic> json) =>
|
||||
_$RecipientFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$RecipientToJson(this);
|
||||
}
|
||||
|
|
@ -1,12 +1,15 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'package:convert/convert.dart';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import './warp_api_generated.dart';
|
||||
import 'types.dart';
|
||||
|
||||
typedef report_callback = Void Function(Int32);
|
||||
const DAY_MS = 24 * 3600 * 1000;
|
||||
|
@ -21,25 +24,12 @@ class SyncParams {
|
|||
|
||||
class PaymentParams {
|
||||
int account;
|
||||
String address;
|
||||
int amount;
|
||||
String memo;
|
||||
int maxAmountPerNote;
|
||||
int anchorOffset;
|
||||
String recipientsJson;
|
||||
bool useTransparent;
|
||||
SendPort port;
|
||||
|
||||
PaymentParams(this.account, this.address, this.amount, this.memo, this.maxAmountPerNote,
|
||||
this.anchorOffset, this.useTransparent, this.port);
|
||||
}
|
||||
|
||||
class MultiPaymentParams {
|
||||
int account;
|
||||
String recipientJson;
|
||||
int anchorOffset;
|
||||
SendPort port;
|
||||
|
||||
MultiPaymentParams(this.account, this.recipientJson, this.anchorOffset, this.port);
|
||||
PaymentParams(this.account, this.recipientsJson, this.useTransparent, this.anchorOffset, this.port);
|
||||
}
|
||||
|
||||
class CommitContactsParams {
|
||||
|
@ -113,8 +103,8 @@ class WarpApi {
|
|||
return await compute(getLatestHeightIsolateFn, null);
|
||||
}
|
||||
|
||||
static bool validKey(String key) {
|
||||
return warp_api_lib.is_valid_key(key.toNativeUtf8().cast<Int8>()) != 0;
|
||||
static int validKey(String key) {
|
||||
return warp_api_lib.is_valid_key(key.toNativeUtf8().cast<Int8>());
|
||||
}
|
||||
|
||||
static bool validAddress(String address) {
|
||||
|
@ -144,29 +134,18 @@ class WarpApi {
|
|||
return warp_api_lib.get_mempool_balance();
|
||||
}
|
||||
|
||||
static Future<String> sendPayment(int account, String address, int amount, String memo,
|
||||
int maxAmountPerNote, int anchorOffset, bool useTransparent, void Function(int) f) async {
|
||||
static Future<String> sendPayment(int account, List<Recipient> recipients, bool useTransparent, int anchorOffset, void Function(int) f) async {
|
||||
var receivePort = ReceivePort();
|
||||
receivePort.listen((progress) {
|
||||
f(progress);
|
||||
});
|
||||
|
||||
final recipientJson = jsonEncode(recipients);
|
||||
|
||||
return await compute(
|
||||
sendPaymentIsolateFn,
|
||||
PaymentParams(
|
||||
account, address, amount, memo, maxAmountPerNote, anchorOffset, useTransparent, receivePort.sendPort));
|
||||
}
|
||||
|
||||
static Future<String> sendMultiPayment(int account, String recipientsJson, int anchorOffset, void Function(int) f) async {
|
||||
var receivePort = ReceivePort();
|
||||
receivePort.listen((progress) {
|
||||
f(progress);
|
||||
});
|
||||
|
||||
return await compute(
|
||||
sendMultiPaymentIsolateFn,
|
||||
MultiPaymentParams(
|
||||
account, recipientsJson, anchorOffset, receivePort.sendPort));
|
||||
account, recipientJson, useTransparent, anchorOffset, receivePort.sendPort));
|
||||
}
|
||||
|
||||
static int getTBalance(int account) {
|
||||
|
@ -186,16 +165,14 @@ class WarpApi {
|
|||
|
||||
static String prepareTx(
|
||||
int account,
|
||||
String toAddress,
|
||||
int amount,
|
||||
String memo,
|
||||
int maxAmountPerNote,
|
||||
List<Recipient> recipients,
|
||||
bool useTransparent,
|
||||
int anchorOffset,
|
||||
String txFilename) {
|
||||
final res = warp_api_lib.prepare_offline_tx(account,
|
||||
toAddress.toNativeUtf8().cast<Int8>(), amount,
|
||||
memo.toNativeUtf8().cast<Int8>(), maxAmountPerNote, anchorOffset,
|
||||
txFilename.toNativeUtf8().cast<Int8>());
|
||||
final recipientsJson = jsonEncode(recipients);
|
||||
final res = warp_api_lib.prepare_multi_payment(account,
|
||||
recipientsJson.toNativeUtf8().cast<Int8>(),
|
||||
useTransparent ? 1 : 0, anchorOffset);
|
||||
return res.cast<Utf8>().toDartString();
|
||||
}
|
||||
|
||||
|
@ -204,6 +181,11 @@ class WarpApi {
|
|||
return res.cast<Utf8>().toDartString();
|
||||
}
|
||||
|
||||
static String broadcastHex(String tx) {
|
||||
final res = warp_api_lib.broadcast_txhex(tx.toNativeUtf8().cast<Int8>());
|
||||
return res.cast<Utf8>().toDartString();
|
||||
}
|
||||
|
||||
static Future<int> syncHistoricalPrices(String currency) async {
|
||||
return await compute(syncHistoricalPricesIsolateFn, currency);
|
||||
}
|
||||
|
@ -241,26 +223,73 @@ class WarpApi {
|
|||
uri.toNativeUtf8().cast<Int8>());
|
||||
return json.cast<Utf8>().toDartString();
|
||||
}
|
||||
|
||||
static void storeShareSecret(int account, String secret) {
|
||||
warp_api_lib.store_share_secret(account, secret.toNativeUtf8().cast<Int8>());
|
||||
}
|
||||
|
||||
static Future<void> runAggregator(String secretShare, int port, SendPort sendPort) async {
|
||||
compute(runAggregatorIsolateFn, RunAggregatorParams(secretShare, port, sendPort.nativePort));
|
||||
}
|
||||
|
||||
static Future<String> submitTx(String txJson, int port) async {
|
||||
return await compute(submitTxIsolateFn, SubmitTxParams(txJson, port));
|
||||
}
|
||||
|
||||
static Future<int> runMultiSigner(String secretShare, String aggregatorUrl, String myUrl, int port) async {
|
||||
return await compute(runMultiSignerIsolateFn, RunMultiSignerParams(secretShare, aggregatorUrl, myUrl, port));
|
||||
}
|
||||
|
||||
static void stopAggregator() {
|
||||
warp_api_lib.shutdown_aggregator();
|
||||
}
|
||||
|
||||
static String splitAccount(int threshold, int participants, int account) {
|
||||
return warp_api_lib.split_account(threshold, participants, account).cast<Utf8>().toDartString();
|
||||
}
|
||||
}
|
||||
|
||||
class RunAggregatorParams {
|
||||
String secretShare;
|
||||
int port;
|
||||
int sendPort;
|
||||
RunAggregatorParams(this.secretShare, this.port, this.sendPort);
|
||||
}
|
||||
|
||||
void runAggregatorIsolateFn(RunAggregatorParams params) {
|
||||
warp_api_lib.run_aggregator(params.secretShare.toNativeUtf8().cast<Int8>(), params.port, params.sendPort);
|
||||
}
|
||||
|
||||
class SubmitTxParams {
|
||||
String txJson;
|
||||
int port;
|
||||
SubmitTxParams(this.txJson, this.port);
|
||||
}
|
||||
|
||||
String submitTxIsolateFn(SubmitTxParams params) {
|
||||
final r = warp_api_lib.submit_multisig_tx(params.txJson.toNativeUtf8().cast<Int8>(), params.port);
|
||||
return r.cast<Utf8>().toDartString();
|
||||
}
|
||||
|
||||
class RunMultiSignerParams {
|
||||
String secretShare;
|
||||
String aggregatorUrl;
|
||||
String myUrl;
|
||||
int port;
|
||||
RunMultiSignerParams(this.secretShare, this.aggregatorUrl, this.myUrl, this.port);
|
||||
}
|
||||
|
||||
int runMultiSignerIsolateFn(RunMultiSignerParams params) {
|
||||
return warp_api_lib.run_multi_signer(params.secretShare.toNativeUtf8().cast<Int8>(),
|
||||
params.aggregatorUrl.toNativeUtf8().cast<Int8>(), params.myUrl.toNativeUtf8().cast<Int8>(), params.port);
|
||||
}
|
||||
|
||||
String sendPaymentIsolateFn(PaymentParams params) {
|
||||
final txId = warp_api_lib.send_payment(
|
||||
params.account,
|
||||
params.address.toNativeUtf8().cast<Int8>(),
|
||||
params.amount,
|
||||
params.memo.toNativeUtf8().cast<Int8>(),
|
||||
params.maxAmountPerNote,
|
||||
params.anchorOffset,
|
||||
params.useTransparent ? 1 : 0,
|
||||
params.port.nativePort);
|
||||
return txId.cast<Utf8>().toDartString();
|
||||
}
|
||||
|
||||
String sendMultiPaymentIsolateFn(MultiPaymentParams params) {
|
||||
final txId = warp_api_lib.send_multi_payment(
|
||||
params.account,
|
||||
params.recipientJson.toNativeUtf8().cast<Int8>(),
|
||||
params.recipientsJson.toNativeUtf8().cast<Int8>(),
|
||||
params.anchorOffset,
|
||||
params.useTransparent ? 1 : 0,
|
||||
params.port.nativePort);
|
||||
return txId.cast<Utf8>().toDartString();
|
||||
}
|
||||
|
@ -285,7 +314,7 @@ String shieldTAddrIsolateFn(int account) {
|
|||
int syncHistoricalPricesIsolateFn(String currency) {
|
||||
final now = DateTime.now();
|
||||
final today = DateTime.utc(now.year, now.month, now.day);
|
||||
return warp_api_lib.sync_historical_prices(today.millisecondsSinceEpoch ~/ 1000, 370, currency.toNativeUtf8().cast<Int8>());
|
||||
return warp_api_lib.sync_historical_prices(today.millisecondsSinceEpoch ~/ 1000, 365, currency.toNativeUtf8().cast<Int8>());
|
||||
}
|
||||
|
||||
String commitUnsavedContactsIsolateFn(CommitContactsParams params) {
|
||||
|
@ -296,3 +325,4 @@ String commitUnsavedContactsIsolateFn(CommitContactsParams params) {
|
|||
int getTBalanceIsolateFn(int account) {
|
||||
return warp_api_lib.get_taddr_balance(account);
|
||||
}
|
||||
|
||||
|
|
|
@ -150,43 +150,18 @@ class NativeLibrary {
|
|||
late final _dart_get_mempool_balance _get_mempool_balance =
|
||||
_get_mempool_balance_ptr.asFunction<_dart_get_mempool_balance>();
|
||||
|
||||
ffi.Pointer<ffi.Int8> send_payment(
|
||||
int account,
|
||||
ffi.Pointer<ffi.Int8> address,
|
||||
int amount,
|
||||
ffi.Pointer<ffi.Int8> memo,
|
||||
int max_amount_per_note,
|
||||
int anchor_offset,
|
||||
int shield_transparent_balance,
|
||||
int port,
|
||||
) {
|
||||
return _send_payment(
|
||||
account,
|
||||
address,
|
||||
amount,
|
||||
memo,
|
||||
max_amount_per_note,
|
||||
anchor_offset,
|
||||
shield_transparent_balance,
|
||||
port,
|
||||
);
|
||||
}
|
||||
|
||||
late final _send_payment_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_send_payment>>('send_payment');
|
||||
late final _dart_send_payment _send_payment =
|
||||
_send_payment_ptr.asFunction<_dart_send_payment>();
|
||||
|
||||
ffi.Pointer<ffi.Int8> send_multi_payment(
|
||||
int account,
|
||||
ffi.Pointer<ffi.Int8> recipients_json,
|
||||
int anchor_offset,
|
||||
int use_transparent,
|
||||
int port,
|
||||
) {
|
||||
return _send_multi_payment(
|
||||
account,
|
||||
recipients_json,
|
||||
anchor_offset,
|
||||
use_transparent,
|
||||
port,
|
||||
);
|
||||
}
|
||||
|
@ -295,30 +270,25 @@ class NativeLibrary {
|
|||
late final _dart_set_lwd_url _set_lwd_url =
|
||||
_set_lwd_url_ptr.asFunction<_dart_set_lwd_url>();
|
||||
|
||||
ffi.Pointer<ffi.Int8> prepare_offline_tx(
|
||||
ffi.Pointer<ffi.Int8> prepare_multi_payment(
|
||||
int account,
|
||||
ffi.Pointer<ffi.Int8> to_address,
|
||||
int amount,
|
||||
ffi.Pointer<ffi.Int8> memo,
|
||||
int max_amount_per_note,
|
||||
ffi.Pointer<ffi.Int8> recipients_json,
|
||||
int use_transparent,
|
||||
int anchor_offset,
|
||||
ffi.Pointer<ffi.Int8> tx_filename,
|
||||
) {
|
||||
return _prepare_offline_tx(
|
||||
return _prepare_multi_payment(
|
||||
account,
|
||||
to_address,
|
||||
amount,
|
||||
memo,
|
||||
max_amount_per_note,
|
||||
recipients_json,
|
||||
use_transparent,
|
||||
anchor_offset,
|
||||
tx_filename,
|
||||
);
|
||||
}
|
||||
|
||||
late final _prepare_offline_tx_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_prepare_offline_tx>>('prepare_offline_tx');
|
||||
late final _dart_prepare_offline_tx _prepare_offline_tx =
|
||||
_prepare_offline_tx_ptr.asFunction<_dart_prepare_offline_tx>();
|
||||
late final _prepare_multi_payment_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_prepare_multi_payment>>(
|
||||
'prepare_multi_payment');
|
||||
late final _dart_prepare_multi_payment _prepare_multi_payment =
|
||||
_prepare_multi_payment_ptr.asFunction<_dart_prepare_multi_payment>();
|
||||
|
||||
ffi.Pointer<ffi.Int8> broadcast(
|
||||
ffi.Pointer<ffi.Int8> tx_filename,
|
||||
|
@ -333,6 +303,19 @@ class NativeLibrary {
|
|||
late final _dart_broadcast _broadcast =
|
||||
_broadcast_ptr.asFunction<_dart_broadcast>();
|
||||
|
||||
ffi.Pointer<ffi.Int8> broadcast_txhex(
|
||||
ffi.Pointer<ffi.Int8> txhex,
|
||||
) {
|
||||
return _broadcast_txhex(
|
||||
txhex,
|
||||
);
|
||||
}
|
||||
|
||||
late final _broadcast_txhex_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_broadcast_txhex>>('broadcast_txhex');
|
||||
late final _dart_broadcast_txhex _broadcast_txhex =
|
||||
_broadcast_txhex_ptr.asFunction<_dart_broadcast_txhex>();
|
||||
|
||||
int sync_historical_prices(
|
||||
int now,
|
||||
int days,
|
||||
|
@ -464,6 +447,112 @@ class NativeLibrary {
|
|||
late final _dart_parse_payment_uri _parse_payment_uri =
|
||||
_parse_payment_uri_ptr.asFunction<_dart_parse_payment_uri>();
|
||||
|
||||
void store_share_secret(
|
||||
int account,
|
||||
ffi.Pointer<ffi.Int8> secret,
|
||||
) {
|
||||
return _store_share_secret(
|
||||
account,
|
||||
secret,
|
||||
);
|
||||
}
|
||||
|
||||
late final _store_share_secret_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_store_share_secret>>('store_share_secret');
|
||||
late final _dart_store_share_secret _store_share_secret =
|
||||
_store_share_secret_ptr.asFunction<_dart_store_share_secret>();
|
||||
|
||||
ffi.Pointer<ffi.Int8> get_share_secret(
|
||||
int account,
|
||||
) {
|
||||
return _get_share_secret(
|
||||
account,
|
||||
);
|
||||
}
|
||||
|
||||
late final _get_share_secret_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_get_share_secret>>('get_share_secret');
|
||||
late final _dart_get_share_secret _get_share_secret =
|
||||
_get_share_secret_ptr.asFunction<_dart_get_share_secret>();
|
||||
|
||||
void run_aggregator(
|
||||
ffi.Pointer<ffi.Int8> secret_share,
|
||||
int port,
|
||||
int send_port,
|
||||
) {
|
||||
return _run_aggregator(
|
||||
secret_share,
|
||||
port,
|
||||
send_port,
|
||||
);
|
||||
}
|
||||
|
||||
late final _run_aggregator_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_run_aggregator>>('run_aggregator');
|
||||
late final _dart_run_aggregator _run_aggregator =
|
||||
_run_aggregator_ptr.asFunction<_dart_run_aggregator>();
|
||||
|
||||
void shutdown_aggregator() {
|
||||
return _shutdown_aggregator();
|
||||
}
|
||||
|
||||
late final _shutdown_aggregator_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_shutdown_aggregator>>(
|
||||
'shutdown_aggregator');
|
||||
late final _dart_shutdown_aggregator _shutdown_aggregator =
|
||||
_shutdown_aggregator_ptr.asFunction<_dart_shutdown_aggregator>();
|
||||
|
||||
ffi.Pointer<ffi.Int8> submit_multisig_tx(
|
||||
ffi.Pointer<ffi.Int8> tx_json,
|
||||
int port,
|
||||
) {
|
||||
return _submit_multisig_tx(
|
||||
tx_json,
|
||||
port,
|
||||
);
|
||||
}
|
||||
|
||||
late final _submit_multisig_tx_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_submit_multisig_tx>>('submit_multisig_tx');
|
||||
late final _dart_submit_multisig_tx _submit_multisig_tx =
|
||||
_submit_multisig_tx_ptr.asFunction<_dart_submit_multisig_tx>();
|
||||
|
||||
int run_multi_signer(
|
||||
ffi.Pointer<ffi.Int8> secret_share,
|
||||
ffi.Pointer<ffi.Int8> aggregator_url,
|
||||
ffi.Pointer<ffi.Int8> my_url,
|
||||
int port,
|
||||
) {
|
||||
return _run_multi_signer(
|
||||
secret_share,
|
||||
aggregator_url,
|
||||
my_url,
|
||||
port,
|
||||
);
|
||||
}
|
||||
|
||||
late final _run_multi_signer_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_run_multi_signer>>('run_multi_signer');
|
||||
late final _dart_run_multi_signer _run_multi_signer =
|
||||
_run_multi_signer_ptr.asFunction<_dart_run_multi_signer>();
|
||||
|
||||
ffi.Pointer<ffi.Int8> split_account(
|
||||
int threshold,
|
||||
int participants,
|
||||
int account,
|
||||
) {
|
||||
return _split_account(
|
||||
threshold,
|
||||
participants,
|
||||
account,
|
||||
);
|
||||
}
|
||||
|
||||
late final _split_account_ptr =
|
||||
_lookup<ffi.NativeFunction<_c_split_account>>('split_account');
|
||||
late final _dart_split_account _split_account =
|
||||
_split_account_ptr.asFunction<_dart_split_account>();
|
||||
|
||||
void dummy_export() {
|
||||
return _dummy_export();
|
||||
}
|
||||
|
@ -554,32 +643,11 @@ typedef _c_get_mempool_balance = ffi.Int64 Function();
|
|||
|
||||
typedef _dart_get_mempool_balance = int Function();
|
||||
|
||||
typedef _c_send_payment = ffi.Pointer<ffi.Int8> Function(
|
||||
ffi.Uint32 account,
|
||||
ffi.Pointer<ffi.Int8> address,
|
||||
ffi.Uint64 amount,
|
||||
ffi.Pointer<ffi.Int8> memo,
|
||||
ffi.Uint64 max_amount_per_note,
|
||||
ffi.Uint32 anchor_offset,
|
||||
ffi.Int8 shield_transparent_balance,
|
||||
ffi.Int64 port,
|
||||
);
|
||||
|
||||
typedef _dart_send_payment = ffi.Pointer<ffi.Int8> Function(
|
||||
int account,
|
||||
ffi.Pointer<ffi.Int8> address,
|
||||
int amount,
|
||||
ffi.Pointer<ffi.Int8> memo,
|
||||
int max_amount_per_note,
|
||||
int anchor_offset,
|
||||
int shield_transparent_balance,
|
||||
int port,
|
||||
);
|
||||
|
||||
typedef _c_send_multi_payment = ffi.Pointer<ffi.Int8> Function(
|
||||
ffi.Uint32 account,
|
||||
ffi.Pointer<ffi.Int8> recipients_json,
|
||||
ffi.Uint32 anchor_offset,
|
||||
ffi.Int8 use_transparent,
|
||||
ffi.Int64 port,
|
||||
);
|
||||
|
||||
|
@ -587,6 +655,7 @@ typedef _dart_send_multi_payment = ffi.Pointer<ffi.Int8> Function(
|
|||
int account,
|
||||
ffi.Pointer<ffi.Int8> recipients_json,
|
||||
int anchor_offset,
|
||||
int use_transparent,
|
||||
int port,
|
||||
);
|
||||
|
||||
|
@ -648,24 +717,18 @@ typedef _dart_set_lwd_url = void Function(
|
|||
ffi.Pointer<ffi.Int8> url,
|
||||
);
|
||||
|
||||
typedef _c_prepare_offline_tx = ffi.Pointer<ffi.Int8> Function(
|
||||
typedef _c_prepare_multi_payment = ffi.Pointer<ffi.Int8> Function(
|
||||
ffi.Uint32 account,
|
||||
ffi.Pointer<ffi.Int8> to_address,
|
||||
ffi.Uint64 amount,
|
||||
ffi.Pointer<ffi.Int8> memo,
|
||||
ffi.Uint64 max_amount_per_note,
|
||||
ffi.Pointer<ffi.Int8> recipients_json,
|
||||
ffi.Int8 use_transparent,
|
||||
ffi.Uint32 anchor_offset,
|
||||
ffi.Pointer<ffi.Int8> tx_filename,
|
||||
);
|
||||
|
||||
typedef _dart_prepare_offline_tx = ffi.Pointer<ffi.Int8> Function(
|
||||
typedef _dart_prepare_multi_payment = ffi.Pointer<ffi.Int8> Function(
|
||||
int account,
|
||||
ffi.Pointer<ffi.Int8> to_address,
|
||||
int amount,
|
||||
ffi.Pointer<ffi.Int8> memo,
|
||||
int max_amount_per_note,
|
||||
ffi.Pointer<ffi.Int8> recipients_json,
|
||||
int use_transparent,
|
||||
int anchor_offset,
|
||||
ffi.Pointer<ffi.Int8> tx_filename,
|
||||
);
|
||||
|
||||
typedef _c_broadcast = ffi.Pointer<ffi.Int8> Function(
|
||||
|
@ -676,6 +739,14 @@ typedef _dart_broadcast = ffi.Pointer<ffi.Int8> Function(
|
|||
ffi.Pointer<ffi.Int8> tx_filename,
|
||||
);
|
||||
|
||||
typedef _c_broadcast_txhex = ffi.Pointer<ffi.Int8> Function(
|
||||
ffi.Pointer<ffi.Int8> txhex,
|
||||
);
|
||||
|
||||
typedef _dart_broadcast_txhex = ffi.Pointer<ffi.Int8> Function(
|
||||
ffi.Pointer<ffi.Int8> txhex,
|
||||
);
|
||||
|
||||
typedef _c_sync_historical_prices = ffi.Uint32 Function(
|
||||
ffi.Int64 now,
|
||||
ffi.Uint32 days,
|
||||
|
@ -762,6 +833,76 @@ typedef _dart_parse_payment_uri = ffi.Pointer<ffi.Int8> Function(
|
|||
ffi.Pointer<ffi.Int8> uri,
|
||||
);
|
||||
|
||||
typedef _c_store_share_secret = ffi.Void Function(
|
||||
ffi.Uint32 account,
|
||||
ffi.Pointer<ffi.Int8> secret,
|
||||
);
|
||||
|
||||
typedef _dart_store_share_secret = void Function(
|
||||
int account,
|
||||
ffi.Pointer<ffi.Int8> secret,
|
||||
);
|
||||
|
||||
typedef _c_get_share_secret = ffi.Pointer<ffi.Int8> Function(
|
||||
ffi.Uint32 account,
|
||||
);
|
||||
|
||||
typedef _dart_get_share_secret = ffi.Pointer<ffi.Int8> Function(
|
||||
int account,
|
||||
);
|
||||
|
||||
typedef _c_run_aggregator = ffi.Void Function(
|
||||
ffi.Pointer<ffi.Int8> secret_share,
|
||||
ffi.Uint16 port,
|
||||
ffi.Int64 send_port,
|
||||
);
|
||||
|
||||
typedef _dart_run_aggregator = void Function(
|
||||
ffi.Pointer<ffi.Int8> secret_share,
|
||||
int port,
|
||||
int send_port,
|
||||
);
|
||||
|
||||
typedef _c_shutdown_aggregator = ffi.Void Function();
|
||||
|
||||
typedef _dart_shutdown_aggregator = void Function();
|
||||
|
||||
typedef _c_submit_multisig_tx = ffi.Pointer<ffi.Int8> Function(
|
||||
ffi.Pointer<ffi.Int8> tx_json,
|
||||
ffi.Uint16 port,
|
||||
);
|
||||
|
||||
typedef _dart_submit_multisig_tx = ffi.Pointer<ffi.Int8> Function(
|
||||
ffi.Pointer<ffi.Int8> tx_json,
|
||||
int port,
|
||||
);
|
||||
|
||||
typedef _c_run_multi_signer = ffi.Uint32 Function(
|
||||
ffi.Pointer<ffi.Int8> secret_share,
|
||||
ffi.Pointer<ffi.Int8> aggregator_url,
|
||||
ffi.Pointer<ffi.Int8> my_url,
|
||||
ffi.Uint16 port,
|
||||
);
|
||||
|
||||
typedef _dart_run_multi_signer = int Function(
|
||||
ffi.Pointer<ffi.Int8> secret_share,
|
||||
ffi.Pointer<ffi.Int8> aggregator_url,
|
||||
ffi.Pointer<ffi.Int8> my_url,
|
||||
int port,
|
||||
);
|
||||
|
||||
typedef _c_split_account = ffi.Pointer<ffi.Int8> Function(
|
||||
ffi.Uint32 threshold,
|
||||
ffi.Uint32 participants,
|
||||
ffi.Uint32 account,
|
||||
);
|
||||
|
||||
typedef _dart_split_account = ffi.Pointer<ffi.Int8> Function(
|
||||
int threshold,
|
||||
int participants,
|
||||
int account,
|
||||
);
|
||||
|
||||
typedef _c_dummy_export = ffi.Void Function();
|
||||
|
||||
typedef _dart_dummy_export = void Function();
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "30.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.7.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -14,7 +28,7 @@ packages:
|
|||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.6.1"
|
||||
version: "2.8.1"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -22,6 +36,62 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
build:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
build_resolvers:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_resolvers
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "7.2.2"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
built_value:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.1.3"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -35,7 +105,14 @@ packages:
|
|||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.1"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -50,6 +127,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: code_builder
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -57,6 +141,27 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
convert:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: convert
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -85,6 +190,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -95,6 +207,13 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: frontend_server_client
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -102,13 +221,55 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
isolate:
|
||||
dependency: "direct main"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: isolate
|
||||
name: graphs
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.3"
|
||||
json_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: json_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
json_serializable:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: json_serializable
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.2"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -129,7 +290,21 @@ packages:
|
|||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.7.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -144,6 +319,34 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
protobuf:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: protobuf
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -151,11 +354,39 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -177,6 +408,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_transform
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -197,7 +435,14 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
version: "0.4.2"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -212,6 +457,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -220,5 +479,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.0"
|
||||
sdks:
|
||||
dart: ">=2.12.0 <3.0.0"
|
||||
dart: ">=2.14.0 <3.0.0"
|
||||
flutter: ">=1.20.0"
|
||||
|
|
|
@ -11,11 +11,16 @@ dependencies:
|
|||
flutter:
|
||||
sdk: flutter
|
||||
ffi: 1.1.2
|
||||
convert: ^3.0.1
|
||||
protobuf: ^2.0.0
|
||||
json_annotation: ^4.1.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
ffigen: 2.4.2
|
||||
build_runner: ^2.1.2
|
||||
json_serializable: ^5.0.0
|
||||
|
||||
ffigen:
|
||||
output: 'lib/warp_api_generated.dart'
|
||||
|
|
60
pubspec.lock
60
pubspec.lock
|
@ -315,7 +315,7 @@ packages:
|
|||
name: fl_chart
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.40.0"
|
||||
version: "0.40.2"
|
||||
flex_color_scheme:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -555,6 +555,15 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
k_chart:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "821f81681f8ee819cd721498f7b28d290f4ebe38"
|
||||
resolved-ref: "821f81681f8ee819cd721498f7b28d290f4ebe38"
|
||||
url: "https://github.com/hhanh00/k_chart.git"
|
||||
source: git
|
||||
version: "0.4.1"
|
||||
list_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -632,6 +641,48 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
network_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: network_info_plus
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
network_info_plus_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: network_info_plus_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
network_info_plus_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: network_info_plus_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
network_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: network_info_plus_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
network_info_plus_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: network_info_plus_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
network_info_plus_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: network_info_plus_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
nm:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -807,6 +858,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.2.3"
|
||||
protobuf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: protobuf
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -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.12+179
|
||||
version: 1.1.0+184
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
@ -45,6 +45,10 @@ dependencies:
|
|||
flex_color_scheme: ^3.0.1
|
||||
flutter_colorpicker: ^0.6.0
|
||||
fl_chart: ^0.40.0
|
||||
k_chart:
|
||||
git:
|
||||
url: https://github.com/hhanh00/k_chart.git
|
||||
ref: 821f81681f8ee819cd721498f7b28d290f4ebe38
|
||||
grouped_list: ^4.1.0
|
||||
json_annotation: ^4.1.0
|
||||
share_plus: ^2.1.4
|
||||
|
@ -65,6 +69,7 @@ dependencies:
|
|||
uni_links: ^0.5.1
|
||||
quick_actions: ^0.6.0
|
||||
csv: ^5.0.0
|
||||
network_info_plus : ^2.0.2
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
|
||||
|
@ -84,7 +89,7 @@ dev_dependencies:
|
|||
flutter_native_splash: ^1.2.3
|
||||
|
||||
flutter_app_name:
|
||||
name: "YWallet"
|
||||
name: "ZWallet"
|
||||
|
||||
flutter_icons:
|
||||
android: true
|
||||
|
|
|
@ -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.12+179
|
||||
version: 1.1.0+184
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
@ -45,6 +45,10 @@ dependencies:
|
|||
flex_color_scheme: ^3.0.1
|
||||
flutter_colorpicker: ^0.6.0
|
||||
fl_chart: ^0.40.0
|
||||
k_chart:
|
||||
git:
|
||||
url: https://github.com/hhanh00/k_chart.git
|
||||
ref: 821f81681f8ee819cd721498f7b28d290f4ebe38
|
||||
grouped_list: ^4.1.0
|
||||
json_annotation: ^4.1.0
|
||||
share_plus: ^2.1.4
|
||||
|
@ -65,6 +69,7 @@ dependencies:
|
|||
uni_links: ^0.5.1
|
||||
quick_actions: ^0.6.0
|
||||
csv: ^5.0.0
|
||||
network_info_plus : ^2.0.2
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
|
||||
|
|
|
@ -25,8 +25,9 @@
|
|||
|
||||
<title>warp</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" type="text/css" href="splash/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<body style="position: fixed; inset: 0px; overflow: hidden; padding: 0px; margin: 0px; user-select: none; touch-action: none; font: 14px sans-serif; color: red;">
|
||||
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||
application. For more information, see:
|
||||
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||
|
@ -94,5 +95,10 @@
|
|||
loadMainDartJs();
|
||||
}
|
||||
</script>
|
||||
<picture id="splash">
|
||||
<source srcset="splash/img/light-1x.png 1x, splash/img/light-2x.png 2x, splash/img/light-3x.png 3x, splash/img/light-4x.png 4x" media="(prefers-color-scheme: light) or (prefers-color-scheme: no-preference)">
|
||||
<source srcset="splash/img/dark-1x.png 1x, splash/img/dark-2x.png 2x, splash/img/dark-3x.png 3x, splash/img/dark-4x.png 4x" media="(prefers-color-scheme: dark)">
|
||||
<img class="center" src="splash/img/light-1x.png" />
|
||||
</picture>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
Loading…
Reference in New Issue