Merge pull request #1397 from Electric-Coin-Company/1359-expose-proposals
Expose APIs for working with transaction proposals
This commit is contained in:
commit
5b04cbc579
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -6,6 +6,13 @@ and this library adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [2.0.7] - 2024-03-08
|
||||
|
||||
### Fixed
|
||||
- `Synchronizer.sendToAddress` and `Synchronizer.shieldFunds` now throw an
|
||||
exception if the created transaction successfully reaches `lightwalletd` but
|
||||
fails to reach its backing full node's mempool.
|
||||
|
||||
### Changed
|
||||
- `WalletBalance` now contains new fields `changePending` and `valuePending`. Fields `total` and `pending` are
|
||||
still provided. See more in the class documentation
|
||||
|
@ -13,8 +20,18 @@ and this library adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- `Synchronizer.transparentBalances: WalletBalance` to `Synchronizer.transparentBalance: Zatoshi`
|
||||
- `WalletSnapshot.transparentBalance: WalletBalance` to `WalletSnapshot.transparentBalance: Zatoshi`
|
||||
- `Memo.MAX_MEMO_LENGTH_BYTES` is now available in public API
|
||||
- `Synchronizer.sendToAddress` and `Synchronizer.shieldFunds` have been
|
||||
deprecated, and will be removed in 2.1.0 (which will create multiple
|
||||
transactions at once for some recipients).
|
||||
|
||||
### Added
|
||||
- APIs that enable constructing a proposal for transferring or shielding funds,
|
||||
and then creating transactions from a proposal. The intermediate proposal can
|
||||
be used to determine the required fee, before committing to producing
|
||||
transactions.
|
||||
- `Synchronizer.proposeTransfer`
|
||||
- `Synchronizer.proposeShielding`
|
||||
- `Synchronizer.createProposedTransactions`
|
||||
- `WalletBalanceFixture` class with mock values that are supposed to be used only for testing purposes
|
||||
- `Memo.countLength(memoString: String)` to count memo length in bytes
|
||||
- `PersistableWallet.toSafeString` is a safe alternative for the regular [toString] function that prints only
|
||||
|
|
|
@ -29,9 +29,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
|
||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
|
@ -40,9 +40,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.7"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
@ -67,9 +67,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.79"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
|
@ -163,12 +163,6 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.2"
|
||||
|
@ -243,9 +237,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.14.0"
|
||||
version = "3.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
||||
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
|
@ -270,12 +264,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
version = "1.0.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
|
@ -351,9 +342,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.11"
|
||||
version = "0.5.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
|
||||
checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
@ -448,7 +439,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -462,14 +453,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||
|
||||
[[package]]
|
||||
name = "equihash"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a#9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab579d7cf78477773b03e80bc2f89702ef02d7112c711d54ca93dcdce68533d5"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"byteorder",
|
||||
|
@ -494,7 +486,8 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "f4jumble"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a#9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a83e8d7fd0c526af4aad893b7c9fe41e2699ed8a776a6c74aecdeafe05afc75"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
]
|
||||
|
@ -707,9 +700,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.4"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
|
@ -746,9 +739,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.1"
|
||||
version = "2.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b"
|
||||
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
|
@ -802,9 +795,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.67"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -843,9 +836,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.152"
|
||||
version = "0.2.153"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
|
@ -878,9 +871,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
|
|||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
|
||||
[[package]]
|
||||
name = "log-panics"
|
||||
|
@ -924,9 +917,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
|||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
@ -984,20 +977,25 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.17"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
@ -1029,15 +1027,15 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
|||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "orchard"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92c801aeaccd19bb6916d71f25694b62d223061872900e8022221c1ad8dcad2d"
|
||||
checksum = "1fb255c3ffdccd3c84fe9ebed72aef64fdc72e6a3e4180dd411002d47abaad42"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bitvec",
|
||||
|
@ -1152,9 +1150,9 @@ checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
|||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.29"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
|
||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "poly1305"
|
||||
|
@ -1186,7 +1184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1225,7 +1223,7 @@ dependencies = [
|
|||
"prost",
|
||||
"prost-types",
|
||||
"regex",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
"tempfile",
|
||||
"which",
|
||||
]
|
||||
|
@ -1240,7 +1238,7 @@ dependencies = [
|
|||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1299,9 +1297,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.8.1"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
|
||||
checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
|
@ -1348,15 +1346,6 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.3"
|
||||
|
@ -1371,9 +1360,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -1416,7 +1405,7 @@ version = "0.29.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
|
@ -1433,11 +1422,11 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.30"
|
||||
version = "0.38.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
|
||||
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
|
@ -1455,9 +1444,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sapling-crypto"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f5de898a7cdb7f6d9c8fb888341b6ae6e2aeae88227b7f435f1dda49ecf9e62"
|
||||
checksum = "d183012062dfdde85f7e3e758328fcf6e9846d8dd3fce35b04d0efcb6677b0e0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bellman",
|
||||
|
@ -1537,22 +1526,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.196"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
|
||||
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.196"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
|
||||
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1581,7 +1570,7 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf20c7a2747d9083092e3a3eeb9a7ed75577ae364896bebbc5e0bdcd4e97735"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"bitflags",
|
||||
"either",
|
||||
"incrementalmerkletree",
|
||||
"tracing",
|
||||
|
@ -1624,9 +1613,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.48"
|
||||
version = "2.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1653,42 +1642,41 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
|||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.9.0"
|
||||
version = "3.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
||||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.56"
|
||||
version = "1.0.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
|
||||
checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.56"
|
||||
version = "1.0.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
||||
checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.7"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
|
||||
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
@ -1696,12 +1684,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.31"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e"
|
||||
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
|
@ -1716,10 +1705,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
|||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.16"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f"
|
||||
checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
|
@ -1748,7 +1738,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"prost-build",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1770,7 +1760,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1834,9 +1824,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
@ -1889,9 +1879,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
|
@ -1905,9 +1895,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.90"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
|
||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -1915,24 +1905,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.90"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
|
||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.90"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
|
||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -1940,28 +1930,28 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.90"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
|
||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.90"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.67"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed"
|
||||
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
@ -2025,7 +2015,7 @@ version = "0.52.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2045,17 +2035,17 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
"windows_aarch64_gnullvm 0.52.4",
|
||||
"windows_aarch64_msvc 0.52.4",
|
||||
"windows_i686_gnu 0.52.4",
|
||||
"windows_i686_msvc 0.52.4",
|
||||
"windows_x86_64_gnu 0.52.4",
|
||||
"windows_x86_64_gnullvm 0.52.4",
|
||||
"windows_x86_64_msvc 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2066,9 +2056,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
|||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
|
@ -2078,9 +2068,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
|||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
|
@ -2090,9 +2080,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
|||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
|
@ -2102,9 +2092,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
|||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
|
@ -2114,9 +2104,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
|||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
|
@ -2126,9 +2116,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
|||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
|
@ -2138,9 +2128,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
|||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
|
@ -2169,7 +2159,6 @@ dependencies = [
|
|||
"jni",
|
||||
"libc",
|
||||
"log-panics",
|
||||
"orchard",
|
||||
"paranoid-android",
|
||||
"prost",
|
||||
"rayon",
|
||||
|
@ -2189,19 +2178,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zcash_address"
|
||||
version = "0.3.1"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a#9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "827c17a1f7e3a69f0d44e991ff610c7a842228afdc9dc2325ffdd1a67fee01e9"
|
||||
dependencies = [
|
||||
"bech32",
|
||||
"bs58",
|
||||
"f4jumble",
|
||||
"zcash_encoding",
|
||||
"zcash_protocol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_client_backend"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a#9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "185913267d824529b9547c933674963fca2b5bd84ad377a59d0f8ab6159ce798"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bech32",
|
||||
|
@ -2239,8 +2231,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zcash_client_sqlite"
|
||||
version = "0.8.1"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a#9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e883405989b8d7275a0e1180000b7568bb3fa33e36b4806c174eb802678e2dbf"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"byteorder",
|
||||
|
@ -2250,7 +2243,6 @@ dependencies = [
|
|||
"incrementalmerkletree",
|
||||
"jubjub",
|
||||
"maybe-rayon",
|
||||
"orchard",
|
||||
"prost",
|
||||
"rusqlite",
|
||||
"sapling-crypto",
|
||||
|
@ -2271,7 +2263,8 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_encoding"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a#9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f03391b81727875efa6ac0661a20883022b6fba92365dc121c48fa9b00c5aac0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"nonempty",
|
||||
|
@ -2279,8 +2272,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zcash_keys"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a#9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f22d3407fdd6992b49f037f23862ab376be6013be6f2d0bc85948a635edc1f5"
|
||||
dependencies = [
|
||||
"bech32",
|
||||
"bls12_381",
|
||||
|
@ -2317,8 +2311,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zcash_primitives"
|
||||
version = "0.13.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a#9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9070e084570bb78aed4f8d71fd6254492e62c87a5d01e084183980e98117092d"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bip0039",
|
||||
|
@ -2354,8 +2349,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zcash_proofs"
|
||||
version = "0.13.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a#9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8a02eb1f151d9b9a6e16408d2c55ff440bd2fb232b7377277146d0fa2df9bc8"
|
||||
dependencies = [
|
||||
"bellman",
|
||||
"blake2b_simd",
|
||||
|
@ -2374,6 +2370,16 @@ dependencies = [
|
|||
"zcash_primitives",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_protocol"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c651f9f95d319cd1e5211178108dcd3aa73063806d09af54b799e1a329a575bf"
|
||||
dependencies = [
|
||||
"document-features",
|
||||
"memuse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_spec"
|
||||
version = "0.1.0"
|
||||
|
@ -2400,7 +2406,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2420,7 +2426,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -23,11 +23,10 @@ schemer = "0.2"
|
|||
secp256k1 = "0.26"
|
||||
secrecy = "0.8"
|
||||
zcash_address = "0.3"
|
||||
zcash_client_backend = { version = "0.10", features = ["transparent-inputs", "unstable"] }
|
||||
zcash_client_sqlite = { version = "^0.8.1", features = ["transparent-inputs", "unstable"] }
|
||||
zcash_primitives = "0.13"
|
||||
zcash_proofs = "0.13"
|
||||
orchard = { version = "0.7", default-features = false }
|
||||
zcash_client_backend = { version = "0.11", features = ["transparent-inputs", "unstable"] }
|
||||
zcash_client_sqlite = { version = "0.9", features = ["transparent-inputs", "unstable"] }
|
||||
zcash_primitives = "0.14"
|
||||
zcash_proofs = "0.14"
|
||||
|
||||
# Initialization
|
||||
rayon = "1.7"
|
||||
|
@ -62,11 +61,3 @@ libc = "0.2"
|
|||
name = "zcashwalletsdk"
|
||||
path = "src/main/rust/lib.rs"
|
||||
crate-type = ["staticlib", "cdylib"]
|
||||
|
||||
[patch.crates-io]
|
||||
# Tag `ecc_sdk-20240130a`
|
||||
zcash_address = { git = "https://github.com/zcash/librustzcash.git", rev = "9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a" }
|
||||
zcash_client_backend = { git = "https://github.com/zcash/librustzcash.git", rev = "9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a" }
|
||||
zcash_client_sqlite = { git = "https://github.com/zcash/librustzcash.git", rev = "9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a" }
|
||||
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a" }
|
||||
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "9b5abe1a386f2c2c625d8f3fb3b6e9ce9aff641a" }
|
||||
|
|
|
@ -30,13 +30,15 @@ interface Backend {
|
|||
|
||||
suspend fun proposeShielding(
|
||||
account: Int,
|
||||
memo: ByteArray? = byteArrayOf()
|
||||
): ProposalUnsafe
|
||||
shieldingThreshold: Long,
|
||||
memo: ByteArray? = byteArrayOf(),
|
||||
transparentReceiver: String? = null
|
||||
): ProposalUnsafe?
|
||||
|
||||
suspend fun createProposedTransaction(
|
||||
suspend fun createProposedTransactions(
|
||||
proposal: ProposalUnsafe,
|
||||
unifiedSpendingKey: ByteArray
|
||||
): ByteArray
|
||||
): List<ByteArray>
|
||||
|
||||
suspend fun decryptAndStoreTransaction(tx: ByteArray)
|
||||
|
||||
|
|
|
@ -307,34 +307,40 @@ class RustBackend private constructor(
|
|||
|
||||
override suspend fun proposeShielding(
|
||||
account: Int,
|
||||
memo: ByteArray?
|
||||
): ProposalUnsafe {
|
||||
shieldingThreshold: Long,
|
||||
memo: ByteArray?,
|
||||
transparentReceiver: String?
|
||||
): ProposalUnsafe? {
|
||||
return withContext(SdkDispatchers.DATABASE_IO) {
|
||||
ProposalUnsafe.parse(
|
||||
proposeShielding(
|
||||
dataDbFile.absolutePath,
|
||||
account,
|
||||
shieldingThreshold,
|
||||
memo ?: ByteArray(0),
|
||||
transparentReceiver,
|
||||
networkId = networkId,
|
||||
useZip317Fees = IS_USE_ZIP_317_FEES
|
||||
)?.let {
|
||||
ProposalUnsafe.parse(
|
||||
it
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun createProposedTransaction(
|
||||
override suspend fun createProposedTransactions(
|
||||
proposal: ProposalUnsafe,
|
||||
unifiedSpendingKey: ByteArray
|
||||
): ByteArray =
|
||||
): List<ByteArray> =
|
||||
withContext(SdkDispatchers.DATABASE_IO) {
|
||||
createProposedTransaction(
|
||||
createProposedTransactions(
|
||||
dataDbFile.absolutePath,
|
||||
proposal.toByteArray(),
|
||||
unifiedSpendingKey,
|
||||
spendParamsPath = saplingSpendFile.absolutePath,
|
||||
outputParamsPath = saplingOutputFile.absolutePath,
|
||||
networkId = networkId
|
||||
)
|
||||
).asList()
|
||||
}
|
||||
|
||||
override suspend fun putUtxo(
|
||||
|
@ -584,21 +590,23 @@ class RustBackend private constructor(
|
|||
private external fun proposeShielding(
|
||||
dbDataPath: String,
|
||||
account: Int,
|
||||
shieldingThreshold: Long,
|
||||
memo: ByteArray,
|
||||
transparentReceiver: String?,
|
||||
networkId: Int,
|
||||
useZip317Fees: Boolean
|
||||
): ByteArray
|
||||
): ByteArray?
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("LongParameterList")
|
||||
private external fun createProposedTransaction(
|
||||
private external fun createProposedTransactions(
|
||||
dbDataPath: String,
|
||||
proposal: ByteArray,
|
||||
usk: ByteArray,
|
||||
spendParamsPath: String,
|
||||
outputParamsPath: String,
|
||||
networkId: Int
|
||||
): ByteArray
|
||||
): Array<ByteArray>
|
||||
|
||||
@JvmStatic
|
||||
private external fun branchIdForHeight(
|
||||
|
|
|
@ -38,9 +38,21 @@ class ProposalUnsafe(
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the fee required by this proposal.
|
||||
* Returns the number of transactions that this proposal will create.
|
||||
*
|
||||
* This is equal to the number of `TransactionSubmitResult`s that will be returned
|
||||
* from `Synchronizer.createProposedTransactions`.
|
||||
*
|
||||
* Proposals always create at least one transaction.
|
||||
*/
|
||||
fun feeRequired(): Long {
|
||||
return inner.balance.feeRequired
|
||||
fun transactionCount(): Int {
|
||||
return inner.stepsCount
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total fee required by this proposal for its transactions.
|
||||
*/
|
||||
fun totalFeeRequired(): Long {
|
||||
return inner.stepsList.fold(0) { acc, step -> acc + step.balance.feeRequired }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,29 @@ syntax = "proto3";
|
|||
package cash.z.wallet.sdk.ffi;
|
||||
option java_package = "cash.z.wallet.sdk.internal.ffi";
|
||||
|
||||
// A data structure that describes a series of transactions to be created.
|
||||
message Proposal {
|
||||
// The version of this serialization format.
|
||||
uint32 protoVersion = 1;
|
||||
// The fee rule used in constructing this proposal
|
||||
FeeRule feeRule = 2;
|
||||
// The target height for which the proposal was constructed
|
||||
//
|
||||
// The chain must contain at least this many blocks in order for the proposal to
|
||||
// be executed.
|
||||
uint32 minTargetHeight = 3;
|
||||
// The series of transactions to be created.
|
||||
repeated ProposalStep steps = 4;
|
||||
}
|
||||
|
||||
// A data structure that describes the inputs to be consumed and outputs to
|
||||
// be produced in a proposed transaction.
|
||||
message Proposal {
|
||||
uint32 protoVersion = 1;
|
||||
message ProposalStep {
|
||||
// ZIP 321 serialized transaction request
|
||||
string transactionRequest = 2;
|
||||
string transactionRequest = 1;
|
||||
// The vector of selected payment index / output pool mappings. Payment index
|
||||
// 0 corresponds to the payment with no explicit index.
|
||||
repeated PaymentOutputPool paymentOutputPools = 2;
|
||||
// The anchor height to be used in creating the transaction, if any.
|
||||
// Setting the anchor height to zero will disallow the use of any shielded
|
||||
// inputs.
|
||||
|
@ -21,16 +38,9 @@ message Proposal {
|
|||
// The total value, fee value, and change outputs of the proposed
|
||||
// transaction
|
||||
TransactionBalance balance = 5;
|
||||
// The fee rule used in constructing this proposal
|
||||
FeeRule feeRule = 6;
|
||||
// The target height for which the proposal was constructed
|
||||
//
|
||||
// The chain must contain at least this many blocks in order for the proposal to
|
||||
// be executed.
|
||||
uint32 minTargetHeight = 7;
|
||||
// A flag indicating whether the proposal is for a shielding transaction,
|
||||
// A flag indicating whether the step is for a shielding transaction,
|
||||
// used for determining which OVK to select for wallet-internal outputs.
|
||||
bool isShielding = 8;
|
||||
bool isShielding = 6;
|
||||
}
|
||||
|
||||
enum ValuePool {
|
||||
|
@ -47,14 +57,45 @@ enum ValuePool {
|
|||
Orchard = 3;
|
||||
}
|
||||
|
||||
// The unique identifier and value for each proposed input.
|
||||
message ProposedInput {
|
||||
// A mapping from ZIP 321 payment index to the output pool that has been chosen
|
||||
// for that payment, based upon the payment address and the selected inputs to
|
||||
// the transaction.
|
||||
message PaymentOutputPool {
|
||||
uint32 paymentIndex = 1;
|
||||
ValuePool valuePool = 2;
|
||||
}
|
||||
|
||||
// The unique identifier and value for each proposed input that does not
|
||||
// require a back-reference to a prior step of the proposal.
|
||||
message ReceivedOutput {
|
||||
bytes txid = 1;
|
||||
ValuePool valuePool = 2;
|
||||
uint32 index = 3;
|
||||
uint64 value = 4;
|
||||
}
|
||||
|
||||
// A reference a payment in a prior step of the proposal. This payment must
|
||||
// belong to the wallet.
|
||||
message PriorStepOutput {
|
||||
uint32 stepIndex = 1;
|
||||
uint32 paymentIndex = 2;
|
||||
}
|
||||
|
||||
// A reference a change output from a prior step of the proposal.
|
||||
message PriorStepChange {
|
||||
uint32 stepIndex = 1;
|
||||
uint32 changeIndex = 2;
|
||||
}
|
||||
|
||||
// The unique identifier and value for an input to be used in the transaction.
|
||||
message ProposedInput {
|
||||
oneof value {
|
||||
ReceivedOutput receivedOutput = 1;
|
||||
PriorStepOutput priorStepOutput = 2;
|
||||
PriorStepChange priorStepChange = 3;
|
||||
}
|
||||
}
|
||||
|
||||
// The fee rule used in constructing a Proposal
|
||||
enum FeeRule {
|
||||
// Protobuf requires that enums have a zero discriminant as the default
|
||||
|
@ -72,15 +113,21 @@ enum FeeRule {
|
|||
|
||||
// The proposed change outputs and fee value.
|
||||
message TransactionBalance {
|
||||
// A list of change output values.
|
||||
repeated ChangeValue proposedChange = 1;
|
||||
// The fee to be paid by the proposed transaction, in zatoshis.
|
||||
uint64 feeRequired = 2;
|
||||
}
|
||||
|
||||
// A proposed change output. If the transparent value pool is selected,
|
||||
// the `memo` field must be null.
|
||||
message ChangeValue {
|
||||
// The value of a change output to be created, in zatoshis.
|
||||
uint64 value = 1;
|
||||
// The value pool in which the change output should be created.
|
||||
ValuePool valuePool = 2;
|
||||
// The optional memo that should be associated with the newly created change output.
|
||||
// Memos must not be present for transparent change outputs.
|
||||
MemoBytes memo = 3;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ use zcash_client_backend::{
|
|||
chain::{scan_cached_blocks, CommitmentTreeRoot, ScanSummary},
|
||||
scanning::{ScanPriority, ScanRange},
|
||||
wallet::{
|
||||
create_proposed_transaction, decrypt_and_store_transaction,
|
||||
create_proposed_transactions, decrypt_and_store_transaction,
|
||||
input_selection::GreedyInputSelector, propose_shielding, propose_transfer,
|
||||
},
|
||||
AccountBalance, AccountBirthday, InputSource, WalletCommitmentTrees, WalletRead,
|
||||
|
@ -524,10 +524,10 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getTransp
|
|||
|
||||
if let Some(taddr) = ua.0.transparent() {
|
||||
let taddr = match taddr {
|
||||
TransparentAddress::PublicKey(data) => {
|
||||
TransparentAddress::PublicKeyHash(data) => {
|
||||
ZcashAddress::from_transparent_p2pkh(network, *data)
|
||||
}
|
||||
TransparentAddress::Script(data) => {
|
||||
TransparentAddress::ScriptHash(data) => {
|
||||
ZcashAddress::from_transparent_p2sh(network, *data)
|
||||
}
|
||||
};
|
||||
|
@ -1145,7 +1145,7 @@ fn encode_account_balance<'a>(
|
|||
/// pending.
|
||||
fn encode_wallet_summary<'a>(
|
||||
env: &mut JNIEnv<'a>,
|
||||
summary: WalletSummary,
|
||||
summary: WalletSummary<AccountId>,
|
||||
) -> jni::errors::Result<JObject<'a>> {
|
||||
let account_balances = utils::rust_vec_to_java(
|
||||
env,
|
||||
|
@ -1397,7 +1397,7 @@ fn zip317_helper<DbT>(
|
|||
StandardFeeRule::PreZip313
|
||||
};
|
||||
GreedyInputSelector::new(
|
||||
SingleOutputChangeStrategy::new(fee_rule, change_memo),
|
||||
SingleOutputChangeStrategy::new(fee_rule, change_memo, ShieldedProtocol::Sapling),
|
||||
DustOutputPolicy::default(),
|
||||
)
|
||||
}
|
||||
|
@ -1463,13 +1463,13 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_proposeTr
|
|||
)
|
||||
.map_err(|e| format_err!("Error creating transaction proposal: {}", e))?;
|
||||
|
||||
utils::rust_bytes_to_java(
|
||||
Ok(utils::rust_bytes_to_java(
|
||||
&env,
|
||||
Proposal::from_standard_proposal(&network, &proposal)
|
||||
.encode_to_vec()
|
||||
.as_ref(),
|
||||
)
|
||||
.map(|arr| arr.into_raw())
|
||||
)?
|
||||
.into_raw())
|
||||
});
|
||||
unwrap_exc_or(&mut env, res, ptr::null_mut())
|
||||
}
|
||||
|
@ -1480,7 +1480,9 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_proposeSh
|
|||
_: JClass<'local>,
|
||||
db_data: JString<'local>,
|
||||
account: jint,
|
||||
shielding_threshold: jlong,
|
||||
memo: JByteArray<'local>,
|
||||
transparent_receiver: JString<'local>,
|
||||
network_id: jint,
|
||||
use_zip317_fees: jboolean,
|
||||
) -> jbyteArray {
|
||||
|
@ -1489,12 +1491,40 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_proposeSh
|
|||
let network = parse_network(network_id as u32)?;
|
||||
let mut db_data = wallet_db(env, network, db_data)?;
|
||||
let account = account_id_from_jint(account)?;
|
||||
let shielding_threshold = NonNegativeAmount::from_nonnegative_i64(shielding_threshold)
|
||||
.map_err(|()| format_err!("Invalid shielding threshold, out of range"))?;
|
||||
let memo_bytes = env.convert_byte_array(memo).unwrap();
|
||||
|
||||
let transparent_receiver =
|
||||
match utils::java_nullable_string_to_rust(env, &transparent_receiver) {
|
||||
None => Ok(None),
|
||||
Some(addr) => match Address::decode(&network, &addr) {
|
||||
None => Err(format_err!("Transparent receiver is for the wrong network")),
|
||||
Some(addr) => match addr {
|
||||
Address::Sapling(_) | Address::Unified(_) => Err(format_err!(
|
||||
"Transparent receiver is not a transparent address"
|
||||
)),
|
||||
Address::Transparent(addr) => {
|
||||
if db_data
|
||||
.get_transparent_receivers(account)?
|
||||
.contains_key(&addr)
|
||||
{
|
||||
Ok(Some(addr))
|
||||
} else {
|
||||
Err(format_err!(
|
||||
"Transparent receiver does not belong to account {}",
|
||||
u32::from(account),
|
||||
))
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}?;
|
||||
|
||||
let min_confirmations = 0;
|
||||
let min_confirmations_for_heights = NonZeroU32::new(1).unwrap();
|
||||
|
||||
let from_addrs: Vec<TransparentAddress> = db_data
|
||||
let account_receivers = db_data
|
||||
.get_target_and_anchor_heights(min_confirmations_for_heights)
|
||||
.map_err(|e| format_err!("Error while fetching anchor height: {}", e))
|
||||
.and_then(|opt_anchor| {
|
||||
|
@ -1512,16 +1542,28 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_proposeSh
|
|||
e
|
||||
)
|
||||
})
|
||||
})?
|
||||
.into_keys()
|
||||
.collect();
|
||||
})?;
|
||||
|
||||
let from_addrs = if let Some((addr, _)) = transparent_receiver.map_or_else(||
|
||||
if account_receivers.len() > 1 {
|
||||
Err(format_err!(
|
||||
"Account has more than one transparent receiver with funds to shield; this is not yet supported by the SDK. Provide a specific transparent receiver to shield funds from."
|
||||
))
|
||||
} else {
|
||||
Ok(account_receivers.iter().next().map(|(a, v)| (*a, *v)))
|
||||
},
|
||||
|addr| Ok(account_receivers.get(&addr).map(|value| (addr, *value)))
|
||||
)?.filter(|(_, value)| *value >= shielding_threshold.into()) {
|
||||
[addr]
|
||||
} else {
|
||||
// There are no transparent funds to shield; don't create a proposal.
|
||||
return Ok(ptr::null_mut());
|
||||
};
|
||||
|
||||
let memo = Memo::from_bytes(&memo_bytes).unwrap();
|
||||
|
||||
let input_selector = zip317_helper(Some(MemoBytes::from(&memo)), use_zip317_fees);
|
||||
|
||||
let shielding_threshold = NonNegativeAmount::from_u64(100000).unwrap();
|
||||
|
||||
let proposal = propose_shielding::<_, _, _, Infallible>(
|
||||
&mut db_data,
|
||||
&network,
|
||||
|
@ -1532,19 +1574,19 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_proposeSh
|
|||
)
|
||||
.map_err(|e| format_err!("Error while shielding transaction: {}", e))?;
|
||||
|
||||
utils::rust_bytes_to_java(
|
||||
Ok(utils::rust_bytes_to_java(
|
||||
&env,
|
||||
Proposal::from_standard_proposal(&network, &proposal)
|
||||
.encode_to_vec()
|
||||
.as_ref(),
|
||||
)
|
||||
.map(|arr| arr.into_raw())
|
||||
)?
|
||||
.into_raw())
|
||||
});
|
||||
unwrap_exc_or(&mut env, res, ptr::null_mut())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_createProposedTransaction<
|
||||
pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_createProposedTransactions<
|
||||
'local,
|
||||
>(
|
||||
mut env: JNIEnv<'local>,
|
||||
|
@ -1555,7 +1597,7 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_createPro
|
|||
spend_params: JString<'local>,
|
||||
output_params: JString<'local>,
|
||||
network_id: jint,
|
||||
) -> jbyteArray {
|
||||
) -> jobjectArray {
|
||||
let res = catch_unwind(&mut env, |env| {
|
||||
let _span = tracing::info_span!("RustBackend.createProposedTransaction").entered();
|
||||
let network = parse_network(network_id as u32)?;
|
||||
|
@ -1570,7 +1612,7 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_createPro
|
|||
.map_err(|e| format_err!("Invalid proposal: {}", e))?
|
||||
.try_into_standard_proposal(&network, &db_data)?;
|
||||
|
||||
let txid = create_proposed_transaction::<_, _, Infallible, _, _>(
|
||||
let txids = create_proposed_transactions::<_, _, Infallible, _, _>(
|
||||
&mut db_data,
|
||||
&network,
|
||||
&prover,
|
||||
|
@ -1579,9 +1621,16 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_createPro
|
|||
OvkPolicy::Sender,
|
||||
&proposal,
|
||||
)
|
||||
.map_err(|e| format_err!("Error while creating transaction: {}", e))?;
|
||||
.map_err(|e| format_err!("Error while creating transactions: {}", e))?;
|
||||
|
||||
utils::rust_bytes_to_java(&env, txid.as_ref()).map(|arr| arr.into_raw())
|
||||
Ok(utils::rust_vec_to_java(
|
||||
env,
|
||||
txids.into(),
|
||||
"[B",
|
||||
|env, txid| utils::rust_bytes_to_java(env, txid.as_ref()),
|
||||
|env| env.new_byte_array(32),
|
||||
)?
|
||||
.into_raw())
|
||||
});
|
||||
unwrap_exc_or(&mut env, res, ptr::null_mut())
|
||||
}
|
||||
|
@ -1657,10 +1706,10 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_listTrans
|
|||
.iter()
|
||||
.map(|(taddr, _)| {
|
||||
let taddr = match taddr {
|
||||
TransparentAddress::PublicKey(data) => {
|
||||
TransparentAddress::PublicKeyHash(data) => {
|
||||
ZcashAddress::from_transparent_p2pkh(zcash_network, *data)
|
||||
}
|
||||
TransparentAddress::Script(data) => {
|
||||
TransparentAddress::ScriptHash(data) => {
|
||||
ZcashAddress::from_transparent_p2sh(zcash_network, *data)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -38,10 +38,11 @@ pub(crate) fn java_string_to_rust(env: &mut JNIEnv, jstring: &JString) -> String
|
|||
.into()
|
||||
}
|
||||
|
||||
pub(crate) fn rust_bytes_to_java<'a>(
|
||||
env: &JNIEnv<'a>,
|
||||
data: &[u8],
|
||||
) -> Result<JByteArray<'a>, failure::Error> {
|
||||
pub(crate) fn java_nullable_string_to_rust(env: &mut JNIEnv, jstring: &JString) -> Option<String> {
|
||||
(!jstring.is_null()).then(|| java_string_to_rust(env, jstring))
|
||||
}
|
||||
|
||||
pub(crate) fn rust_bytes_to_java<'a>(env: &JNIEnv<'a>, data: &[u8]) -> JNIResult<JByteArray<'a>> {
|
||||
// SAFETY: jbyte (i8) has the same size and alignment as u8, and a well-defined
|
||||
// twos-complement representation with no "trap representations".
|
||||
let buf = unsafe { slice::from_raw_parts(data.as_ptr().cast(), data.len()) };
|
||||
|
|
|
@ -105,7 +105,15 @@ class TestWallet(
|
|||
memo: String = "",
|
||||
amount: Zatoshi = Zatoshi(500L)
|
||||
): TestWallet {
|
||||
synchronizer.sendToAddress(shieldedSpendingKey, amount, address, memo)
|
||||
synchronizer.createProposedTransactions(
|
||||
synchronizer.proposeTransfer(
|
||||
shieldedSpendingKey.account,
|
||||
address,
|
||||
amount,
|
||||
memo
|
||||
),
|
||||
shieldedSpendingKey
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -121,7 +129,12 @@ class TestWallet(
|
|||
|
||||
synchronizer.getTransparentBalance(transparentAddress).let { walletBalance ->
|
||||
if (walletBalance.value > 0L) {
|
||||
synchronizer.shieldFunds(shieldedSpendingKey)
|
||||
synchronizer.proposeShielding(shieldedSpendingKey.account, Zatoshi(100000))?.let {
|
||||
synchronizer.createProposedTransactions(
|
||||
it,
|
||||
shieldedSpendingKey
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -189,7 +189,15 @@ class SampleCodeTest {
|
|||
ZcashNetwork.Mainnet,
|
||||
Account.DEFAULT
|
||||
)
|
||||
synchronizer.sendToAddress(spendingKey, amount, address, memo)
|
||||
synchronizer.createProposedTransactions(
|
||||
synchronizer.proposeTransfer(
|
||||
spendingKey.account,
|
||||
address,
|
||||
amount,
|
||||
memo
|
||||
),
|
||||
spendingKey
|
||||
)
|
||||
}
|
||||
|
||||
// /////////////////////////////////////////////////////
|
||||
|
|
|
@ -47,6 +47,7 @@ class GetBalanceFragment : BaseDemoFragment<FragmentGetBalanceBinding>() {
|
|||
reportTraceEvent(SyncBlockchainBenchmarkTrace.Event.BALANCE_SCREEN_END)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
override fun onViewCreated(
|
||||
view: View,
|
||||
savedInstanceState: Bundle?
|
||||
|
@ -60,16 +61,23 @@ class GetBalanceFragment : BaseDemoFragment<FragmentGetBalanceBinding>() {
|
|||
binding.shield.apply {
|
||||
setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
sharedViewModel.synchronizerFlow.value?.shieldFunds(
|
||||
val usk =
|
||||
DerivationTool.getInstance().deriveUnifiedSpendingKey(
|
||||
seed,
|
||||
network,
|
||||
Account.DEFAULT
|
||||
)
|
||||
sharedViewModel.synchronizerFlow.value?.let { synchronizer ->
|
||||
synchronizer.proposeShielding(usk.account, Zatoshi(100000))?.let { it1 ->
|
||||
synchronizer.createProposedTransactions(
|
||||
it1,
|
||||
usk
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
monitorChanges()
|
||||
}
|
||||
|
|
|
@ -145,13 +145,18 @@ class SendFragment : BaseDemoFragment<FragmentSendBinding>() {
|
|||
val amount = amountInput.text.toString().toDouble().convertZecToZatoshi()
|
||||
val toAddress = addressInput.text.toString().trim()
|
||||
lifecycleScope.launch {
|
||||
sharedViewModel.synchronizerFlow.value?.sendToAddress(
|
||||
spendingKey,
|
||||
amount,
|
||||
sharedViewModel.synchronizerFlow.value?.let { synchronizer ->
|
||||
synchronizer.createProposedTransactions(
|
||||
synchronizer.proposeTransfer(
|
||||
spendingKey.account,
|
||||
toAddress,
|
||||
amount,
|
||||
"Funds from Demo App"
|
||||
),
|
||||
spendingKey
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
mainActivity()?.hideKeyboard()
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import cash.z.ecc.android.sdk.model.Account
|
|||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||
import cash.z.ecc.android.sdk.model.PersistableWallet
|
||||
import cash.z.ecc.android.sdk.model.TransactionSubmitResult
|
||||
import cash.z.ecc.android.sdk.model.WalletAddresses
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
|
@ -47,6 +48,7 @@ import kotlinx.coroutines.flow.flatMapLatest
|
|||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
@ -202,7 +204,7 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||
viewModelScope.launch {
|
||||
val spendingKey = spendingKey.filterNotNull().first()
|
||||
runCatching { synchronizer.send(spendingKey, zecSend) }
|
||||
.onSuccess { mutableSendState.value = SendState.Sent(it) }
|
||||
.onSuccess { mutableSendState.value = SendState.Sent(it.toList()) }
|
||||
.onFailure { mutableSendState.value = SendState.Error(it) }
|
||||
}
|
||||
} else {
|
||||
|
@ -215,6 +217,7 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||
*
|
||||
* Observe the result via [sendState].
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
fun shieldFunds() {
|
||||
if (sendState.value is SendState.Sending) {
|
||||
return
|
||||
|
@ -226,8 +229,15 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||
if (null != synchronizer) {
|
||||
viewModelScope.launch {
|
||||
val spendingKey = spendingKey.filterNotNull().first()
|
||||
kotlin.runCatching { synchronizer.shieldFunds(spendingKey) }
|
||||
.onSuccess { mutableSendState.value = SendState.Sent(it) }
|
||||
kotlin.runCatching {
|
||||
synchronizer.proposeShielding(spendingKey.account, Zatoshi(100000))?.let {
|
||||
synchronizer.createProposedTransactions(
|
||||
it,
|
||||
spendingKey
|
||||
)
|
||||
}
|
||||
}
|
||||
.onSuccess { it?.let { mutableSendState.value = SendState.Sent(it.toList()) } }
|
||||
.onFailure { mutableSendState.value = SendState.Error(it) }
|
||||
}
|
||||
} else {
|
||||
|
@ -302,7 +312,7 @@ sealed class SendState {
|
|||
override fun toString(): String = "Sending"
|
||||
}
|
||||
|
||||
class Sent(val localTxId: Long) : SendState() {
|
||||
class Sent(val txIds: List<TransactionSubmitResult>) : SendState() {
|
||||
override fun toString(): String = "Sent"
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ ZCASH_ASCII_GPG_KEY=
|
|||
# Configures whether release is an unstable snapshot, therefore published to the snapshot repository.
|
||||
IS_SNAPSHOT=true
|
||||
|
||||
LIBRARY_VERSION=2.0.6
|
||||
LIBRARY_VERSION=2.0.7
|
||||
|
||||
# Kotlin compiler warnings can be considered errors, failing the build.
|
||||
ZCASH_IS_TREAT_WARNINGS_AS_ERRORS=true
|
||||
|
|
|
@ -9,9 +9,12 @@ data class ZecSend(val destination: WalletAddress, val amount: Zatoshi, val memo
|
|||
suspend fun Synchronizer.send(
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
send: ZecSend
|
||||
) = sendToAddress(
|
||||
spendingKey,
|
||||
send.amount,
|
||||
) = createProposedTransactions(
|
||||
proposeTransfer(
|
||||
spendingKey.account,
|
||||
send.destination.address,
|
||||
send.amount,
|
||||
send.memo.value
|
||||
),
|
||||
spendingKey
|
||||
)
|
||||
|
|
|
@ -112,11 +112,14 @@ class TestnetIntegrationTest : ScopedTest() {
|
|||
Account.DEFAULT
|
||||
)
|
||||
log("sending to address")
|
||||
synchronizer.sendToAddress(
|
||||
spendingKey,
|
||||
ZcashSdk.MINERS_FEE,
|
||||
synchronizer.createProposedTransactions(
|
||||
synchronizer.proposeTransfer(
|
||||
spendingKey.account,
|
||||
toAddress,
|
||||
ZcashSdk.MINERS_FEE,
|
||||
"first mainnet tx from the SDK"
|
||||
),
|
||||
spendingKey
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -106,7 +106,15 @@ class TestWallet(
|
|||
memo: String = "",
|
||||
amount: Zatoshi = Zatoshi(500L)
|
||||
): TestWallet {
|
||||
synchronizer.sendToAddress(spendingKey, amount, address, memo)
|
||||
synchronizer.createProposedTransactions(
|
||||
synchronizer.proposeTransfer(
|
||||
spendingKey.account,
|
||||
address,
|
||||
amount,
|
||||
memo
|
||||
),
|
||||
spendingKey
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -124,7 +132,12 @@ class TestWallet(
|
|||
Twig.debug { "FOUND utxo balance of total: $walletBalance" }
|
||||
|
||||
if (walletBalance.value > 0L) {
|
||||
synchronizer.shieldFunds(spendingKey)
|
||||
synchronizer.proposeShielding(spendingKey.account, Zatoshi(100000))?.let {
|
||||
synchronizer.createProposedTransactions(
|
||||
it,
|
||||
spendingKey
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -88,15 +88,17 @@ internal class FakeRustBackend(
|
|||
|
||||
override suspend fun proposeShielding(
|
||||
account: Int,
|
||||
memo: ByteArray?
|
||||
): ProposalUnsafe {
|
||||
shieldingThreshold: Long,
|
||||
memo: ByteArray?,
|
||||
transparentReceiver: String?
|
||||
): ProposalUnsafe? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun createProposedTransaction(
|
||||
override suspend fun createProposedTransactions(
|
||||
proposal: ProposalUnsafe,
|
||||
unifiedSpendingKey: ByteArray
|
||||
): ByteArray {
|
||||
): List<ByteArray> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
|
|
|
@ -42,8 +42,10 @@ import cash.z.ecc.android.sdk.internal.transaction.TransactionEncoderImpl
|
|||
import cash.z.ecc.android.sdk.model.Account
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||
import cash.z.ecc.android.sdk.model.Proposal
|
||||
import cash.z.ecc.android.sdk.model.TransactionOverview
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.model.TransactionSubmitResult
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
|
@ -66,6 +68,7 @@ import kotlinx.coroutines.cancel
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
|
@ -405,6 +408,7 @@ class SdkSynchronizer private constructor(
|
|||
lastScanTime = now
|
||||
SYNCED
|
||||
}
|
||||
|
||||
is Stopped -> STOPPED
|
||||
is Disconnected -> DISCONNECTED
|
||||
is Syncing, Initialized -> SYNCING
|
||||
|
@ -555,6 +559,58 @@ class SdkSynchronizer private constructor(
|
|||
account
|
||||
)
|
||||
|
||||
@Throws(TransactionEncoderException::class)
|
||||
override suspend fun proposeTransfer(
|
||||
account: Account,
|
||||
recipient: String,
|
||||
amount: Zatoshi,
|
||||
memo: String
|
||||
): Proposal = txManager.proposeTransfer(account, recipient, amount, memo)
|
||||
|
||||
@Throws(TransactionEncoderException::class)
|
||||
override suspend fun proposeShielding(
|
||||
account: Account,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: String,
|
||||
transparentReceiver: String?
|
||||
): Proposal? = txManager.proposeShielding(account, shieldingThreshold, memo, transparentReceiver)
|
||||
|
||||
@Throws(TransactionEncoderException::class)
|
||||
override suspend fun createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
usk: UnifiedSpendingKey
|
||||
): Flow<TransactionSubmitResult> {
|
||||
// Internally, this logic submits and checks every incoming transaction, and once [Failure] or
|
||||
// [NotAttempted] submission result occurs, it returns [NotAttempted] for the rest of them
|
||||
var anySubmissionFailed = false
|
||||
return txManager.createProposedTransactions(proposal, usk)
|
||||
.asFlow()
|
||||
.map { transaction ->
|
||||
if (anySubmissionFailed) {
|
||||
TransactionSubmitResult.NotAttempted(transaction.txId)
|
||||
} else {
|
||||
val submission = txManager.submit(transaction)
|
||||
when (submission) {
|
||||
is TransactionSubmitResult.Success -> {
|
||||
// Expected state
|
||||
}
|
||||
is TransactionSubmitResult.Failure,
|
||||
is TransactionSubmitResult.NotAttempted -> {
|
||||
anySubmissionFailed = true
|
||||
}
|
||||
}
|
||||
submission
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
message = "Upcoming SDK 2.1 will create multiple transactions at once for some recipients.",
|
||||
replaceWith =
|
||||
ReplaceWith(
|
||||
"createProposedTransactions(proposeTransfer(usk.account, toAddress, amount, memo), usk)"
|
||||
)
|
||||
)
|
||||
@Throws(TransactionEncoderException::class, TransactionSubmitException::class)
|
||||
override suspend fun sendToAddress(
|
||||
usk: UnifiedSpendingKey,
|
||||
|
@ -571,13 +627,23 @@ class SdkSynchronizer private constructor(
|
|||
usk.account
|
||||
)
|
||||
|
||||
if (txManager.submit(encodedTx)) {
|
||||
when (txManager.submit(encodedTx)) {
|
||||
is TransactionSubmitResult.Success -> {
|
||||
return storage.findMatchingTransactionId(encodedTx.txId.byteArray)!!
|
||||
} else {
|
||||
}
|
||||
else -> {
|
||||
throw TransactionSubmitException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
message = "Upcoming SDK 2.1 will create multiple transactions at once for some recipients.",
|
||||
replaceWith =
|
||||
ReplaceWith(
|
||||
"proposeShielding(usk.account, shieldingThreshold, memo)?.let { createProposedTransactions(it, usk) }"
|
||||
)
|
||||
)
|
||||
@Throws(TransactionEncoderException::class, TransactionSubmitException::class)
|
||||
override suspend fun shieldFunds(
|
||||
usk: UnifiedSpendingKey,
|
||||
|
@ -596,12 +662,15 @@ class SdkSynchronizer private constructor(
|
|||
usk.account
|
||||
)
|
||||
|
||||
if (txManager.submit(encodedTx)) {
|
||||
when (txManager.submit(encodedTx)) {
|
||||
is TransactionSubmitResult.Success -> {
|
||||
return storage.findMatchingTransactionId(encodedTx.txId.byteArray)!!
|
||||
} else {
|
||||
}
|
||||
else -> {
|
||||
throw TransactionSubmitException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun refreshUtxos(
|
||||
account: Account,
|
||||
|
|
|
@ -15,8 +15,10 @@ import cash.z.ecc.android.sdk.internal.model.ext.toBlockHeight
|
|||
import cash.z.ecc.android.sdk.model.Account
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||
import cash.z.ecc.android.sdk.model.Proposal
|
||||
import cash.z.ecc.android.sdk.model.TransactionOverview
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.model.TransactionSubmitResult
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
|
@ -167,6 +169,64 @@ interface Synchronizer {
|
|||
*/
|
||||
suspend fun getTransparentAddress(account: Account): String
|
||||
|
||||
/**
|
||||
* Creates a proposal for transferring funds to the given recipient.
|
||||
*
|
||||
* @param account the account from which to transfer funds.
|
||||
* @param recipient the recipient's address.
|
||||
* @param amount the amount of zatoshi to send.
|
||||
* @param memo the optional memo to include as part of the proposal's transactions.
|
||||
*
|
||||
* @return the proposal or an exception
|
||||
*/
|
||||
suspend fun proposeTransfer(
|
||||
account: Account,
|
||||
recipient: String,
|
||||
amount: Zatoshi,
|
||||
memo: String = ""
|
||||
): Proposal
|
||||
|
||||
/**
|
||||
* Creates a proposal for shielding any transparent funds received by the given account.
|
||||
*
|
||||
* @param account the account for which to shield funds.
|
||||
* @param shieldingThreshold the minimum transparent balance required before a
|
||||
* proposal will be created.
|
||||
* @param memo the optional memo to include as part of the proposal's transactions.
|
||||
* @param transparentReceiver a specific transparent receiver within the account that
|
||||
* should be the source of transparent funds. Default is
|
||||
* null which will select whichever of the account's
|
||||
* transparent receivers has funds to shield.
|
||||
*
|
||||
* @return the proposal, or null if the transparent balance that would be shielded is
|
||||
* zero or below `shieldingThreshold`.
|
||||
*
|
||||
* @throws Exception if `transparentReceiver` is null and there are transparent funds
|
||||
* in more than one of the account's transparent receivers.
|
||||
*/
|
||||
suspend fun proposeShielding(
|
||||
account: Account,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: String = ZcashSdk.DEFAULT_SHIELD_FUNDS_MEMO_PREFIX,
|
||||
transparentReceiver: String? = null
|
||||
): Proposal?
|
||||
|
||||
/**
|
||||
* Creates the transactions in the given proposal.
|
||||
*
|
||||
* @param proposal the proposal for which to create transactions.
|
||||
* @param usk the unified spending key associated with the account for which the
|
||||
* proposal was created.
|
||||
*
|
||||
* @return a flow of result objects for the transactions that were created as part of
|
||||
* the proposal, indicating whether they were submitted to the network or if
|
||||
* an error occurred.
|
||||
*/
|
||||
suspend fun createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
usk: UnifiedSpendingKey
|
||||
): Flow<TransactionSubmitResult>
|
||||
|
||||
/**
|
||||
* Sends zatoshi.
|
||||
*
|
||||
|
@ -180,6 +240,13 @@ interface Synchronizer {
|
|||
* useful for updating the UI without needing to poll. Of course, polling is always an option
|
||||
* for any wallet that wants to ignore this return value.
|
||||
*/
|
||||
@Deprecated(
|
||||
message = "Upcoming SDK 2.1 will create multiple transactions at once for some recipients.",
|
||||
replaceWith =
|
||||
ReplaceWith(
|
||||
"createProposedTransactions(proposeTransfer(usk.account, toAddress, amount, memo), usk)"
|
||||
)
|
||||
)
|
||||
suspend fun sendToAddress(
|
||||
usk: UnifiedSpendingKey,
|
||||
amount: Zatoshi,
|
||||
|
@ -187,6 +254,13 @@ interface Synchronizer {
|
|||
memo: String = ""
|
||||
): Long
|
||||
|
||||
@Deprecated(
|
||||
message = "Upcoming SDK 2.1 will create multiple transactions at once for some recipients.",
|
||||
replaceWith =
|
||||
ReplaceWith(
|
||||
"proposeShielding(usk.account, shieldingThreshold, memo)?.let { createProposedTransactions(it, usk) }"
|
||||
)
|
||||
)
|
||||
suspend fun shieldFunds(
|
||||
usk: UnifiedSpendingKey,
|
||||
memo: String = ZcashSdk.DEFAULT_SHIELD_FUNDS_MEMO_PREFIX
|
||||
|
|
|
@ -26,21 +26,23 @@ internal interface TypesafeBackend {
|
|||
|
||||
@Suppress("LongParameterList")
|
||||
suspend fun proposeTransfer(
|
||||
usk: UnifiedSpendingKey,
|
||||
account: Account,
|
||||
to: String,
|
||||
value: Long,
|
||||
memo: ByteArray? = byteArrayOf()
|
||||
): Proposal
|
||||
|
||||
suspend fun proposeShielding(
|
||||
usk: UnifiedSpendingKey,
|
||||
memo: ByteArray? = byteArrayOf()
|
||||
): Proposal
|
||||
account: Account,
|
||||
shieldingThreshold: Long,
|
||||
memo: ByteArray? = byteArrayOf(),
|
||||
transparentReceiver: String? = null
|
||||
): Proposal?
|
||||
|
||||
suspend fun createProposedTransaction(
|
||||
suspend fun createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
usk: UnifiedSpendingKey
|
||||
): FirstClassByteArray
|
||||
): List<FirstClassByteArray>
|
||||
|
||||
suspend fun getCurrentAddress(account: Account): String
|
||||
|
||||
|
|
|
@ -37,14 +37,14 @@ internal class TypesafeBackendImpl(private val backend: Backend) : TypesafeBacke
|
|||
|
||||
@Suppress("LongParameterList")
|
||||
override suspend fun proposeTransfer(
|
||||
usk: UnifiedSpendingKey,
|
||||
account: Account,
|
||||
to: String,
|
||||
value: Long,
|
||||
memo: ByteArray?
|
||||
): Proposal =
|
||||
Proposal.fromUnsafe(
|
||||
backend.proposeTransfer(
|
||||
usk.account.value,
|
||||
account.value,
|
||||
to,
|
||||
value,
|
||||
memo
|
||||
|
@ -52,26 +52,30 @@ internal class TypesafeBackendImpl(private val backend: Backend) : TypesafeBacke
|
|||
)
|
||||
|
||||
override suspend fun proposeShielding(
|
||||
usk: UnifiedSpendingKey,
|
||||
memo: ByteArray?
|
||||
): Proposal =
|
||||
Proposal.fromUnsafe(
|
||||
account: Account,
|
||||
shieldingThreshold: Long,
|
||||
memo: ByteArray?,
|
||||
transparentReceiver: String?
|
||||
): Proposal? =
|
||||
backend.proposeShielding(
|
||||
usk.account.value,
|
||||
memo
|
||||
)
|
||||
account.value,
|
||||
shieldingThreshold,
|
||||
memo,
|
||||
transparentReceiver
|
||||
)?.let {
|
||||
Proposal.fromUnsafe(
|
||||
it
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun createProposedTransaction(
|
||||
override suspend fun createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
usk: UnifiedSpendingKey
|
||||
): FirstClassByteArray =
|
||||
FirstClassByteArray(
|
||||
backend.createProposedTransaction(
|
||||
): List<FirstClassByteArray> =
|
||||
backend.createProposedTransactions(
|
||||
proposal.toUnsafe(),
|
||||
usk.copyBytes()
|
||||
)
|
||||
)
|
||||
).map { FirstClassByteArray(it) }
|
||||
|
||||
override suspend fun getCurrentAddress(account: Account): String {
|
||||
return backend.getCurrentAddress(account.value)
|
||||
|
|
|
@ -2,7 +2,9 @@ package cash.z.ecc.android.sdk.internal.transaction
|
|||
|
||||
import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
|
||||
import cash.z.ecc.android.sdk.model.Account
|
||||
import cash.z.ecc.android.sdk.model.Proposal
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.model.TransactionSubmitResult
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
|
||||
|
@ -33,6 +35,62 @@ internal interface OutboundTransactionManager {
|
|||
account: Account
|
||||
): EncodedTransaction
|
||||
|
||||
/**
|
||||
* Creates a proposal for transferring funds to the given recipient.
|
||||
*
|
||||
* @param account the account from which to transfer funds.
|
||||
* @param recipient the recipient's address.
|
||||
* @param amount the amount of zatoshi to send.
|
||||
* @param memo the optional memo to include as part of the proposal's transactions.
|
||||
*
|
||||
* @return the proposal or an exception
|
||||
*/
|
||||
suspend fun proposeTransfer(
|
||||
account: Account,
|
||||
recipient: String,
|
||||
amount: Zatoshi,
|
||||
memo: String
|
||||
): Proposal
|
||||
|
||||
/**
|
||||
* Creates a proposal for shielding any transparent funds received by the given account.
|
||||
*
|
||||
* @param account the account for which to shield funds.
|
||||
* @param shieldingThreshold the minimum transparent balance required before a
|
||||
* proposal will be created.
|
||||
* @param memo the optional memo to include as part of the proposal's transactions.
|
||||
* @param transparentReceiver a specific transparent receiver within the account that
|
||||
* should be the source of transparent funds. Default is
|
||||
* null which will select whichever of the account's
|
||||
* transparent receivers has funds to shield.
|
||||
*
|
||||
* @return the proposal, or null if the transparent balance that would be shielded is
|
||||
* zero or below `shieldingThreshold`.
|
||||
*
|
||||
* @throws Exception if `transparentReceiver` is null and there are transparent funds
|
||||
* in more than one of the account's transparent receivers.
|
||||
*/
|
||||
suspend fun proposeShielding(
|
||||
account: Account,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: String,
|
||||
transparentReceiver: String?
|
||||
): Proposal?
|
||||
|
||||
/**
|
||||
* Creates the transactions in the given proposal.
|
||||
*
|
||||
* @param proposal the proposal for which to create transactions.
|
||||
* @param usk the unified spending key associated with the account for which the
|
||||
* proposal was created.
|
||||
*
|
||||
* @return the successfully encoded transactions or an exception
|
||||
*/
|
||||
suspend fun createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
usk: UnifiedSpendingKey
|
||||
): List<EncodedTransaction>
|
||||
|
||||
/**
|
||||
* Submits the transaction represented by [encodedTransaction] to lightwalletd to broadcast to the
|
||||
* network and, hopefully, include in the next block.
|
||||
|
@ -41,7 +99,7 @@ internal interface OutboundTransactionManager {
|
|||
* to lightwalletd.
|
||||
* @return true if the transaction was successfully submitted to lightwalletd.
|
||||
*/
|
||||
suspend fun submit(encodedTransaction: EncodedTransaction): Boolean
|
||||
suspend fun submit(encodedTransaction: EncodedTransaction): TransactionSubmitResult
|
||||
|
||||
/**
|
||||
* Return true when the given address is a valid t-addr.
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package cash.z.ecc.android.sdk.internal.transaction
|
||||
|
||||
import cash.z.ecc.android.sdk.internal.Twig
|
||||
import cash.z.ecc.android.sdk.internal.ext.toHexReversed
|
||||
import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
|
||||
import cash.z.ecc.android.sdk.model.Account
|
||||
import cash.z.ecc.android.sdk.model.Proposal
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.model.TransactionSubmitResult
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import co.electriccoin.lightwallet.client.LightWalletClient
|
||||
|
@ -40,20 +43,60 @@ internal class OutboundTransactionManagerImpl(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun submit(encodedTransaction: EncodedTransaction): Boolean {
|
||||
override suspend fun proposeTransfer(
|
||||
account: Account,
|
||||
recipient: String,
|
||||
amount: Zatoshi,
|
||||
memo: String
|
||||
): Proposal = encoder.proposeTransfer(account, recipient, amount, memo.toByteArray())
|
||||
|
||||
override suspend fun proposeShielding(
|
||||
account: Account,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: String,
|
||||
transparentReceiver: String?
|
||||
): Proposal? = encoder.proposeShielding(account, shieldingThreshold, memo.toByteArray(), transparentReceiver)
|
||||
|
||||
override suspend fun createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
usk: UnifiedSpendingKey
|
||||
): List<EncodedTransaction> = encoder.createProposedTransactions(proposal, usk)
|
||||
|
||||
override suspend fun submit(encodedTransaction: EncodedTransaction): TransactionSubmitResult {
|
||||
return when (val response = service.submitTransaction(encodedTransaction.raw.byteArray)) {
|
||||
is Response.Success -> {
|
||||
Twig.debug { "SUCCESS: submit transaction completed with response: ${response.result}" }
|
||||
true
|
||||
if (response.result.code == 0) {
|
||||
Twig.info {
|
||||
"SUCCESS: submit transaction completed for:" +
|
||||
" ${encodedTransaction.txId.byteArray.toHexReversed()}"
|
||||
}
|
||||
TransactionSubmitResult.Success(encodedTransaction.txId)
|
||||
} else {
|
||||
Twig.error {
|
||||
"FAILURE! submit transaction ${encodedTransaction.txId.byteArray.toHexReversed()} " +
|
||||
"completed with response: ${response.result.code}: ${response.result.message}"
|
||||
}
|
||||
TransactionSubmitResult.Failure(
|
||||
encodedTransaction.txId,
|
||||
false,
|
||||
response.result.code,
|
||||
response.result.message
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is Response.Failure -> {
|
||||
Twig.debug {
|
||||
"FAILURE! submit transaction completed with response: ${response.code}: ${
|
||||
Twig.error {
|
||||
"FAILURE! submit transaction failed with gRPC response: ${response.code}: ${
|
||||
response.description
|
||||
}"
|
||||
}
|
||||
false
|
||||
TransactionSubmitResult.Failure(
|
||||
encodedTransaction.txId,
|
||||
true,
|
||||
response.code,
|
||||
response.description
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package cash.z.ecc.android.sdk.internal.transaction
|
||||
|
||||
import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
|
||||
import cash.z.ecc.android.sdk.model.Account
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.Proposal
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
|
@ -38,6 +40,61 @@ internal interface TransactionEncoder {
|
|||
memo: ByteArray? = byteArrayOf()
|
||||
): EncodedTransaction
|
||||
|
||||
/**
|
||||
* Creates a proposal for transferring funds to the given recipient.
|
||||
*
|
||||
* @param account the account from which to transfer funds.
|
||||
* @param recipient the recipient's address.
|
||||
* @param amount the amount of zatoshi to send.
|
||||
* @param memo the optional memo to include as part of the proposal's transactions.
|
||||
*
|
||||
* @return the proposal or an exception
|
||||
*/
|
||||
suspend fun proposeTransfer(
|
||||
account: Account,
|
||||
recipient: String,
|
||||
amount: Zatoshi,
|
||||
memo: ByteArray? = byteArrayOf()
|
||||
): Proposal
|
||||
|
||||
/**
|
||||
* Creates a proposal for shielding any transparent funds sent to the given account.
|
||||
*
|
||||
* @param account the account for which to shield funds.
|
||||
* @param shieldingThreshold the minimum transparent balance required before a
|
||||
* proposal will be created.
|
||||
* @param memo the optional memo to include as part of the proposal's transactions.
|
||||
* @param transparentReceiver a specific transparent receiver within the account that
|
||||
* should be the source of transparent funds. Default is
|
||||
* null which will select whichever of the account's
|
||||
* transparent receivers has funds to shield.
|
||||
*
|
||||
* @return the proposal, or null if the transparent balance that would be shielded is
|
||||
* zero or below `shieldingThreshold`.
|
||||
*
|
||||
* @throws Exception if `transparentReceiver` is null and there are transparent funds
|
||||
* in more than one of the account's transparent receivers.
|
||||
*/
|
||||
suspend fun proposeShielding(
|
||||
account: Account,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: ByteArray? = byteArrayOf(),
|
||||
transparentReceiver: String? = null
|
||||
): Proposal?
|
||||
|
||||
/**
|
||||
* Creates the transactions in the given proposal.
|
||||
*
|
||||
* @param proposal the proposal to create.
|
||||
* @param usk the unified spending key associated with the notes that will be spent.
|
||||
*
|
||||
* @return the successfully encoded transactions or an exception
|
||||
*/
|
||||
suspend fun createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
usk: UnifiedSpendingKey
|
||||
): List<EncodedTransaction>
|
||||
|
||||
/**
|
||||
* Utility function to help with validation. This is not called during [createTransaction]
|
||||
* because this class asserts that all validation is done externally by the UI, for now.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package cash.z.ecc.android.sdk.internal.transaction
|
||||
|
||||
import cash.z.ecc.android.sdk.exception.SdkException
|
||||
import cash.z.ecc.android.sdk.exception.TransactionEncoderException
|
||||
import cash.z.ecc.android.sdk.ext.masked
|
||||
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
||||
|
@ -7,8 +8,10 @@ import cash.z.ecc.android.sdk.internal.Twig
|
|||
import cash.z.ecc.android.sdk.internal.TypesafeBackend
|
||||
import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
|
||||
import cash.z.ecc.android.sdk.internal.repository.DerivedDataRepository
|
||||
import cash.z.ecc.android.sdk.model.Account
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.FirstClassByteArray
|
||||
import cash.z.ecc.android.sdk.model.Proposal
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
|
@ -22,6 +25,7 @@ import cash.z.ecc.android.sdk.model.Zatoshi
|
|||
* @property repository the repository that stores information about the transactions being created
|
||||
* such as the raw bytes and raw txId.
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
internal class TransactionEncoderImpl(
|
||||
private val backend: TypesafeBackend,
|
||||
private val saplingParamTool: SaplingParamTool,
|
||||
|
@ -64,6 +68,77 @@ internal class TransactionEncoderImpl(
|
|||
?: throw TransactionEncoderException.TransactionNotFoundException(transactionId)
|
||||
}
|
||||
|
||||
override suspend fun proposeTransfer(
|
||||
account: Account,
|
||||
recipient: String,
|
||||
amount: Zatoshi,
|
||||
memo: ByteArray?
|
||||
): Proposal {
|
||||
Twig.debug {
|
||||
"creating proposal to spend $amount zatoshi to" +
|
||||
" ${recipient.masked()} with memo: ${memo?.decodeToString()}"
|
||||
}
|
||||
|
||||
return runCatching {
|
||||
backend.proposeTransfer(
|
||||
account,
|
||||
recipient,
|
||||
amount.value,
|
||||
memo
|
||||
)
|
||||
}.onFailure {
|
||||
Twig.error(it) { "Caught exception while creating proposal." }
|
||||
}.onSuccess { result ->
|
||||
Twig.debug { "result of proposeTransfer: $result" }
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
override suspend fun proposeShielding(
|
||||
account: Account,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: ByteArray?,
|
||||
transparentReceiver: String?
|
||||
): Proposal? {
|
||||
return runCatching {
|
||||
backend.proposeShielding(account, shieldingThreshold.value, memo, transparentReceiver)
|
||||
}.onFailure {
|
||||
// TODO [#680]: if this error matches: Insufficient balance (have 0, need 1000 including fee)
|
||||
// then consider custom error that says no UTXOs existed to shield
|
||||
// TODO [#680]: https://github.com/zcash/zcash-android-wallet-sdk/issues/680
|
||||
Twig.error(it) { "proposeShielding failed" }
|
||||
}.onSuccess { result ->
|
||||
Twig.debug { "result of proposeShielding: $result" }
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
override suspend fun createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
usk: UnifiedSpendingKey
|
||||
): List<EncodedTransaction> {
|
||||
Twig.debug {
|
||||
"creating transactions for proposal"
|
||||
}
|
||||
|
||||
val transactionIds =
|
||||
runCatching {
|
||||
saplingParamTool.ensureParams(saplingParamTool.properties.paramsDirectory)
|
||||
Twig.debug { "params exist! attempting to send..." }
|
||||
backend.createProposedTransactions(proposal, usk)
|
||||
}.onFailure {
|
||||
Twig.error(it) { "Caught exception while creating transaction." }
|
||||
}.onSuccess { result ->
|
||||
Twig.debug { "result of createProposedTransactions: $result" }
|
||||
}.getOrThrow()
|
||||
|
||||
val txs =
|
||||
transactionIds.map { transactionId ->
|
||||
repository.findEncodedTransactionByTxId(transactionId)
|
||||
?: throw TransactionEncoderException.TransactionNotFoundException(transactionId)
|
||||
}
|
||||
|
||||
return txs
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to help with validation. This is not called during [createTransaction]
|
||||
* because this class asserts that all validation is done externally by the UI, for now.
|
||||
|
@ -133,48 +208,53 @@ internal class TransactionEncoderImpl(
|
|||
" ${toAddress.masked()} with memo: ${memo?.decodeToString()}"
|
||||
}
|
||||
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
return try {
|
||||
return runCatching {
|
||||
saplingParamTool.ensureParams(saplingParamTool.properties.paramsDirectory)
|
||||
Twig.debug { "params exist! attempting to send..." }
|
||||
// TODO [#1359]: Expose the proposal in a way that enables querying its fee.
|
||||
// TODO [#1359]: https://github.com/Electric-Coin-Company/zcash-android-wallet-sdk/issues/1359
|
||||
val proposal =
|
||||
backend.proposeTransfer(
|
||||
usk,
|
||||
usk.account,
|
||||
toAddress,
|
||||
amount.value,
|
||||
memo
|
||||
)
|
||||
backend.createProposedTransaction(proposal, usk)
|
||||
} catch (t: Throwable) {
|
||||
Twig.debug(t) { "Caught exception while creating transaction." }
|
||||
throw t
|
||||
}.also { result ->
|
||||
val transactionIds = backend.createProposedTransactions(proposal, usk)
|
||||
assert(transactionIds.size == 1)
|
||||
transactionIds[0]
|
||||
}.onFailure {
|
||||
Twig.error(it) { "Caught exception while creating transaction." }
|
||||
}.onSuccess { result ->
|
||||
Twig.debug { "result of sendToAddress: $result" }
|
||||
}
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
private suspend fun createShieldingSpend(
|
||||
usk: UnifiedSpendingKey,
|
||||
memo: ByteArray? = byteArrayOf()
|
||||
): FirstClassByteArray {
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
return try {
|
||||
return runCatching {
|
||||
saplingParamTool.ensureParams(saplingParamTool.properties.paramsDirectory)
|
||||
Twig.debug { "params exist! attempting to shield..." }
|
||||
// TODO [#1359]: Expose the proposal in a way that enables querying its fee.
|
||||
// TODO [#1359]: https://github.com/Electric-Coin-Company/zcash-android-wallet-sdk/issues/1359
|
||||
val proposal = backend.proposeShielding(usk, memo)
|
||||
backend.createProposedTransaction(proposal, usk)
|
||||
} catch (t: Throwable) {
|
||||
val proposal =
|
||||
backend.proposeShielding(usk.account, SHIELDING_THRESHOLD, memo)
|
||||
?: throw SdkException(
|
||||
"Insufficient balance (have 0, need $SHIELDING_THRESHOLD including fee)",
|
||||
null
|
||||
)
|
||||
val transactionIds = backend.createProposedTransactions(proposal, usk)
|
||||
assert(transactionIds.size == 1)
|
||||
transactionIds[0]
|
||||
}.onFailure {
|
||||
// TODO [#680]: if this error matches: Insufficient balance (have 0, need 1000 including fee)
|
||||
// then consider custom error that says no UTXOs existed to shield
|
||||
// TODO [#680]: https://github.com/zcash/zcash-android-wallet-sdk/issues/680
|
||||
Twig.debug(t) { "Shield failed" }
|
||||
throw t
|
||||
}.also { result ->
|
||||
Twig.error(it) { "Shield failed" }
|
||||
}.onSuccess { result ->
|
||||
Twig.debug { "result of shieldToAddress: $result" }
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SHIELDING_THRESHOLD = 100000L
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class Proposal(
|
|||
|
||||
// Check for type errors eagerly, to ensure that the caller won't
|
||||
// encounter these errors later.
|
||||
typed.feeRequired()
|
||||
typed.totalFeeRequired()
|
||||
|
||||
return typed
|
||||
}
|
||||
|
@ -34,9 +34,21 @@ class Proposal(
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the fee required by this proposal.
|
||||
* Returns the number of transactions that this proposal will create.
|
||||
*
|
||||
* This is equal to the number of `TransactionSubmitResult`s that will be returned
|
||||
* from `Synchronizer.createProposedTransactions`.
|
||||
*
|
||||
* Proposals always create at least one transaction.
|
||||
*/
|
||||
fun feeRequired(): Zatoshi {
|
||||
return Zatoshi(inner.feeRequired())
|
||||
fun transactionCount(): Int {
|
||||
return inner.transactionCount()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total fee required by this proposal for its transactions.
|
||||
*/
|
||||
fun totalFeeRequired(): Zatoshi {
|
||||
return Zatoshi(inner.totalFeeRequired())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package cash.z.ecc.android.sdk.model
|
||||
|
||||
/**
|
||||
* A result object for a transaction that was created as part of a proposal, indicating
|
||||
* whether it was submitted to the network or if an error occurred.
|
||||
*/
|
||||
sealed class TransactionSubmitResult {
|
||||
/**
|
||||
* The transaction was successfully submitted to the mempool.
|
||||
*/
|
||||
data class Success(val txId: FirstClassByteArray) : TransactionSubmitResult()
|
||||
|
||||
/**
|
||||
* An error occurred while submitting the transaction.
|
||||
*
|
||||
* If `grpcError` is true, the transaction failed to reach the `lightwalletd` server.
|
||||
* Otherwise, the transaction reached the `lightwalletd` server but failed to enter
|
||||
* the mempool.
|
||||
*/
|
||||
data class Failure(
|
||||
val txId: FirstClassByteArray,
|
||||
val grpcError: Boolean,
|
||||
val code: Int,
|
||||
val description: String?
|
||||
) : TransactionSubmitResult()
|
||||
|
||||
/**
|
||||
* The transaction was created and is in the local wallet, but was not submitted to
|
||||
* the network.
|
||||
*/
|
||||
data class NotAttempted(val txId: FirstClassByteArray) : TransactionSubmitResult()
|
||||
}
|
Loading…
Reference in New Issue