Compare commits

..

280 commits
dev ... master

Author SHA1 Message Date
5349498737
Merge pull request 'Upgrade to GHC 9.6.5' (#84) from rav001 into master
Reviewed-on: #84
2024-07-01 21:07:52 +00:00
812ff0aa70
Upgrade to GHC 9.6.5 2024-07-01 16:05:33 -05:00
874db2907e
Performance enhancement for transaction creation 2024-05-16 10:42:44 -05:00
4165cab701
Merge branch 'dev040' 2024-05-13 14:25:46 -05:00
9dddb42bb3
Merge pull request 'Implement fee calculator' (#81) from rav001 into dev040
Reviewed-on: #81
2024-05-08 18:51:34 +00:00
148abd95d0
Implement fee calculator 2024-05-08 13:49:39 -05:00
4ca5d07d1c
Merge pull request 'Fix bug in Orchard witness calculation' (#80) from rav001 into dev040
Reviewed-on: #80
2024-05-07 20:21:19 +00:00
37b485288d
Fix bug in Orchard witness calculation 2024-05-07 15:19:54 -05:00
302a2f87fa
Merge pull request 'Remove debugging' (#79) from rav001 into dev040
Reviewed-on: #79
2024-05-07 17:17:29 +00:00
2108f46afa
Remove debugging 2024-05-07 12:13:54 -05:00
22c0fe3749
Merge pull request 'Transaction creation updates' (#78) from rav001 into dev040
Reviewed-on: #78
2024-05-02 19:59:25 +00:00
1e31bb73c2
Update Rust debugging 2024-05-02 14:55:24 -05:00
c583451c83
Update debugging 2024-05-02 14:30:59 -05:00
6a632d45c1
Change error messaging 2024-05-02 14:07:54 -05:00
31c5cda65a
Improve error message 2024-05-02 13:38:12 -05:00
d5e17afc99
Debugging parameters 2024-05-02 13:34:26 -05:00
c7f2bca2c4
Remove ovk from transaction creation 2024-05-02 12:48:30 -05:00
2d14ef6b22
Update to use commitment trees for anchors 2024-05-02 12:35:36 -05:00
652e95c361
Improve error messaging 2024-05-02 12:10:53 -05:00
c144a6d624
Add more debugging to Rust 2024-05-02 07:31:01 -05:00
5fd33e7e43
Add debuggin for create transaction 2024-05-02 07:22:12 -05:00
8dbcf58a93
Merge pull request 'Fix typo in constructor' (#77) from rav001 into dev040
Reviewed-on: #77
2024-05-01 21:15:50 +00:00
bea4d2f071
Fix typo in constructor 2024-05-01 16:14:41 -05:00
61a35a034b
Merge pull request 'Add transparent key derivation' (#76) from rav001 into dev040
Reviewed-on: #76
2024-05-01 19:30:48 +00:00
bc074d0386
Add transparent key derivation 2024-05-01 14:24:18 -05:00
4a48769eeb
Merge pull request 'Add functionality for transaction creation' (#75) from rav001 into dev040
Reviewed-on: #75
2024-05-01 14:14:40 +00:00
6b391ef7d2
Merge branch 'dev040' into rav001 2024-05-01 14:14:28 +00:00
787cf40629
Add functionality for transaction creation 2024-05-01 09:12:58 -05:00
91707e13c2
Merge pull request 'Add Read instance to Rseed' (#74) from rav001 into dev040
Reviewed-on: #74
2024-05-01 00:17:18 +00:00
26a79443a7
Add Read instance to Rseed 2024-04-30 19:14:30 -05:00
c9f13643e4
Merge pull request 'Implement transaction creation' (#73) from rav001 into dev040
Reviewed-on: #73
2024-04-30 21:56:10 +00:00
ad9e2f074d
Implement transaction creation 2024-04-30 16:54:15 -05:00
f456332454
Merge pull request 'Upgrade of Rust crates' (#72) from rav001 into dev040
Reviewed-on: #72
2024-04-29 15:31:41 +00:00
201df05e9b
Merge branch 'dev040' into rav001 2024-04-29 10:29:09 -05:00
8901d97c64
Upgrade of Zcash Rust crates 2024-04-29 10:27:45 -05:00
619c80c816
Merge pull request 'Add witness update functionality' (#71) from rav001 into dev040
Reviewed-on: #71
2024-04-26 01:00:18 +00:00
24ae69cddb
Merge branch 'dev040' into rav001 2024-04-26 01:00:01 +00:00
af9806d72d
Add witness update functionality 2024-04-25 19:56:29 -05:00
00400c433d
Merge pull request 'Update note position calculation' (#70) from rav001 into dev040
Reviewed-on: #70
2024-04-24 22:28:05 +00:00
b74cd5f354
Update note position calculation 2024-04-24 16:04:56 -05:00
586cb4646c
Merge pull request 'Fix Sapling spend parsing' (#69) from rav001 into dev040
Reviewed-on: #69
2024-04-24 17:02:40 +00:00
6cf5d85c0b
Merge branch 'dev040' into rav001 2024-04-24 12:01:13 -05:00
f4612a7310
Merge pull request 'rvv040' (#67) from rvv040 into dev040
Reviewed-on: #67
2024-04-24 17:00:41 +00:00
173445612d
Merge branch 'dev040' into rvv040 2024-04-24 11:59:58 -05:00
3296909c82
Fix Sapling spend parsing 2024-04-24 11:57:00 -05:00
ebfac8438f rvv040 - decodeExchangeAddress modified to return an ExcahngeAddress object 2024-04-18 08:30:14 -04:00
f39b376380
Merge pull request 'Fix Orchard nullifier calculation' (#68) from rav001 into dev040
Reviewed-on: #68
2024-04-18 01:19:55 +00:00
7d20edd08d
Fix Orchard nullifier calculation 2024-04-17 20:14:03 -05:00
1b2c6dce24 rvv040 - Update CHANGE.LOG file 2024-04-17 20:51:12 -04:00
e6d16267ee rvv040 - Functions to create and decode an ExchangeAddress added
New DataType ExchangeAddress added.
2024-04-17 20:36:04 -04:00
4027907896
Merge pull request 'Update version' (#66) from rav001 into dev040
Reviewed-on: #66
2024-04-17 16:24:30 +00:00
e75175852b
Version bump 2024-04-17 11:21:03 -05:00
4efae180f5
Fix Rust binding for Sapling decode 2024-04-17 11:18:56 -05:00
915cd68042
Merge pull request 'Add Orchard commitment tree functionality' (#65) from rav001 into dev040
Reviewed-on: #65
2024-04-17 16:00:03 +00:00
e98ca65409
Merge branch 'dev040' into rav001 2024-04-17 10:23:30 -05:00
5abc57081a
Merge pull request 'rvv040' (#63) from rvv040 into dev040
Reviewed-on: #63
2024-04-17 14:26:38 +00:00
f94a1f83cb
Merge branch 'dev040' into rvv040 2024-04-17 09:25:46 -05:00
a56a4b1e15
Add Orchard commitment tree functionality 2024-04-17 09:21:47 -05:00
06aff8c787 rvv040 - Add encodeSaplingAddress function
Added new tests for encodeSaplingAddress and decodeSaplingAddress
2024-04-16 18:51:14 -04:00
914eb6341e
Merge pull request 'Remove debugging from Sapling decoder' (#64) from rav001 into dev040
Reviewed-on: #64
2024-04-16 20:16:46 +00:00
4f2b88974c
Remove debugging 2024-04-16 15:13:41 -05:00
058bbfe3f2 rvv040 - Added a decode Testnet Sapling Address test 2024-04-16 14:48:36 -04:00
382284a8ca rvv040 - decodeSaplingAddress Function added
SaplingAddress  data type added
2024-04-16 14:39:56 -04:00
cb985d26cd
Add debugging for Sapling decode 2024-04-16 11:19:53 -05:00
1232c3e36f
Merge pull request 'Test Sapling decoding' (#62) from rav001 into dev040
Reviewed-on: #62
2024-04-16 14:46:59 +00:00
99d772d2c7
Test Sapling decoding 2024-04-16 09:43:00 -05:00
23b8de31f1
Merge pull request 'Update Sapling commitment tree reader' (#61) from rav001 into dev040
Reviewed-on: #61
2024-04-16 01:03:01 +00:00
09ff2ed5ac
Merge branch 'dev040' into rav001 2024-04-16 01:02:38 +00:00
5402fcc072
Update Sapling commitment tree reader 2024-04-15 19:58:26 -05:00
d754498ec3
Merge pull request 'Add nullifier field to DecodedNote' (#60) from rav001 into dev040
Reviewed-on: #60
2024-04-14 22:37:52 +00:00
1b98120376
Add nullifier field to DecodedNote 2024-04-14 17:35:49 -05:00
0e52adbea4
Merge pull request 'Add new function to decode a Transparent Address in HRF' (#59) from rvv040 into dev040
Reviewed-on: #59
2024-04-14 14:27:17 +00:00
15b2f98f1d rvv040 - Fix transparent address decoding -
Function was returning the "digest" instead the "transparentReceiver"
2024-04-14 08:37:19 -04:00
95f20adb56
Merge branch 'dev040' into rvv040 2024-04-14 07:01:51 -05:00
e781ed6bd0
Add test to for transparent decoding 2024-04-14 06:57:36 -05:00
deacf373e1 rvv040 - Add new function to decode a Transparent Address in HRF
The function  retunrs a TransparentAddress object.
2024-04-13 18:27:59 -04:00
7b45bb9a6f
Merge pull request 'Add Sapling nullifier calculation' (#58) from rav001 into dev040
Reviewed-on: #58
2024-04-12 18:18:47 +00:00
6a2849aae0
Add Sapling nullifier calculation to decoding 2024-04-12 13:15:41 -05:00
0f19e376dc
Add Sapling commitment tree functionality 2024-04-11 16:01:29 -05:00
ce6a13e333
Merge branch 'dev040' into rav001 2024-04-10 11:39:27 -05:00
7efb9d0148
Merge pull request '#57 - Sapling address in Human Readable format' (#57) from rvv040 into dev040
Reviewed-on: #57
2024-04-10 16:35:39 +00:00
b6af8630b8
Merge branch 'dev040' into rvv040 2024-04-10 11:34:40 -05:00
30ca143dc9
Update changelog 2024-04-10 11:29:59 -05:00
cea8a70f44 rvva040 - Convert Sapling receiver to Human readable format
Function getSaplingFromUA -> Now returns "Maybe T.Text" instead of "T.Text"
2024-04-10 10:27:09 -04:00
3f918f734a rvv040 - Sapling address encoding to human readable format
Change Bech32m to Bech32  encoding for Sapling address
2024-04-10 09:55:41 -04:00
27b291c49a
Add function to append nodes to commitment tree 2024-04-10 07:06:04 -05:00
1f8a4cbd2b Branch rvv040 - Get Sapling Human Readable representation - In proccess
Bug - Bech32m error calculating checksum - to resolve
2024-04-09 20:23:16 -04:00
ea937f8e51
Merge pull request 'Add Orchard action decryption with spendig key' (#56) from rav001 into dev040
Reviewed-on: #56
2024-04-09 18:09:46 +00:00
7c5d4cf99f
Update version 2024-04-09 13:06:23 -05:00
4f9601f8d8
Add function to decode Orchard action with spending key 2024-04-09 13:05:57 -05:00
817c52dacf
Merge pull request 'Add Sapling output decrypting with spending key' (#55) from rav001 into dev040
Reviewed-on: #55
2024-04-08 18:01:25 +00:00
e00cf21709
Add Sapling output decrypting with spending key 2024-04-08 12:55:30 -05:00
2709d42266
Merge pull request 'Correct the parsing of the tx hash in TxIn' (#54) from rav001 into dev040
Reviewed-on: #54
2024-04-05 19:14:13 +00:00
5814cb7c9e
Correct the parsing of the tx hash in TxIn 2024-04-05 14:12:39 -05:00
a06fd08172
Merge pull request 'Fix TxIn parsing' (#53) from rav001 into dev040
Reviewed-on: #53
2024-04-05 17:52:02 +00:00
3c2e8fc994
Fix TxIn parsing 2024-04-05 12:47:17 -05:00
f375467fee
Merge pull request 'Implement identification of transparent output' (#52) from rav001 into dev040
Reviewed-on: #52
2024-04-03 21:21:08 +00:00
09411adfff
Implement test to validate transparent outputs 2024-04-03 16:16:42 -05:00
2d39576dc8
Merge branch 'dev040' into rav001 2024-04-02 14:06:07 -05:00
938ccb4b97
Add test to identify transparent outputs (#50)
Reviewed-on: #50
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
2024-04-02 19:03:50 +00:00
8b1965b46f
Merge branch 'dev040' into rav001 2024-04-02 14:03:11 -05:00
2f18c15c86
Add test to identify transparent outputs 2024-04-02 13:42:45 -05:00
204275a9b6
Merge pull request 'Implements FFI for transactions from Zebra' (#49) from rav001 into dev040
Reviewed-on: #49
2024-04-02 17:09:42 +00:00
98fb89b7b0
Merge branch 'dev040' into rav001 2024-04-02 11:36:14 -05:00
6ad879c155
Implements FFI for transaction deserialization 2024-04-02 11:23:05 -05:00
474aadb5cd
Merge pull request 'Update Zebra block deserialization for block time' (#48) from rvv040 into dev040
Reviewed-on: #48
2024-04-01 13:09:47 +00:00
93a04c09d3
Merge branch 'dev040' into rvv040 2024-03-31 06:43:17 -05:00
58b74a4c9a
Update getBlockTime to use HexString 2024-03-29 15:51:48 -05:00
dbae2150da
Advance bundle FFI 2024-03-29 13:54:21 -05:00
7cada685ce getBlockTime function added 2024-03-28 15:06:02 -04:00
4b064af4de
Merge pull request 'Implements parsing of transparent bundles' (#47) from rav001 into dev040
Reviewed-on: #47
2024-03-27 18:25:47 +00:00
52950885c1
Implements parsing of transparent bundles 2024-03-27 13:22:34 -05:00
899b79f155
Merge pull request 'Correct the parsing of OutPoint' (#46) from rav001 into dev040
Reviewed-on: #46
2024-03-27 14:05:17 +00:00
0fb02b2514
Correct parsing of OutPoint 2024-03-27 09:00:00 -05:00
1674f9b592
Merge branch 'dev040' into rav001 2024-03-26 15:40:11 -05:00
bb9d336dc3
Implements low-level transparent components (#45)
This PR includes components for the deserialization of low-level part of transparent components.

Reviewed-on: #45
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
2024-03-26 20:39:31 +00:00
f593fefd7f
Add types for low-level transparent components 2024-03-26 15:37:04 -05:00
ee27860299
Merge branch 'dev040' into rav001 2024-03-26 09:56:38 -05:00
4e86a2f5a4
Zebra Raw Tx deserialization (#44)
Implements features to deserialize the hex representation of of a Zebra Transaction

Reviewed-on: #44
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
2024-03-26 14:56:10 +00:00
921d34383a
Merge remote-tracking branch 'forge/rav001' into rav001 2024-03-26 09:53:17 -05:00
b0df0480c5
Implement Transaction hex deserialization 2024-03-26 09:50:49 -05:00
03d53aa303
Merge branch 'dev040' into rav001 2024-03-22 13:04:35 -05:00
f099544162
Account for missing response fields in Zebra response (#43)
This PR adds code to account for the missing `time` field in the Zebra response for blocks and raw transactions.

Reviewed-on: #43
Co-authored-by: pitmutt <rene@vergara.network>
Co-committed-by: pitmutt <rene@vergara.network>
2024-03-22 18:04:04 +00:00
07fa36ed7d
Merge branch 'dev040' into rav001 2024-03-22 18:03:45 +00:00
5b6ce3f29b
Account for missing block time field 2024-03-21 19:27:09 -05:00
aa10e09595
Implement Sapling spends (#42)
This PR add support for Sapling spends in the communication with Zebra.

Reviewed-on: #42
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
2024-03-21 20:15:49 +00:00
d659368cff
Merge branch 'dev040' into rav001 2024-03-21 15:14:13 -05:00
9c8a851ead
Implement Sapling spends 2024-03-21 15:12:22 -05:00
d7752e9866
Improve response handling for Zebra RPC (#41)
This PR includes changes to handle differences between the `zebrad` and `zcashd` RPC.

Reviewed-on: #41
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
2024-03-21 18:26:13 +00:00
69bce58345
Improve exception handling of Zebra calls 2024-03-21 12:52:45 -05:00
adc7150b81
Merge branch 'dev040' into rav001 2024-03-20 14:34:11 -05:00
3af235377b
Adapt response handling to Zebra (#40)
This PR allows for the Zebra behavior of not having a `result` field in the RPC response on error conditions.

Reviewed-on: #40
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
2024-03-20 19:33:36 +00:00
517b736c9a
Allow for missing result in RPC response 2024-03-20 14:16:12 -05:00
d1eaf1de4d
Merge branch 'dev040' into rav001 2024-03-20 11:29:31 -05:00
1af152dc31
Upgrade Zebra call (#39)
Reviewed-on: #39
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
2024-03-20 16:15:30 +00:00
e7050f03c0
Upgrade Zebra call 2024-03-20 11:13:02 -05:00
f228eff367
Merge pull request 'Improve dependency on Haskoin for downstream' (#38) from rav001 into dev040
Reviewed-on: #38
2024-03-15 17:30:15 +00:00
5a6f31573c
Merge branch 'dev040' into rav001 2024-03-15 17:29:59 +00:00
bc1ee2430a
Improve dependency on Haskoin for downstream 2024-03-15 12:26:28 -05:00
6e86f2caf0
Merge pull request 'Complete Unified Address generation' (#37) from rav001 into dev040
Reviewed-on: #37
2024-03-15 16:31:50 +00:00
d1b0436af2
Add documentation for new functions 2024-03-15 10:26:06 -05:00
d5c50d58c5
Merge branch 'rvv040' into rav001 2024-03-15 10:11:27 -05:00
c7c4d664dc
Remove duplicate import 2024-03-15 08:15:08 -05:00
0a98246855 Transparent fix 2 2024-03-14 17:47:09 -04:00
2c58d1260a Transparent address fix 2024-03-14 17:44:18 -04:00
5b08026102
Merge pull request 'Add Read instance to Phrase' (#36) from rav001 into dev040
Reviewed-on: #36
2024-03-14 18:14:37 +00:00
c93809489b
Add Read instance to Phrase 2024-03-14 13:12:18 -05:00
749472e515
Merge pull request 'Fix #34' (#35) from rav001 into dev040
Reviewed-on: #35
2024-03-14 18:04:47 +00:00
d0ba74c7a1
Fix #34 2024-03-14 13:02:02 -05:00
4963eea68b
Merge pull request 'Type safety improvements' (#33) from rav001 into dev040
Reviewed-on: #33
2024-03-14 17:42:17 +00:00
46a28128fd
Bump version 2024-03-14 12:39:31 -05:00
4cc4c37960
Improve type safety for Orchard 2024-03-14 12:35:13 -05:00
d2619123c0
Improve type safety for Sapling 2024-03-14 11:30:54 -05:00
23472ee1c4
Improve type safety for Seed and Phrase 2024-03-14 11:13:10 -05:00
8a293f4e79
Enable for internal/external Orchard receivers 2024-03-14 11:12:31 -05:00
5815c5c326 Merge with dev040 2024-03-13 15:37:23 -04:00
0dcf6d3e9a
Merge pull request 'Correct Sapling receiver generation' (#32) from rav001 into dev040
Reviewed-on: #32
2024-03-13 19:25:43 +00:00
6e1048cd4d
Adjust Transparent generators to use indices 2024-03-13 14:12:28 -05:00
c5feb10fbc
Update Sapling spending key with coin type 2024-03-13 12:50:39 -05:00
e69a26e984
Merge pull request 'Unified Address Generation tests' (#31) from rav001 into dev040
Reviewed-on: #31
2024-03-12 21:06:06 +00:00
4f20160c36
Enable Unified Address generation tests 2024-03-12 16:03:35 -05:00
5b6f5fa8e2
Upgrade HexString 2024-03-12 16:02:35 -05:00
1d59e8f5eb After merging with dev040 2024-03-12 15:57:43 -04:00
5db66dcf39
Adjust indexing of Sapling payment addresses 2024-03-12 12:22:05 -05:00
8d437105c9
Merge pull request 'Implement test for sequential address generation' (#30) from rav001 into dev040
Reviewed-on: #30
2024-03-11 21:18:03 +00:00
30c3827cab
Merge branch 'dev040' into rav001 2024-03-11 16:09:11 -05:00
ddaabcc5cd
Add test to check that Sapling receivers are unique 2024-03-11 15:48:27 -05:00
8baf27e988
Merge pull request 'Implement Sapling child key derivation' (#29) from rav001 into dev040
Reviewed-on: #29
2024-03-11 20:25:54 +00:00
89730a8219
Merge branch 'dev040' into rav001 2024-03-11 20:25:01 +00:00
db92dd7de7
Implement Sapling child key derivation 2024-03-11 15:23:29 -05:00
46efe9cd21 Commit first version of genSaplingInternalAddress function 2024-03-10 22:19:51 -04:00
4edd789a40
Merge pull request 'Add signature for internal Sapling address' (#28) from rav001 into dev040
Reviewed-on: #28
2024-03-10 15:21:48 +00:00
4443ffeec5
Add signature for internal Sapling address 2024-03-10 10:20:10 -05:00
9cfed00380
Merge pull request 'Sapling Spending keys and receivers' (#27) from rvv040 into dev040
Reviewed-on: #27
2024-03-10 15:07:09 +00:00
1e795dbcea
Merge remote-tracking branch 'forge/rvv040' into rvv040 2024-03-10 10:01:19 -05:00
1f58f111a6
Merge branch 'rav002' into rvv040 2024-03-10 09:44:27 -05:00
7538bbfa19
Revision of Sapling receiver logic 2024-03-10 07:47:26 -05:00
477817f37f Find_Address method implemented 2024-03-09 10:28:36 -05:00
a549c8be9a Merge branch 'dev040' into rvv040 2024-03-08 15:32:36 -05:00
54b1567011 Default Paymebt address and DiversifierIndex created
x
2024-03-08 14:46:41 -05:00
e25d759b5e
Merge pull request 'Allow for optional shielded receivers' (#25) from rav001 into dev040
Reviewed-on: #25
2024-03-08 19:45:02 +00:00
ff89bbdac6
Merge branch 'dev040' into rav001 2024-03-08 19:44:43 +00:00
d3cf05d00e
Update version 2024-03-08 13:42:18 -06:00
9c4e26c9f2
Implement initial changes for ZIP-320 Rev1 2024-03-08 13:35:37 -06:00
5c4b715a24
Merge pull request 'Update UnifiedAddress to use named types for receivers' (#24) from rav001 into dev040
Reviewed-on: #24
2024-03-08 19:12:19 +00:00
6e31d83963
Update UnifiedAddress to use named types for receivers 2024-03-08 13:09:13 -06:00
db5a694e7d
Merge pull request 'Implement QuickCheck tests for Orchard components' (#23) from rav001 into dev040
Reviewed-on: #23
2024-03-08 18:47:01 +00:00
6c2dfa02fa
Implement QuickCheck tests for Orchard components 2024-03-08 12:44:10 -06:00
47e3cf71cb
Merge pull request 'Implement generation of Orchard receiver' (#22) from rav001 into dev040
Reviewed-on: #22
2024-03-07 22:11:59 +00:00
b2f56941a4
Bump version 2024-03-07 16:07:50 -06:00
72e87577a7
Add generation of Orchard receivers 2024-03-07 16:06:33 -06:00
f1174751fc
Add new types for Spending Keys and Receivers 2024-03-07 16:05:59 -06:00
e371fcdb72
Merge pull request 'Add constants to library' (#21) from rav001 into dev040
Reviewed-on: #21
2024-03-06 21:37:04 +00:00
977f4e791d
Implement Unified HRP constants 2024-03-06 15:35:03 -06:00
b568ee5ff4
Pin dependencies 2024-03-06 15:02:48 -06:00
d118a83993
Add constants to library 2024-03-06 13:05:00 -06:00
0e6f7503d4 Sapling Extended Spemding Key generation from HDSedd (64 byte array) 2024-03-05 22:10:05 -05:00
dbccb23b45 Merge branch 'dev040' into rvv040
-- Include orchard Spending Key and new types for working with
	-- zcash network and keys
2024-03-05 17:16:27 -05:00
7b65d322e6 Commit 003 - before merging with dev040 - with orchard spending key 2024-03-05 17:01:17 -05:00
815b4f16b4
Merge pull request 'Add Orchard spending key functionality' (#20) from rav001 into dev040
Reviewed-on: #20
2024-03-05 21:13:14 +00:00
c13d321da5
Bump version 2024-03-05 15:09:57 -06:00
3822e9f2ff
Add tests for Orchard spending key 2024-03-05 15:09:35 -06:00
53716685a8
Add new types for constants for Zcash protocol 2024-03-05 14:44:19 -06:00
694ab8fd17
Add new Orchard spending key generation 2024-03-05 14:44:00 -06:00
f09c3c500b
Update versions of Zcash crates 2024-03-05 14:43:33 -06:00
9acbe5b98c
Fix compilation for Spending Key 2024-03-05 07:36:45 -06:00
a6c358cd5d Commit for debuggin process
Erros with Parameters for rustWrapperSaplingSpendingkey function
   x in Sapling.hs module
2024-03-04 18:46:39 -05:00
c1507f36e0
Merge pull request 'Implement UA encoding' (#18) from rav001 into dev040
Reviewed-on: #18
2024-03-04 18:01:38 +00:00
0b1d9e0920
Implement UA encoding per ZIP-316 2024-03-04 11:59:07 -06:00
53a5b62b6b
Correct casing on Rust code 2024-03-04 11:58:04 -06:00
2ae18463fc
Increase verbosity of Rust compile 2024-03-03 15:29:50 -06:00
97b338bddc Commit for revision... 2024-03-03 16:19:06 -05:00
3cc0e96c44
Rust updates for bech32 encode/decode 2024-03-03 08:23:48 -06:00
9a5ad756b8
Add Read implementation to UnifiedAddress 2024-03-02 07:53:48 -06:00
a52d2231f1
Merge pull request 'Correct type of blockheight' (#17) from rav001 into dev040
Reviewed-on: #17
2024-02-28 17:20:35 +00:00
cb44b6d4e0
Correct type for blockheight 2024-02-27 19:06:58 -06:00
67d6e85d05
Fix typo in cabal file 2024-02-26 08:57:12 -06:00
419f041ca9
Merge pull request 'Correct cabal versioning' (#16) from rav001 into dev040
Reviewed-on: #16
2024-02-26 14:51:12 +00:00
2ada9aac41
Correct cabal versioning 2024-02-26 08:49:47 -06:00
d0d9a1837b
Merge pull request 'Update .gitignore' (#15) from rav001 into dev040
Reviewed-on: #15
2024-02-25 23:53:17 +00:00
050c36e76d
Update .gitignore 2024-02-25 17:50:47 -06:00
ef93147f22
Merge pull request 'Update the installation settings for use by other packages' (#14) from rav001 into dev040
Reviewed-on: #14
2024-02-25 22:17:51 +00:00
105e0afc70
Merge branch 'dev040' into rav001 2024-02-25 22:17:03 +00:00
6e11ae7779
Update install instructions 2024-02-25 16:14:04 -06:00
6b870d91f8
Correct needed libraries 2024-02-25 16:11:10 -06:00
26b21e882b
Remove Makefile 2024-02-25 16:10:52 -06:00
c28addbfc3
Merge pull request 'Update installation package' (#13) from rav001 into dev040
Reviewed-on: #13
2024-02-25 21:36:30 +00:00
9713203e2b
Update installation package 2024-02-25 15:22:53 -06:00
75cc947dda
Merge pull request 'Fine tune the cabal configuration' (#12) from rav001 into dev040
Reviewed-on: #12
2024-02-23 01:29:24 +00:00
a3d6da12d7
Merge branch 'dev040' into rav001 2024-02-23 01:29:03 +00:00
ee7e32feb6
Remove flags 2024-02-21 20:32:36 -06:00
f818586b33
Set the Rust tool-chain 2024-02-21 19:33:28 -06:00
9d7a88be43
Add shared flag for cabal 2024-02-21 15:44:03 -06:00
3fa771f9f5
Merge pull request 'Add static flag for cabal' (#11) from rav001 into dev040
Reviewed-on: #11
2024-02-21 21:21:01 +00:00
faaa84caa6
Add static flag for cabal 2024-02-21 15:19:23 -06:00
4885d7525f
Merge pull request 'Implement custom build with cabal' (#10) from package into dev040
Reviewed-on: #10
2024-02-21 19:06:58 +00:00
c0e8fa85ce
Implement custom build with cabal 2024-02-21 10:51:03 -06:00
5c4786f1d5
Add tests for Seed and Phrase generation 2024-02-20 07:35:05 -06:00
f39838f24b
Pin the Rust nightly to avoid ahash error 2024-02-19 08:29:39 -06:00
73d8125b83
Merge pull request 'Add host parameter for Zebra nodes' (#9) from fix080 into dev040
Reviewed-on: #9
2024-02-14 14:22:16 +00:00
f95ebc7b00
Add host parameter for Zebra nodes 2024-02-14 08:19:34 -06:00
09cee9a064
Merge pull request 'Implement Zebra RPC calling functions' (#8) from fix080 into dev040
Reviewed-on: #8
2024-02-12 18:01:06 +00:00
75c95b03dc
Implement Zebra RPC calling functions 2024-02-12 11:55:42 -06:00
c4f345b1de
Merge pull request 'Implement Read instance' (#7) from fix080 into dev040
Reviewed-on: #7
2024-02-09 19:35:35 +00:00
49438bc99b
Merge branch 'dev040' into fix080 2024-02-09 19:35:12 +00:00
790ffec717
Update change log 2024-02-09 13:28:15 -06:00
88a5189eba
Add Read implementations 2024-02-09 13:24:34 -06:00
c91e23ab9c
Add function documentation 2024-02-09 13:23:58 -06:00
6ea8698ccb
Merge pull request 'Implement HexString' (#4) from fix080 into dev040
Reviewed-on: #4
2024-02-06 19:33:02 +00:00
c001fb5343
Implement HexString 2024-02-06 13:10:06 -06:00
d5728525ce
Update docs 2024-01-18 13:21:37 -06:00
beebabcf49
Update license to MIT 2024-01-18 12:55:23 -06:00
11a951f62a Add a new line character at the start of the script 2024-01-17 18:10:53 -05:00
0858b805d0
Update version 2024-01-17 07:45:27 -06:00
ca8010145b
Add functions to generate seed phrases and seeds 2024-01-16 16:15:05 -06:00
72e3700aa6
Merge pull request 'Encode transparent addresses' (#3) from dev021 into master
Reviewed-on: #3
2024-01-12 15:54:07 +00:00
dce171d830
Encode transparent addresses 2024-01-12 09:46:26 -06:00
abd605e6eb
Licensing update 2023-12-20 14:03:42 -06:00
c17f450253
Merge pull request 'Addition of functinality for manipulating Unified Addresses and Viewing Keys' (#1) from dev020 into master
Reviewed-on: #1
2023-12-04 16:31:16 +00:00
1d558fc646
Implement check of Unified Address and UVK 2023-10-04 11:12:30 -05:00
7992e5bfbe
Expand fields of raw Tx parsing 2023-10-02 15:25:44 -05:00
00090dbfcd
Improve error handling in Sapling decode 2023-09-29 14:06:56 -05:00
31579a6bb2
Correct return types for Rust tx parsing 2023-09-29 09:02:05 -05:00
697ce83f7c
Correct Sapling outputs parsing 2023-09-28 14:50:53 -05:00
a6a69ae4cc
Integrate Bech32 decoding into Sapling key validation 2023-09-28 14:23:42 -05:00
cbbbaa0fd0
Correct JSON parser for raw Tx 2023-09-28 13:56:31 -05:00
d78c269d96
Update raw Tx parsing to extract shielded outputs 2023-09-27 14:04:53 -05:00
489d3d632f
Add extraction of shielded outputs 2023-09-27 10:37:53 -05:00
c4799c3558
Changes for use of viewing keys 2023-09-26 15:24:18 -05:00
90b0b3e954
Add tx hex field parsing 2023-09-25 07:51:14 -05:00
e00faeda51
Add tests for Sapling decoding 2023-08-23 15:24:42 -05:00
846c8971fe
Update Sapling decoding functions 2023-08-23 15:19:31 -05:00
1d8e3729a8
Implement Sapling tx decoding 2023-08-22 15:05:40 -05:00
4d2540dce1
Update dependency graph 2023-08-21 15:58:12 -05:00
deb3ef33da
Add tests for JSON parsers 2023-08-21 09:57:45 -05:00
fef27b09bd
Add types for block and raw Tx response 2023-08-19 07:58:47 -05:00
2f8d9a0c11
Documentation update 2023-08-17 10:02:32 -05:00
ee19bc3e36
Rust dependency added for rustc 1.73 2023-07-19 14:33:32 -05:00
2600caecaf
Add installation instructions 2023-07-19 13:45:01 -05:00
fef3d3af35
Merge branch 'dev' 2023-06-15 09:27:50 -05:00
29 changed files with 5575 additions and 786 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
*~ *~
librustzcash-wrapper/target/ librustzcash-wrapper/target/
stack.yaml.lock stack.yaml.lock
dist-newstyle/

View file

@ -5,6 +5,227 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.6.2.1]
### Changed
- Modified the parsing of raw transactions for shielded outputs
- Upgraded to GHC 9.6.5
## [0.6.2.0]
### Changed
- Performance enhancement for transaction creation
## [0.6.1.1]
### Added
- Type for transaction creation errors
- Types for Sapling circuit parameters
- Function to create transaction
- Function to derive distinct transparent spending keys
### Changed
- Add `Read` instance for `Rseed`
## [0.6.1.0]
### Added
- Function to create a raw transaction
- New types for transaction creation:
- `Rseed`
- `TransparentTxSpend`
- `SaplingTxSpend`
- `OrchardTxSpend`
- `OutgoingNote`
- Rust crates:
- `secp256k1`
- `jubjub`
- `rand_core`
### Changed
- `DecodedNote` type now includes a field for `rho` and one for `rseed`
## [0.6.0.0]
### Added
- Rust crates:
- `sapling-crypto` 0.1.3
### Changed
- Modified handling of `ShieldedOutput`s based on new Rust crates
- Upgraded Rust crates:
- `orchard` to 0.7.1
- `zcash_primitives` to 0.14.0
- `zcash_client_backend` to 0.11.1
## [0.5.5.4]
### Added
- Functions to update Sapling witnesses.
- Functions to update Orchard witnesses.
## [0.5.5.3]
### Added
- Added function to generate an `ExchangeAddress` in Human Readable Format Using a `TransparentAddress` in HRF
- `encodeExchangeAddress` a function to create a `ExchangeAddress` in HRF
- `decodeExchangeAddress` a function to obtain a `TransparentAddress` object from an `ExchangeAddress` in HRF
- Added new type `ExchangeAddress`
### Fixed
- Orchard note nullifier calculation
- Sapling spend field parsing
## [0.5.5.2]
### Added
- Added function to encode a Sappling Address in Human Readable Format Using a SaplingReceiver
`encodeSaplingAddress` a zcash sapling address is returned or Nothing if the function fails
- Added decoding and encoding test
## [0.5.5.1]
### Added
- Added unction to decode a Sappling Address in Human Readable Format
`decodeSaplingAddress` returns 43 byte array containing
- Added a new Datatype `SaplingAddress`
- Added a new FFI function `rust_wrapper_decode_sapling_address` to haskell-rust interface
### Changed
- `TransparentAddress` type refactored
- `TransparentReceiver` added to replace old `TransparentAddress`
- `sha256` Function moved outside of `encodeTransparentReceiver`
## [0.5.5.0]
### Added
- Added unction to decode Transparent Address in Human Readable Format
### Changed
- `TransparentAddress` type refactored
- `TransparentReceiver` added to replace old `TransparentAddress`
- `sha256` Function moved outside of `encodeTransparentReceiver`
## [0.5.4.1]
### Added
- Functions to handle Sapling commitment trees, incremental witnesses and note positions
## [0.5.4.0]
### Added
- Function to decode Orchard actions with a spending key
- Functions for Bech32 encoding
- Function to encode a Sapling address
## [0.5.3.0]
### Added
- Function to decode Sapling outputs with a spending key
### Fixed
- Parsing of `TxIn` for FFI
## [0.5.2.0]
### Added
- Functionality to parse transparent bundles from Zebra
- Types for transparent `TxIn`, `TxOut`, `OutPoint`
## [0.5.1.0]
### Added
- Functionality to capture Sapling Spends
### Changed
- Modified the `makeZebraCall` function to handle errors explicitly
- Modified the RPC response to handle missing `result` field
## [0.5.0.1]
### Added
- Function to encode a human-readable transparent address
- Function to generate a seed phrase
- Implementations of `Read` for types
- Function to make RPC calls to `zebrad`
- Function to encode unified addresses from receivers
- Function to generate an Orchard spending key
- Constants for Zcash protocol
- Types for Spending Keys and Receivers for Sapling and Orchard
- Function to generate an Orchard receiver
- Function to generate a Sapling receiver
- Function to generate a Transparent receiver
### Changed
- Update installation to `cabal`
- Updated Rust crates:
- `bech32` to 0.11
- `orchard` to 0.7.0
- `zcash_note_encryption` to 0.4.0
- `zcash_primitives` to 0.13.0
- `zcash_client_backend` to 0.10.0
- `zip32` to 0.1.0
- Changed the `UnifiedAddress` to allow for optional shielded receivers
### Removed
- `Makefile`
## [0.3.0]
### Added
- Type to represent a transparent address/receiver
### Changed
- Full decoding of Unified Address
## [0.2.0]
### Added
- `matchOrchardAddress` function to ensure a UA matches a UVK and corresponding tests
- `makeZcashCall` function moved into this library
- `RpcResponse`, `RpcCall` types moved into this library
- Functions to decode Sapling transactions
- Tests for Sapling decoding
- Type for block response
- Type for raw transaction response
- JSON parsers for block response, transaction response, `ShieldedOutput` and `OrchardAction`
- Tests for JSON parsers
- Haddock annotations
### Changed
- Rearranged modules for cleaner dependencies.
- Upgrade to Haskell LTS 21.6
## [0.1.0] - 2023-06-14 ## [0.1.0] - 2023-06-14
### Added ### Added

190
LICENSE
View file

@ -1,178 +1,22 @@
Copyright (c) 2023 Vergara Technologies LLC MIT License
======================================================= Copyright (c) 2022-2024 Vergara Technologies LLC
Bootstrap Open Source Licence ("BOSL") v. 1.0
=======================================================
This Bootstrap Open Source Licence (the "License") applies to any original work
of authorship (the "Original Work") whose owner (the "Licensor") has placed the
following licensing notice adjacent to the copyright notice for the Original
Work:
*Licensed under the Bootstrap Open Source Licence version 1.0* Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
1. **Grant of Copyright License.** Licensor grants You a worldwide, The above copyright notice and this permission notice shall be included in all
royalty-free, non-exclusive, sublicensable license, for the duration of the copies or substantial portions of the Software.
copyright in the Original Work, to do the following:
a. to reproduce the Original Work in copies, either alone or as part of THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
a collective work; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
b. to translate, adapt, alter, transform, modify, or arrange the
Original Work, thereby creating derivative works ("Derivative Works")
based upon the Original Work;
c. to distribute or communicate copies of the Original Work and
Derivative Works to the public, provided that prior to any such
distribution or communication You first place a machine-readable copy
of the Source Code of the Original Work and such Derivative Works that
You intend to distribute or communicate in an information repository
reasonably calculated to permit inexpensive and convenient access
thereto by the public (“Information Repository”) for as long as You
continue to distribute or communicate said copies, accompanied by an
irrevocable offer to license said copies to the public free of charge
under this License, said offer valid starting no later than 12 months
after You first distribute or communicate said copies;
d. to perform the Original Work publicly; and
e. to display the Original Work publicly.
2. **Grant of Patent License.** Licensor grants You a worldwide, royalty-free,
non-exclusive, sublicensable license, under patent claims owned or controlled
by the Licensor that are embodied in the Original Work as furnished by the
Licensor, for the duration of the patents, to make, use, sell, offer for sale,
have made, and import the Original Work and Derivative Works.
3. **Grant of Source Code License.** The "Source Code" for a work means the
preferred form of the work for making modifications to it and all available
documentation describing how to modify the work. Licensor agrees to provide a
machine-readable copy of the Source Code of the Original Work along with each
copy of the Original Work that Licensor distributes. Licensor reserves the
right to satisfy this obligation by placing a machine-readable copy of said
Source Code in an Information Repository for as long as Licensor continues to
distribute the Original Work.
4. **Exclusions From License Grant.** Neither the names of Licensor, nor the
names of any contributors to the Original Work, nor any of their trademarks or
service marks, may be used to endorse or promote products derived from this
Original Work without express prior permission of the Licensor. Except as
expressly stated herein, nothing in this License grants any license to
Licensor's trademarks, copyrights, patents, trade secrets or any other
intellectual property. No patent license is granted to make, use, sell, offer
for sale, have made, or import embodiments of any patent claims other than the
licensed claims defined in Section 2. No license is granted to the trademarks
of Licensor even if such marks are included in the Original Work. Nothing in
this License shall be interpreted to prohibit Licensor from licensing under
terms different from this License any Original Work that Licensor otherwise
would have a right to license.
5. **External Deployment.** The term "External Deployment" means the use,
distribution, or communication of the Original Work or Derivative Works in any
way such that the Original Work or Derivative Works may be used by anyone other
than You, whether those works are distributed or communicated to those persons
or made available as an application intended for use over a network. As an
express condition for the grants of license hereunder, You must treat any
External Deployment by You of the Original Work or a Derivative Work as a
distribution under section 1(c).
6. **Attribution Rights.** You must retain, in the Source Code of any
Derivative Works that You create, all copyright, patent, or trademark notices
from the Source Code of the Original Work, as well as any notices of licensing
and any descriptive text identified therein as an "Attribution Notice." You
must cause the Source Code for any Derivative Works that You create to carry a
prominent Attribution Notice reasonably calculated to inform recipients that
You have modified the Original Work.
7. **Warranty of Provenance and Disclaimer of Warranty.** Licensor warrants
that the copyright in and to the Original Work and the patent rights granted
herein by Licensor are owned by the Licensor or are sublicensed to You under
the terms of this License with the permission of the contributor(s) of those
copyrights and patent rights. Except as expressly stated in the immediately
preceding sentence, the Original Work is provided under this License on an "AS
IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without
limitation, the warranties of non-infringement, merchantability or fitness for
a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS
WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this
License. No license to the Original Work is granted by this License except
under this disclaimer.
8. **Limitation of Liability.** Under no circumstances and under no legal
theory, whether in tort (including negligence), contract, or otherwise, shall
the Licensor be liable to anyone for any indirect, special, incidental, or
consequential damages of any character arising as a result of this License or
the use of the Original Work including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses. This limitation of liability shall not apply to
the extent applicable law prohibits such limitation.
9. **Acceptance and Termination.** If, at any time, You expressly assented to
this License, that assent indicates your clear and irrevocable acceptance of
this License and all of its terms and conditions. If You distribute or
communicate copies of the Original Work or a Derivative Work, You must make a
reasonable effort under the circumstances to obtain the express assent of
recipients to the terms of this License. This License conditions your rights to
undertake the activities listed in Section 1, including your right to create
Derivative Works based upon the Original Work, and doing so without honoring
these terms and conditions is prohibited by copyright law and international
treaty. Nothing in this License is intended to affect copyright exceptions and
limitations (including 'fair use' or 'fair dealing'). This License shall
terminate immediately and You may no longer exercise any of the rights granted
to You by this License upon your failure to honor the conditions in Section
1(c).
10. **Termination for Patent Action.** This License shall terminate
automatically and You may no longer exercise any of the rights granted to You
by this License as of the date You commence an action, including a cross-claim
or counterclaim, against Licensor or any licensee alleging that the Original
Work infringes a patent. This termination provision shall not apply for an
action alleging patent infringement by combinations of the Original Work with
other software or hardware.
11. **Jurisdiction, Venue and Governing Law.** Any action or suit relating to
this License may be brought only in the courts of a jurisdiction wherein the
Licensor resides or in which Licensor conducts its primary business, and under
the laws of that jurisdiction excluding its conflict-of-law provisions. The
application of the United Nations Convention on Contracts for the International
Sale of Goods is expressly excluded. Any use of the Original Work outside the
scope of this License or after its termination shall be subject to the
requirements and penalties of copyright or patent law in the appropriate
jurisdiction. This section shall survive the termination of this License.
12. **Attorneys' Fees.** In any action to enforce the terms of this License or
seeking damages relating thereto, the prevailing party shall be entitled to
recover its costs and expenses, including, without limitation, reasonable
attorneys' fees and costs incurred in connection with such action, including
any appeal of such action. This section shall survive the termination of this
License.
13. **Miscellaneous.** If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent necessary to
make it enforceable.
14. **Definition of "You" in This License.** "You" throughout this License,
whether in upper or lower case, means an individual or a legal entity
exercising rights under, and complying with all of the terms of, this License.
For legal entities, "You" includes any entity that controls, is controlled by,
or is under common control with you. For purposes of this definition, "control"
means (i) the power, direct or indirect, to cause the direction or management
of such entity, whether by contract or otherwise, or (ii) ownership of fifty
percent (50%) or more of the outstanding shares, or (iii) beneficial ownership
of such entity.
15. **Right to Use.** You may use the Original Work in all ways not otherwise
restricted or conditioned by this License or by law, and Licensor promises not
to interfere with or be responsible for such uses by You.
16. **Modification of This License.** This License is Copyright © 2007 Zooko
Wilcox-O'Hearn. Permission is granted to copy, distribute, or communicate this
License without modification. Nothing in this License permits You to modify
this License as applied to the Original Work or to Derivative Works. However,
You may modify the text of this License and copy, distribute or communicate
your modified version (the "Modified License") and apply it to other original
works of authorship subject to the following conditions: (i) You may not
indicate in any way that your Modified License is the "Bootstrap Open Source
Licence" or "BOSL" and you may not use those names in the name of your Modified
License; and (ii) You must replace the notice specified in the first paragraph
above with the notice "Licensed under <insert your license name here>" or with
a notice of your own that is not confusingly similar to the notice in this
License.

View file

@ -1,14 +0,0 @@
rustlib := librustzcash-wrapper/target/x86_64-unknown-linux-gnu/debug
.PHONY: all
all: haskell
test: test/Spec.hs haskell
stack test
haskell: src/ZcashHaskell/Orchard.hs src/ZcashHaskell/Sapling.hs src/ZcashHaskell/Types.hs src/ZcashHaskell/Utils.hs src/C/Zcash.chs package.yaml stack.yaml $(rustlib)/rustzcash_wrapper.h $(rustlib)/librustzcash_wrapper.a $(rustlib)/librustzcash_wrapper.so $(rustlib)/rustzcash_wrapper-uninstalled.pc
stack build
$(rustlib)/rustzcash_wrapper.h: librustzcash-wrapper/src/lib.rs librustzcash-wrapper/Cargo.toml
cd librustzcash-wrapper && cargo +nightly cbuild

View file

@ -4,4 +4,37 @@ A Haskell library to interact with the Zcash blockchain.
## Installation ## Installation
- Install [Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html)
- Install `cbuild`:
```
cargo install cargo-c
```
- Install `c2hs`:
```
stack install c2hs
```
- Set up the paths to locate the static library:
```
./configure
```
- Compile the Rust and Haskell portions:
```
cabal build
```
## Use
Add these dependencies to your `stack.yaml`:
```
- git: https://git.vergara.tech/Vergara_Tech/zcash-haskell.git
commit: fef3d3af35a09db718cddb8fc9166b2d2691a744
- git: https://git.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
commit: 787c2e813eb3a5d16c375d4b37dfefbd2adcdf05
- git: https://github.com/well-typed/borsh.git
commit: d2fcfa159e0a844b1ec5e8ed3e232d4b380fa831
- aeson-2.1.2.1@sha256:5b8d62a60963a925c4d123a46e42a8e235a32188522c9f119f64ac228c2612a7,6359
- vector-0.13.0.0@sha256:fa5cac81a17a5af388716792e8b99c24b3b66770086756d0d8b23f8272a0244c,9112
```
Add `zcash-haskell` to your `package.yaml` as needed.

137
Setup.hs Normal file
View file

@ -0,0 +1,137 @@
import Control.Exception (throw)
import Control.Monad (forM_, when)
import Data.Maybe (fromMaybe)
import Distribution.PackageDescription
import Distribution.Simple
import Distribution.Simple.LocalBuildInfo (LocalBuildInfo(..), localPkgDescr)
import Distribution.Simple.PreProcess
import Distribution.Simple.Program.Find
( defaultProgramSearchPath
, findProgramOnSearchPath
)
import Distribution.Simple.Setup
import Distribution.Simple.Utils
( IODataMode(IODataModeBinary)
, maybeExit
, rawSystemStdInOut
)
import Distribution.Verbosity (Verbosity)
import qualified Distribution.Verbosity as Verbosity
import GHC.Generics
import System.Directory
( XdgDirectory(..)
, copyFile
, createDirectory
, createDirectoryIfMissing
, doesDirectoryExist
, doesFileExist
, getCurrentDirectory
, getDirectoryContents
, getHomeDirectory
, getXdgDirectory
)
import System.Environment
import System.FilePath ((</>))
import Text.Regex
import Text.Regex.Base
main :: IO ()
main = defaultMainWithHooks hooks
where
hooks =
simpleUserHooks
{ preConf =
\_ flags -> do
rsMake (fromFlag $ configVerbosity flags)
pure emptyHookedBuildInfo
, hookedPreProcessors = knownSuffixHandlers
, confHook = \a flags -> confHook simpleUserHooks a flags >>= rsAddDirs
, postClean = \_ flags _ _ -> rsClean (fromFlag $ cleanVerbosity flags)
}
rsFolder :: FilePath
rsFolder = "librustzcash-wrapper"
execCargo :: Verbosity -> String -> [String] -> IO ()
execCargo verbosity command args = do
cargoPath <-
findProgramOnSearchPath Verbosity.normal defaultProgramSearchPath "cargo"
dir <- getCurrentDirectory
let cargoExec =
case cargoPath of
Just (p, _) -> p
Nothing -> "cargo"
cargoArgs = command : args
workingDir = Just (dir </> rsFolder)
thirdComponent (_, _, c) = c
maybeExit . fmap thirdComponent $
rawSystemStdInOut
verbosity
cargoExec
cargoArgs
workingDir
Nothing
Nothing
IODataModeBinary
rsMake :: Verbosity -> IO ()
rsMake verbosity = do
execCargo verbosity "cbuild" []
rsAddDirs :: LocalBuildInfo -> IO LocalBuildInfo
rsAddDirs lbi' = do
localData <- getXdgDirectory XdgData "zcash-haskell"
createDirectoryIfMissing True localData
dir <- getCurrentDirectory
let rustIncludeDir =
dir </> rsFolder </> "target/x86_64-unknown-linux-gnu/debug"
rustLibDir = dir </> rsFolder </> "target/x86_64-unknown-linux-gnu/debug"
updateLbi lbi = lbi {localPkgDescr = updatePkgDescr (localPkgDescr lbi)}
updatePkgDescr pkgDescr =
pkgDescr {library = updateLib <$> library pkgDescr}
updateLib lib = lib {libBuildInfo = updateLibBi (libBuildInfo lib)}
updateLibBi libBuild =
libBuild
{ includeDirs = rustIncludeDir : includeDirs libBuild
, extraLibDirs = rustLibDir : extraLibDirs libBuild
}
copyDir rustLibDir localData
pure $ updateLbi lbi'
rsClean :: Verbosity -> IO ()
rsClean verbosity = execCargo verbosity "clean" []
cabalFlag :: FlagName -> ConfigFlags -> Bool
cabalFlag name =
fromMaybe False . lookupFlagAssignment name . configConfigurationsFlags
unlessFlagM :: FlagName -> ConfigFlags -> IO () -> IO ()
unlessFlagM name flags action
| cabalFlag name flags = pure ()
| otherwise = action
applyUnlessM :: FlagName -> ConfigFlags -> (a -> IO a) -> a -> IO a
applyUnlessM name flags apply a
| cabalFlag name flags = pure a
| otherwise = apply a
copyDir :: FilePath -> FilePath -> IO ()
copyDir src dst = do
whenM (not <$> doesDirectoryExist src) $
throw (userError "source does not exist")
--whenM (doesFileOrDirectoryExist dst) $
--throw (userError "destination already exists")
createDirectoryIfMissing True dst
content <- getDirectoryContents src
let xs = filter (`notElem` [".", ".."]) content
forM_ xs $ \name -> do
let srcPath = src </> name
let dstPath = dst </> name
isDirectory <- doesDirectoryExist srcPath
if isDirectory
then copyDir srcPath dstPath
else copyFile srcPath dstPath
where
doesFileOrDirectoryExist x = orM [doesDirectoryExist x, doesFileExist x]
orM xs = or <$> sequence xs
whenM s r = s >>= flip when r

75
block.json Normal file
View file

@ -0,0 +1,75 @@
{
"hash": "000000000079250b2cb5f3a04f47623db0f2552abeeb5fef914d8833c827ff63",
"confirmations": 5,
"size": 19301,
"height": 2196277,
"version": 4,
"merkleroot": "bbeb085e2e69afd760e48512f2cc4af788331a19ad03cf1442dc2c38bf1819ef",
"blockcommitments": "9af507deaee501f8a9a9efb367d199b21d08874393f0408412c408352f967845",
"authdataroot": "562acdacbf061ef8ef5b84917247669b45935f83280adfedcd0f9b39efaf25ef",
"finalsaplingroot": "625ebbfa357830e0ecf7b14b149939e9c95c75ef19ae17b32f660783add33196",
"finalorchardroot": "d54d40365258b350642ede76ec8d411220b93b4bd16c63bff803715b87154e0b",
"chainhistoryroot": "b4438f23544049ed0185baca65cfbc06a09eee7577b4fe567e3f6bb08f107c56",
"tx": [
"795fabb4070cc221480e3b8deba2f76a9c5d16026a5f8e2c29c833e5b6088eb4",
"66637dc7703bbacc385ef7f2e087bd5fcc56763515217822906e352f504eb820",
"b2384cd27fb12cb119754f91077453ffdc553da3be384d156b1f16ce4e88a9c5",
"c4c1c3d962f2e56b65585be3b5a09c7b42e1a6ea66c0f6492ad3d3ea2e0775d0",
"e1acb17e24b7d2df5a2c23349a1fc66d1084b1a9a85cfe760ed72fb37f960a12",
"e5aeac0d023259551616cdec6727219048535aa619bba4e722e887424cf9ebef"
],
"time": 1692399702,
"nonce": "ddca0340000000000000000000370000000000000000000000000000093e790d",
"solution": "003b65d98e5199710d69e661f6def0120bc519c7bd1a4ec4b727edf953746a261046760f1dd584f743781478251d65a4b7e1f775c192c8f01aecf2301753bd1eb472ea4b9bb33d9c6236d6f94551c6ee699a20be02342d54196ed2a1ce43c0a56cb20baeda8578498a2cd783b49970a65b8bc2c9d45d7b6863b86e5fb5291b5af986da9e11f5342477173b68cd8e58099791b028031725459bb81353f398baee5acb0390243e36e1039720df4108697dab0772b844ded785119a3cb4f30483221042c965efcb0190dbcbe8eac0f4c0ac51a404ec0f06bf83cfae33a9163c73e7402e07c1f59fb01b692167359a5ea2fd30452b723443454e22ec32de0556e899860cb029439e04642f2cc4815265b521e207ba7d794d498157d1f0e364762f32b32a375e483c19f4a7419846fc75be75729a2cff99f8f5b690d58d40a3bd1043a2caeb79aa44a97d792b0d60d1d6c2460105c304c9418fd5f859b1ebb649854a9473394057103edad7e518bf7afe1165ceff7e50365c7b1dac6c3b9e35ea842ce251b041566c3f576e961485770806459a1e752ee2fac542693999ad7c268aecd87d37550285a6a1420ba2af5007c2ac3c678401c92dbb63a423f003537bd7b93961c32314667dc8dddfc49b84dc0896bb7611da7d5347b1019f7aacf3e19c16ddf91d30ddec8f40ea919156aa75b8644981ae909f98f433012173489f443a11e1d9e50649a95299d0aa91b9d50343c70b4c209ce77222a2200dc1406d98bfacc9ac09f98d1e1d440af18b3c8327d0a1c0027e9c7fadfe181a4d62b9d3869d38c542e1b22c271b6f491f49ea0b684b4a3ca841c1ebb5b1efe443cd1b94653cc8d70c220dc95e9611c561f19188391fe2be3b9bf84e2615ca99f87a4d7421964002018b4199c8a9037b44304133c7c4bcd6a55d7aeec4f5d12d9359dbc97802350072885f8f2ea93feaa3e3b03e7afc2ad581b6aea30cafb2ea8891cc0df673b2b8ca5e1a692d3ab32b31132b3e6882937443e872c34818305f390500bb37a921b1094e05d894c6e62913c402bc6deef5989f98990256b0f99c212bd3d810f1459a30f281196edebf531392d72368df449b3ee2a2c3c8a36349bd985215630701decafe90648edebec3f263bd70969955bb839b37a724a9c9d0420abc80e8172fc1ca5a7d3b587ea305fd1d2c021e760cf662f19079bbe56a454e9e284e465adebb3c12d4d9353fa5c002c037af529f3fb9ab067ebf1a7b30807b89803751665f6b5aeea117f03e15d66e1b1aef675b9674d512b5d0d895ca5cd5cc920f35020eaaa76637c198124c2dc33da4d71bdfc49e15f5c79ca4b33f0df22682d5541f2714cba71207d91acecb0fe88dd960eb61a3c8aec32b822b4abc11ba1f63b920191a62b4e4bc42b2b151ed1e701cbd408100bb2b4fe393da9b81b708f3884cee7e7414944a481b1e1c5f2851477acc7803e622ffab7e444d7e8faa3c46d6187ed31d02f3c6790453e67f7ac622db35ac5edee7b72aa4acf16f6bd8cb3dd878c7b0223ef2ce017dcf919d120dc0c83d5401bf4c6baaed245eabea031b3c2fbce6d7a3bd3ea0886e1e0c8067bd724de003c837947284569e5a39666bb7ce0a21af3d11f82114b75d5556504d31e229b3c2942a28f51b378bdb15059e0073e9a60f515770315c0d8dd58ab3b89bd6cd3e9bd2109b67cfe5732ff68cdb6aa0f29b90f92f3707cbed01a0c20bec9c427735af54983ec4369a253521d4c42e4ca1bff59adb02878cd8b26cb952b71a0506305b8ffe695581eae625d23bb4e3be2e84bed7ac193d0267386846efa7ccd1b3b6bd04d52271bf62dd08590125c49f9fefe32a859380bc638fd4f31eecc11087e627b44a7a73786b23614b6864bec39afacf18",
"bits": "1c01b44d",
"difficulty": 78752260.61608158,
"chainwork": "0000000000000000000000000000000000000000000000000e4f2c44f6a82cfb",
"anchor": "638a7385e9910d3e18ae4240735ed4a5f6b0f410b0a1bef9d831452e0cff0a3c",
"chainSupply": {
"monitored": false,
"valueDelta": 3.12500000,
"valueDeltaZat": 312500000
},
"valuePools": [
{
"id": "transparent",
"monitored": false,
"valueDelta": -134.79807867,
"valueDeltaZat": -13479807867
},
{
"id": "sprout",
"monitored": true,
"chainValue": 26762.63007004,
"chainValueZat": 2676263007004,
"valueDelta": 0.00000000,
"valueDeltaZat": 0
},
{
"id": "sapling",
"monitored": true,
"chainValue": 1155712.35104510,
"chainValueZat": 115571235104510,
"valueDelta": 68.96131433,
"valueDeltaZat": 6896131433
},
{
"id": "orchard",
"monitored": true,
"chainValue": 96151.73011093,
"chainValueZat": 9615173011093,
"valueDelta": 68.96176434,
"valueDeltaZat": 6896176434
}
],
"trees": {
"sapling": {
"size": 72943241
},
"orchard": {
"size": 48645942
}
},
"previousblockhash": "0000000000a67420fd68bf269b63d821b158cd1da20d067e219adaa66977970d",
"nextblockhash": "00000000016ebe0a0da97446c677478aa30df66b1b503fd297ad895ee7941d5e"
}

13
cabal.project Normal file
View file

@ -0,0 +1,13 @@
packages: ./*.cabal
with-compiler: ghc-9.6.5
source-repository-package
type: git
location: https://git.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
tag: 335e804454cd30da2c526457be37e477f71e4665
source-repository-package
type: git
location: https://git.vergara.tech/Vergara_Tech/haskell-hexstring.git
tag: 39d8da7b11a80269454c2f134a5c834e0f3cb9a7

207
cabal.project.freeze Normal file
View file

@ -0,0 +1,207 @@
active-repositories: hackage.haskell.org:merge
constraints: any.Cabal ==3.10.3.0,
any.Cabal-syntax ==3.10.3.0,
any.HUnit ==1.6.2.0,
any.OneTuple ==0.4.2,
any.QuickCheck ==2.14.3,
QuickCheck -old-random +templatehaskell,
any.StateVar ==1.2.2,
any.aeson ==2.2.3.0,
aeson +ordered-keymap,
any.alex ==3.5.1.0,
any.ansi-terminal ==1.1.1,
ansi-terminal -example,
any.ansi-terminal-types ==1.1,
any.appar ==0.1.8,
any.array ==0.5.6.0,
any.asn1-encoding ==0.9.6,
any.asn1-parse ==0.9.5,
any.asn1-types ==0.3.4,
any.assoc ==1.1.1,
assoc -tagged,
any.async ==2.2.5,
async -bench,
any.attoparsec ==0.14.4,
attoparsec -developer,
any.attoparsec-aeson ==2.2.2.0,
any.base ==4.18.2.1,
any.base-orphans ==0.9.2,
any.base16 ==1.0,
any.base16-bytestring ==1.0.2.0,
any.base58-bytestring ==0.1.0,
any.base64-bytestring ==1.2.1.0,
any.basement ==0.0.16,
any.bifunctors ==5.6.2,
bifunctors +tagged,
any.binary ==0.8.9.1,
any.binary-orphans ==1.0.5,
any.bitvec ==1.1.5.0,
bitvec +simd,
any.blaze-builder ==0.4.2.3,
any.borsh ==0.3.0,
any.byteorder ==1.0.4,
any.bytes ==0.17.3,
any.bytestring ==0.11.5.3,
any.c2hs ==0.28.8,
c2hs +base3 -regression,
any.call-stack ==0.4.0,
any.case-insensitive ==1.2.1.0,
any.cborg ==0.2.10.0,
cborg +optimize-gmp,
any.cereal ==0.5.8.3,
cereal -bytestring-builder,
any.character-ps ==0.1,
any.colour ==2.3.6,
any.comonad ==5.0.8,
comonad +containers +distributive +indexed-traversable,
any.conduit ==1.3.5,
any.conduit-extra ==1.3.6,
any.containers ==0.6.7,
any.contravariant ==1.5.5,
contravariant +semigroups +statevar +tagged,
any.cookie ==0.5.0,
any.crypton ==1.0.0,
crypton -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq +support_pclmuldq +support_rdrand -support_sse +use_target_attributes,
any.crypton-connection ==0.4.1,
any.crypton-x509 ==1.7.7,
any.crypton-x509-store ==1.6.9,
any.crypton-x509-system ==1.6.7,
any.crypton-x509-validation ==1.6.12,
any.cryptonite ==0.30,
cryptonite -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq -support_pclmuldq +support_rdrand -support_sse +use_target_attributes,
any.data-default ==0.7.1.1,
any.data-default-class ==0.1.2.0,
any.data-default-instances-containers ==0.0.1,
any.data-default-instances-dlist ==0.0.1,
any.data-default-instances-old-locale ==0.0.1,
any.data-fix ==0.3.3,
any.deepseq ==1.4.8.1,
any.directory ==1.3.8.4,
any.distributive ==0.6.2.1,
distributive +semigroups +tagged,
any.dlist ==1.0,
dlist -werror,
any.entropy ==0.4.1.10,
entropy -donotgetentropy,
any.envy ==2.1.3.0,
any.exceptions ==0.10.7,
any.filepath ==1.4.300.1,
any.foreign-rust ==0.1.0,
any.generically ==0.1.1,
any.generics-sop ==0.5.1.4,
any.ghc-bignum ==1.3,
any.ghc-boot-th ==9.6.5,
any.ghc-prim ==0.10.0,
any.half ==0.3.1,
any.happy ==1.20.1.1,
any.hashable ==1.4.7.0,
hashable -arch-native +integer-gmp -random-initial-seed,
any.haskell-lexer ==1.1.1,
any.haskoin-core ==1.1.0,
any.hexstring ==0.12.1.0,
any.hourglass ==0.2.12,
any.hsc2hs ==0.68.10,
hsc2hs -in-ghc-tree,
any.hspec ==2.11.9,
any.hspec-core ==2.11.9,
any.hspec-discover ==2.11.9,
any.hspec-expectations ==0.8.4,
any.http-client ==0.7.17,
http-client +network-uri,
any.http-client-tls ==0.3.6.3,
any.http-conduit ==2.3.8.3,
http-conduit +aeson,
any.http-types ==0.12.4,
any.indexed-traversable ==0.1.4,
any.indexed-traversable-instances ==0.1.2,
any.integer-conversion ==0.1.1,
any.integer-gmp ==1.1,
any.integer-logarithms ==1.0.3.1,
integer-logarithms -check-bounds +integer-gmp,
any.iproute ==1.7.12,
any.language-c ==0.9.3,
language-c -allwarnings +iecfpextension +usebytestrings,
any.memory ==0.18.0,
memory +support_bytestring +support_deepseq,
any.mime-types ==0.1.2.0,
any.mono-traversable ==1.0.17.0,
any.mtl ==2.3.1,
any.murmur3 ==1.0.5,
any.network ==3.2.1.0,
network -devel,
any.network-uri ==2.6.4.2,
any.old-locale ==1.0.0.7,
any.old-time ==1.1.0.4,
any.os-string ==2.0.6,
any.parsec ==3.1.16.1,
any.pem ==0.2.4,
any.pretty ==1.1.3.6,
any.primitive ==0.9.0.0,
any.process ==1.6.19.0,
any.quickcheck-io ==0.2.0,
any.quickcheck-transformer ==0.3.1.2,
any.random ==1.2.1.2,
any.regex-base ==0.94.0.2,
any.regex-compat ==0.95.2.1,
any.regex-posix ==0.96.0.1,
regex-posix -_regex-posix-clib,
any.resourcet ==1.3.0,
any.rts ==1.0.2,
any.safe ==0.3.21,
any.scientific ==0.3.8.0,
scientific -integer-simple,
any.secp256k1-haskell ==1.2.0,
any.semialign ==1.3.1,
semialign +semigroupoids,
any.semigroupoids ==6.0.1,
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
any.serialise ==0.2.6.1,
serialise +newtime15,
any.socks ==0.6.1,
any.sop-core ==0.5.0.2,
any.split ==0.2.5,
any.splitmix ==0.1.0.5,
splitmix -optimised-mixer,
any.stm ==2.5.1.0,
any.streaming-commons ==0.2.2.6,
streaming-commons -use-bytestring-builder,
any.strict ==0.5,
any.string-conversions ==0.4.0.1,
any.tagged ==0.8.8,
tagged +deepseq +transformers,
any.template-haskell ==2.20.0.0,
any.text ==2.0.2,
any.text-iso8601 ==0.1.1,
any.text-short ==0.1.6,
text-short -asserts,
any.tf-random ==0.5,
any.th-abstraction ==0.7.0.0,
any.th-compat ==0.1.5,
any.these ==1.2.1,
any.time ==1.12.2,
any.time-compat ==1.9.7,
any.tls ==2.1.0,
tls -devel,
any.transformers ==0.6.1.0,
any.transformers-compat ==0.7.2,
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
any.typed-process ==0.2.11.1,
any.unix ==2.8.4.0,
any.unix-time ==0.4.15,
any.unliftio-core ==0.2.1.0,
any.unordered-containers ==0.2.20,
unordered-containers -debug,
any.utf8-string ==1.0.2,
any.uuid-types ==1.0.6,
any.vector ==0.13.1.0,
vector +boundschecks -internalchecks -unsafechecks -wall,
any.vector-algorithms ==0.9.0.2,
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
any.vector-stream ==0.1.0.1,
any.void ==0.7.3,
void -safe,
any.wide-word ==0.1.6.0,
any.witherable ==0.5,
any.zlib ==0.7.1.0,
zlib -bundled-c-zlib +non-blocking-ffi +pkg-config
index-state: hackage.haskell.org 2024-07-01T20:28:56Z

2
configure vendored
View file

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
echo -e "\n"
echo "export PKG_CONFIG_PATH=$(pwd)/librustzcash-wrapper/target/x86_64-unknown-linux-gnu/debug:\$PKG_CONFIG_PATH" | tee -a ~/.bashrc echo "export PKG_CONFIG_PATH=$(pwd)/librustzcash-wrapper/target/x86_64-unknown-linux-gnu/debug:\$PKG_CONFIG_PATH" | tee -a ~/.bashrc
echo "export LD_LIBRARY_PATH=$(pwd)/librustzcash-wrapper/target/x86_64-unknown-linux-gnu/debug:\$LD_LIBRARY_PATH" | tee -a ~/.bashrc echo "export LD_LIBRARY_PATH=$(pwd)/librustzcash-wrapper/target/x86_64-unknown-linux-gnu/debug:\$LD_LIBRARY_PATH" | tee -a ~/.bashrc
source ~/.bashrc source ~/.bashrc

File diff suppressed because it is too large Load diff

View file

@ -4,18 +4,26 @@ version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
haskell-ffi.git = "https://github.com/BeFunctional/haskell-rust-ffi.git" haskell-ffi.git = "https://github.com/BeFunctional/haskell-rust-ffi.git"
haskell-ffi.rev = "2bf292e2e56eac8e9fb0fb2e1450cf4a4bd01274" haskell-ffi.rev = "2bf292e2e56eac8e9fb0fb2e1450cf4a4bd01274"
f4jumble = "0.1" f4jumble = "0.1"
zcash_address = "0.2.0" zcash_address = "0.2.0"
borsh = "0.10" borsh = "0.10"
bech32 = "0.9.1" bech32 = "0.11"
orchard = "0.4.0" orchard = "0.7.1"
zcash_note_encryption = "0.3.0" zcash_note_encryption = "0.4.0"
zcash_primitives = "0.11.0" zcash_primitives = { version = "0.14.0", features = ["transparent-inputs"]}
zcash_client_backend = "0.9.0" zcash_client_backend = "0.11.1"
sapling-crypto = "0.1.3"
zip32 = "0.1.0"
proc-macro2 = "1.0.66"
nonempty = "0.7.0"
incrementalmerkletree = "0.5.0"
secp256k1 = "0.26.0"
jubjub = "0.10.0"
rand_core = { version = "0.6.4", features = ["getrandom"]}
[features] [features]
capi = [] capi = []

View file

@ -0,0 +1,4 @@
[toolchain]
channel = "nightly-2024-02-04"
components = [ "rustfmt", "rustc-dev"]
profile = "minimal"

File diff suppressed because it is too large Load diff

View file

@ -1,49 +0,0 @@
name: zcash-haskell
version: 0.1.0
git: "https://git.vergara.tech/Vergara_Tech/zcash-haskell"
license: BOSL
author: "Rene Vergara"
maintainer: "rene@vergara.network"
copyright: "(c)2023 Vergara Technologies LLC"
extra-source-files:
- README.md
- CHANGELOG.md
- configure
# Metadata used when publishing your package
synopsis: Utilities to interact with the Zcash blockchain
category: Blockchain
# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
# common to point users to the README.md file.
description: Please see the README on the repo at <https://git.vergara.tech/Vergara_Tech/haskell-wrapper#readme>
dependencies:
- base >= 4.7 && < 5
library:
source-dirs: src
dependencies:
- bytestring
- borsh >= 0.2
- text
- foreign-rust
- generics-sop
pkg-config-dependencies:
- rustzcash_wrapper-uninstalled
tests:
zcash-haskell-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- zcash-haskell
- hspec
- bytestring
- text

View file

@ -1,3 +1,9 @@
{- Copyright 2022-2024 Vergara Technologies LLC
This file is part of Zcash-Haskell.
-}
{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveAnyClass #-}
@ -11,10 +17,11 @@ module C.Zcash where
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import Codec.Borsh import Codec.Borsh
import Data.Text (Text) import qualified Data.Text as T
import Data.Word import Data.Word
import Data.Int import Data.Int
import Data.Structured import Data.Structured
import Data.HexString (HexString(..))
import Foreign.C.Types import Foreign.C.Types
import Foreign.Rust.Marshall.External import Foreign.Rust.Marshall.External
import Foreign.Rust.Marshall.Fixed import Foreign.Rust.Marshall.Fixed
@ -25,6 +32,20 @@ import qualified Generics.SOP as SOP
import qualified GHC.Generics as GHC import qualified GHC.Generics as GHC
import ZcashHaskell.Types import ZcashHaskell.Types
{# fun unsafe rust_wrapper_bech32decode as rustWrapperBech32Decode
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer RawData'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_bech32m_encode as rustWrapperBech32mEncode
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer (T.Text)'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_f4jumble as rustWrapperF4Jumble {# fun unsafe rust_wrapper_f4jumble as rustWrapperF4Jumble
{ toBorshVar* `BS.ByteString'& { toBorshVar* `BS.ByteString'&
@ -40,10 +61,11 @@ import ZcashHaskell.Types
-> `()' -> `()'
#} #}
{# fun pure unsafe rust_wrapper_ua_decode as rustWrapperIsUA {# fun unsafe rust_wrapper_ua_decode as rustWrapperUADecode
{ toBorshVar* `BS.ByteString'& { toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer RawUA'&
} }
-> `Bool' -> `()'
#} #}
{# fun pure unsafe rust_wrapper_shielded_decode as rustWrapperIsShielded {# fun pure unsafe rust_wrapper_shielded_decode as rustWrapperIsShielded
@ -52,13 +74,6 @@ import ZcashHaskell.Types
-> `Bool' -> `Bool'
#} #}
{# fun unsafe rust_wrapper_bech32decode as rustWrapperBech32Decode
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer RawData'&
}
-> `()'
#}
{# fun pure unsafe rust_wrapper_svk_decode as rustWrapperSaplingVkDecode {# fun pure unsafe rust_wrapper_svk_decode as rustWrapperSaplingVkDecode
{ toBorshVar* `BS.ByteString'& { toBorshVar* `BS.ByteString'&
} }
@ -72,6 +87,32 @@ import ZcashHaskell.Types
-> `Bool' -> `Bool'
#} #}
{# fun pure unsafe rust_wrapper_ufvk_check_address as rustWrapperOrchardCheck
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
}
-> `Bool'
#}
{# fun unsafe rust_wrapper_sapling_note_decrypt_v2 as rustWrapperSaplingNoteDecode
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `ShieldedOutput'&
, getVarBuffer `Buffer DecodedNote'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_sapling_esk_decrypt as rustWrapperSaplingDecodeEsk
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `ShieldedOutput'&
, `Bool'
, `Bool'
, `Word64'
, getVarBuffer `Buffer DecodedNote'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_ufvk_decode as rustWrapperUfvkDecode {# fun unsafe rust_wrapper_ufvk_decode as rustWrapperUfvkDecode
{ toBorshVar* `BS.ByteString'& { toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer UnifiedFullViewingKey'& , getVarBuffer `Buffer UnifiedFullViewingKey'&
@ -82,7 +123,172 @@ import ZcashHaskell.Types
{# fun unsafe rust_wrapper_orchard_note_decrypt as rustWrapperOrchardNoteDecode {# fun unsafe rust_wrapper_orchard_note_decrypt as rustWrapperOrchardNoteDecode
{ toBorshVar* `BS.ByteString'& { toBorshVar* `BS.ByteString'&
, toBorshVar* `OrchardAction'& , toBorshVar* `OrchardAction'&
, getVarBuffer `Buffer OrchardDecodedAction'& , getVarBuffer `Buffer DecodedNote'&
} }
-> `()' -> `()'
#} #}
{# fun unsafe rust_wrapper_orchard_note_decrypt_sk as rustWrapperOrchardNoteDecodeSK
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `OrchardAction'&
, `Bool'
, getVarBuffer `Buffer DecodedNote'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_tx_parse as rustWrapperTxParse
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer [ShieldedOutput]'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_tx_read as rustWrapperTxRead
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer RawZebraTx'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_gen_seed_phrase as rustWrapperGenSeedPhrase
{ getVarBuffer `Buffer Phrase'& } -> `()'
#}
{# fun unsafe rust_wrapper_recover_seed as rustWrapperGetSeed
{ toBorshVar* `Phrase'&
, getVarBuffer `Buffer Seed'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_sapling_spendingkey as rustWrapperSaplingSpendingkey
{ toBorshVar* `BS.ByteString'&
, `Word32'
, `Word32'
, getVarBuffer `Buffer (BS.ByteString)'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_sapling_paymentaddress as rustWrapperSaplingPaymentAddress
{ toBorshVar* `BS.ByteString'&
, `Word32'
, getVarBuffer `Buffer (BS.ByteString)'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_sapling_chgpaymentaddress as rustWrapperSaplingChgPaymentAddress
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer (BS.ByteString)'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_derive_orchard_spending_key as rustWrapperGenOrchardSpendKey
{ toBorshVar* `BS.ByteString'&
, `Word32'
, `Word32'
, getVarBuffer `Buffer (BS.ByteString)'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_derive_orchard_receiver as rustWrapperGenOrchardReceiver
{ toBorshVar* `BS.ByteString'&
, `Word32'
, `Bool'
, getVarBuffer `Buffer (BS.ByteString)'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_read_sapling_commitment_tree as rustWrapperReadSaplingCommitmentTree
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_read_sapling_witness as rustWrapperReadSaplingWitness
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun pure unsafe rust_wrapper_read_sapling_position as rustWrapperReadSaplingPosition
{ toBorshVar* `BS.ByteString'&
}
-> `Word64'
#}
{# fun unsafe rust_wrapper_bech32_encode as rustWrapperBech32Encode
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer (T.Text)'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_decode_sapling_address as rustWrapperDecodeSaplingAddress
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer (BS.ByteString)'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_read_orchard_commitment_tree as rustWrapperReadOrchardCommitmentTree
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_read_orchard_witness as rustWrapperReadOrchardWitness
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun pure unsafe rust_wrapper_read_orchard_position as rustWrapperReadOrchardPosition
{ toBorshVar* `BS.ByteString'&
}
-> `Word64'
#}
{# fun unsafe rust_wrapper_update_sapling_witness as rustWrapperUpdateSaplingWitness
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `[BS.ByteString]'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_update_orchard_witness as rustWrapperUpdateOrchardWitness
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `[BS.ByteString]'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_create_transaction as rustWrapperCreateTx
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
, toBorshVar* `[TransparentTxSpend]'&
, toBorshVar* `[SaplingTxSpend]'&
, toBorshVar* `[OrchardTxSpend]'&
, toBorshVar* `[OutgoingNote]'&
, toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
, `Bool'
, `Word64'
, `Bool'
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}

38
src/ZcashHaskell/Keys.hs Normal file
View file

@ -0,0 +1,38 @@
-- Copyright 2022-2024 Vergara Technologies LLC
-- This file is part of Zcash-Haskell.
--
-- |
-- Module : ZcashHaskell.Keys
-- Copyright : 2022-2024 Vergara Technologies
-- License : MIT
--
-- Maintainer : pitmutt@vergara.tech
-- Stability : experimental
-- Portability : unknown
--
-- Functions to generate keys for the Zcash blockchain
--
module ZcashHaskell.Keys where
import C.Zcash (rustWrapperGenSeedPhrase, rustWrapperGetSeed)
import qualified Data.ByteString as BS
import qualified Data.Text as T
import Foreign.Rust.Marshall.Variable
( withBorshVarBuffer
, withPureBorshVarBuffer
)
import ZcashHaskell.Types (Phrase, Seed(..), ToBytes(..))
-- | Generate a random seed that can be used to generate private keys for shielded addresses and transparent addresses.
generateWalletSeedPhrase :: IO Phrase
generateWalletSeedPhrase = withBorshVarBuffer rustWrapperGenSeedPhrase
-- | Derive a cryptographic seed from the given seed phrase.
getWalletSeed :: Phrase -> Maybe Seed
getWalletSeed p =
if BS.length (getBytes result) > 0
then Just result
else Nothing
where
result :: Seed
result = (withPureBorshVarBuffer . rustWrapperGetSeed) p

View file

@ -1,19 +1,140 @@
{-# LANGUAGE OverloadedStrings #-}
-- Copyright 2022-2024 Vergara Technologies LLC
--
-- This file is part of Zcash-Haskell.
--
-- |
-- Module : ZcashHaskell.Orchard
-- Copyright : 2022-2024 Vergara Technologies
-- License : MIT
--
-- Maintainer : rene@vergara.network
-- Stability : experimental
-- Portability : unknown
--
-- Functions to interact with the Orchard shielded pool of the Zcash blockchain.
--
module ZcashHaskell.Orchard where module ZcashHaskell.Orchard where
import C.Zcash import C.Zcash
( rustWrapperIsUA ( rustWrapperGenOrchardReceiver
, rustWrapperGenOrchardSpendKey
, rustWrapperOrchardCheck
, rustWrapperOrchardNoteDecode , rustWrapperOrchardNoteDecode
, rustWrapperOrchardNoteDecodeSK
, rustWrapperReadOrchardCommitmentTree
, rustWrapperReadOrchardPosition
, rustWrapperReadOrchardWitness
, rustWrapperUADecode
, rustWrapperUfvkDecode , rustWrapperUfvkDecode
, rustWrapperUpdateOrchardWitness
) )
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C
import Data.HexString (HexString(..), fromRawBytes, toBytes)
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Data.Word
import Foreign.Rust.Marshall.Variable import Foreign.Rust.Marshall.Variable
import ZcashHaskell.Types import ZcashHaskell.Types
import ZcashHaskell.Utils (encodeBech32, encodeBech32m, f4Jumble)
-- | Check if given bytestring is a valid encoded unified address -- | Derives an Orchard spending key for the given seed and account ID
isValidUnifiedAddress :: BS.ByteString -> Bool genOrchardSpendingKey ::
isValidUnifiedAddress = rustWrapperIsUA Seed -- ^ The cryptographic seed for the wallet
-> CoinType -- ^ The coin type constant
-> AccountId -- ^ The index of the account to be used
-> Maybe OrchardSpendingKey
genOrchardSpendingKey s coinType accountId =
if BS.length k /= 32
then Nothing
else Just $ OrchardSpendingKey k
where
k =
withPureBorshVarBuffer $
rustWrapperGenOrchardSpendKey
(getBytes s)
(getValue coinType)
(fromIntegral accountId)
-- | Attempt to decode the given bytestring into a Unified Full Viewing Key -- | Derives an Orchard receiver for the given spending key and index
genOrchardReceiver ::
Int -- ^ The index of the address to be created
-> Scope -- ^ `External` for wallet addresses, `Internal` for change addresses
-> OrchardSpendingKey -- ^ The spending key
-> Maybe OrchardReceiver
genOrchardReceiver i scope osk =
if BS.length k /= 43
then Nothing
else Just $ OrchardReceiver k
where
k =
withPureBorshVarBuffer $
rustWrapperGenOrchardReceiver
(getBytes osk)
(fromIntegral i)
(scope == External)
-- | Checks if given bytestring is a valid encoded unified address
isValidUnifiedAddress :: BS.ByteString -> Maybe UnifiedAddress
isValidUnifiedAddress str =
case raw_net decodedAddress of
0 -> Nothing
_ -> Just $ makeUA decodedAddress
where
decodedAddress = (withPureBorshVarBuffer . rustWrapperUADecode) str
whichNet =
case raw_net decodedAddress of
1 -> MainNet
2 -> TestNet
3 -> RegTestNet
makeUA x =
UnifiedAddress
whichNet
(if BS.length (raw_o x) == 43
then Just $ OrchardReceiver (raw_o x)
else Nothing)
(if BS.length (raw_s x) == 43
then Just $ SaplingReceiver (raw_s x)
else Nothing)
(if not (BS.null (raw_t x))
then Just $ TransparentReceiver P2PKH (fromRawBytes $ raw_t x)
else if not (BS.null (raw_to x))
then Just $ TransparentReceiver P2SH (fromRawBytes $ raw_to x)
else Nothing)
-- | Encode a 'UnifiedAddress' per [ZIP-316](https://zips.z.cash/zip-0316)
encodeUnifiedAddress :: UnifiedAddress -> T.Text
encodeUnifiedAddress ua = encodeBech32m (E.encodeUtf8 hr) b
where
hr =
case ua_net ua of
MainNet -> uniPaymentAddressHrp
TestNet -> uniTestPaymentAddressHrp
b = f4Jumble $ tReceiver <> sReceiver <> oReceiver <> padding
tReceiver =
case t_rec ua of
Nothing -> BS.empty
Just t ->
case tr_type t of
P2SH -> packReceiver 0x01 $ Just $ toBytes $ tr_bytes t
P2PKH -> packReceiver 0x00 $ Just $ toBytes $ tr_bytes t
sReceiver = packReceiver 0x02 $ getBytes <$> s_rec ua
oReceiver = packReceiver 0x03 $ getBytes <$> o_rec ua
padding = E.encodeUtf8 $ T.justifyLeft 16 '\NUL' hr
packReceiver :: Word8 -> Maybe BS.ByteString -> BS.ByteString
packReceiver typeCode receiver' =
case receiver' of
Just receiver ->
if BS.length receiver > 1
then BS.singleton typeCode `BS.append`
(BS.singleton . toEnum . BS.length) receiver `BS.append`
receiver
else BS.empty
Nothing -> BS.empty
-- | Attempts to decode the given bytestring into a Unified Full Viewing Key
decodeUfvk :: BS.ByteString -> Maybe UnifiedFullViewingKey decodeUfvk :: BS.ByteString -> Maybe UnifiedFullViewingKey
decodeUfvk str = decodeUfvk str =
case net decodedKey of case net decodedKey of
@ -22,9 +143,14 @@ decodeUfvk str =
where where
decodedKey = (withPureBorshVarBuffer . rustWrapperUfvkDecode) str decodedKey = (withPureBorshVarBuffer . rustWrapperUfvkDecode) str
-- | Check if the given UVK matches the UA given
matchOrchardAddress :: BS.ByteString -> BS.ByteString -> Bool
matchOrchardAddress = rustWrapperOrchardCheck
-- | Attempts to decode the given @OrchardAction@ using the given @UnifiedFullViewingKey@.
decryptOrchardAction :: decryptOrchardAction ::
OrchardAction -> UnifiedFullViewingKey -> Maybe OrchardDecodedAction UnifiedFullViewingKey -> OrchardAction -> Maybe DecodedNote
decryptOrchardAction encAction key = decryptOrchardAction key encAction =
case a_value decodedAction of case a_value decodedAction of
0 -> Nothing 0 -> Nothing
_ -> Just decodedAction _ -> Just decodedAction
@ -32,3 +158,71 @@ decryptOrchardAction encAction key =
decodedAction = decodedAction =
withPureBorshVarBuffer $ withPureBorshVarBuffer $
rustWrapperOrchardNoteDecode (o_key key) encAction rustWrapperOrchardNoteDecode (o_key key) encAction
getSaplingFromUA :: BS.ByteString -> Maybe T.Text
getSaplingFromUA uadd = do
let a = isValidUnifiedAddress uadd
case a of
Nothing -> Nothing
Just a -> do
let sraw = s_rec a
case sraw of
Nothing -> Nothing
Just sraw -> do
let net = ua_net a
case net of
MainNet ->
Just $ encodeBech32 (C.pack sapPaymentAddressHrp) (getBytes sraw)
TestNet ->
Just $
encodeBech32 (C.pack sapTestPaymentAddressHrp) (getBytes sraw)
-- | Attemtps to decode the given @OrchardAction@ using the given @OrchardSpendingKey@
decryptOrchardActionSK ::
OrchardSpendingKey -> Scope -> OrchardAction -> Maybe DecodedNote
decryptOrchardActionSK sk scope oa =
case a_value decodedAction of
0 -> Nothing
_ -> Just decodedAction
where
decodedAction =
withPureBorshVarBuffer $
rustWrapperOrchardNoteDecodeSK (getBytes sk) oa (scope == External)
-- | Update a Orchard commitment tree
updateOrchardCommitmentTree ::
OrchardCommitmentTree -- ^ the base tree
-> HexString -- ^ the new note commitment
-> Maybe OrchardCommitmentTree
updateOrchardCommitmentTree tree cmx =
if BS.length (hexBytes updatedTree) > 1
then Just $ OrchardCommitmentTree updatedTree
else Nothing
where
updatedTree =
withPureBorshVarBuffer $
rustWrapperReadOrchardCommitmentTree
(hexBytes $ orchTree tree)
(hexBytes cmx)
-- | Get the Orchard incremental witness from a commitment tree
getOrchardWitness :: OrchardCommitmentTree -> Maybe OrchardWitness
getOrchardWitness tree =
if BS.length (hexBytes wit) > 1
then Just $ OrchardWitness wit
else Nothing
where
wit =
withPureBorshVarBuffer $
rustWrapperReadOrchardWitness (hexBytes $ orchTree tree)
-- | Get the Sapling note position from a witness
getOrchardNotePosition :: OrchardWitness -> Integer
getOrchardNotePosition =
fromIntegral . rustWrapperReadOrchardPosition . hexBytes . orchWit
updateOrchardWitness :: OrchardWitness -> [HexString] -> OrchardWitness
updateOrchardWitness wit cmus =
OrchardWitness $
withPureBorshVarBuffer $
rustWrapperUpdateOrchardWitness (toBytes $ orchWit wit) (map toBytes cmus)

View file

@ -1,20 +1,252 @@
-- Copyright 2022-2024 Vergara Technologies LLC
--
-- This file is part of Zcash-Haskell.
--
-- |
-- Module : ZcashHaskell.Sapling
-- Copyright : 2022-2024 Vergara Technologies
-- License : MIT
--
-- Maintainer : pitmutt@vergara.tech
-- Stability : experimental
-- Portability : unknown
--
-- Functions to interact with the Sapling shielded pool of the Zcash blockchain.
--
{-# LANGUAGE OverloadedStrings #-}
module ZcashHaskell.Sapling where module ZcashHaskell.Sapling where
import C.Zcash import C.Zcash
( rustWrapperIsShielded ( rustWrapperDecodeSaplingAddress
, rustWrapperIsShielded
, rustWrapperReadSaplingCommitmentTree
, rustWrapperReadSaplingPosition
, rustWrapperReadSaplingWitness
, rustWrapperSaplingCheck , rustWrapperSaplingCheck
, rustWrapperSaplingChgPaymentAddress
, rustWrapperSaplingDecodeEsk
, rustWrapperSaplingNoteDecode
, rustWrapperSaplingPaymentAddress
, rustWrapperSaplingSpendingkey
, rustWrapperSaplingVkDecode , rustWrapperSaplingVkDecode
, rustWrapperTxParse
, rustWrapperUpdateSaplingWitness
) )
import Data.Aeson
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C
import Data.HexString (HexString(..), fromText, hexString, toBytes, toText)
import qualified Data.Text as T
import Data.Word
import Foreign.Rust.Marshall.Variable
( withPureBorshVarBuffer
, withPureBorshVarBuffer
)
import ZcashHaskell.Types
import ZcashHaskell.Utils (decodeBech32, encodeBech32, encodeBech32m)
-- | Check if given bytesting is a valid encoded shielded address -- | Check if given bytesting is a valid encoded shielded address
isValidShieldedAddress :: BS.ByteString -> Bool isValidShieldedAddress :: BS.ByteString -> Bool
isValidShieldedAddress = rustWrapperIsShielded isValidShieldedAddress = rustWrapperIsShielded
getShieldedOutputs :: HexString -> [ShieldedOutput]
getShieldedOutputs t = withPureBorshVarBuffer $ rustWrapperTxParse $ toBytes t
serializeShieldedOutput :: ShieldedOutput -> BS.ByteString
serializeShieldedOutput so =
hexBytes . fromText $
toText (s_cv so) <>
toText (s_cmu so) <>
toText (s_ephKey so) <>
toText (s_encCipherText so) <>
toText (s_outCipherText so) <> toText (s_proof so)
-- | Check if given bytestring is a valid Sapling viewing key -- | Check if given bytestring is a valid Sapling viewing key
isValidSaplingViewingKey :: BS.ByteString -> Bool isValidSaplingViewingKey :: BS.ByteString -> Bool
isValidSaplingViewingKey = rustWrapperSaplingVkDecode isValidSaplingViewingKey k =
case hrp decodedKey of
"zxviews" -> rustWrapperSaplingVkDecode $ bytes decodedKey
_ -> False
where
decodedKey = decodeBech32 k
-- | Check if the given bytestring for the Sapling viewing key matches the second bytestring for the address -- | Check if the given bytestring for the Sapling viewing key matches the second bytestring for the address
matchSaplingAddress :: BS.ByteString -> BS.ByteString -> Bool matchSaplingAddress :: BS.ByteString -> BS.ByteString -> Bool
matchSaplingAddress = rustWrapperSaplingCheck matchSaplingAddress = rustWrapperSaplingCheck
-- | Attempt to decode the given raw tx with the given Sapling viewing key
decodeSaplingOutput :: BS.ByteString -> ShieldedOutput -> Maybe DecodedNote
decodeSaplingOutput key out =
case a_value decodedAction of
0 -> Nothing
_ -> Just decodedAction
where
decodedAction =
withPureBorshVarBuffer $ rustWrapperSaplingNoteDecode key out
instance FromJSON RawTxResponse where
parseJSON =
withObject "RawTxResponse" $ \obj -> do
i <- obj .: "txid"
o <- obj .:? "orchard"
h <- obj .: "hex"
ht <- obj .: "height"
c <- obj .: "confirmations"
b <- obj .: "blocktime"
sSpend <- obj .: "vShieldedSpend"
sOut <- obj .: "vShieldedOutput"
case o of
Nothing ->
pure $
RawTxResponse
i
h
sSpend
(if not (null (sOut :: [Object]))
then getShieldedOutputs h
else [])
[]
ht
c
b
Just o' -> do
a <- o' .: "actions"
pure $
RawTxResponse
i
h
sSpend
(if not (null sOut)
then getShieldedOutputs h
else [])
a
ht
c
b
-- | Attempt to decode the given raw tx with the given Sapling spending key
decodeSaplingOutputEsk ::
SaplingSpendingKey
-> ShieldedOutput
-> ZcashNet
-> Scope
-> Integer
-> Maybe DecodedNote
decodeSaplingOutputEsk key out znet scope pos =
case a_value decodedAction of
0 -> Nothing
_ -> Just decodedAction
where
decodedAction =
withPureBorshVarBuffer $
rustWrapperSaplingDecodeEsk
(getBytes key)
out
(scope == External)
(znet == MainNet)
(fromIntegral pos)
-- | Attempts to obtain a sapling SpendingKey using a HDSeed
genSaplingSpendingKey :: Seed -> CoinType -> Int -> Maybe SaplingSpendingKey
genSaplingSpendingKey seed c i = do
if BS.length res == 169
then Just $ SaplingSpendingKey res
else Nothing
where
res =
withPureBorshVarBuffer
(rustWrapperSaplingSpendingkey
(getBytes seed)
(fromIntegral $ getValue c)
(fromIntegral i))
-- | Attempts to generate a sapling Payment Address using an ExtendedSpendingKey and a Diversifier Index
genSaplingPaymentAddress :: Int -> SaplingSpendingKey -> Maybe SaplingReceiver
genSaplingPaymentAddress i extspk =
if BS.length res == 43
then Just $ SaplingReceiver res
else Nothing
where
res =
withPureBorshVarBuffer
(rustWrapperSaplingPaymentAddress
(getBytes extspk)
(fromIntegral (i * 111)))
-- | Generate an internal Sapling address
genSaplingInternalAddress :: SaplingSpendingKey -> Maybe SaplingReceiver
genSaplingInternalAddress sk =
if BS.length res == 43
then Just $ SaplingReceiver res
else Nothing
where
res =
withPureBorshVarBuffer (rustWrapperSaplingChgPaymentAddress $ getBytes sk)
-- | Update a Sapling commitment tree
updateSaplingCommitmentTree ::
SaplingCommitmentTree -- ^ the base tree
-> HexString -- ^ the new note commitment
-> Maybe SaplingCommitmentTree
updateSaplingCommitmentTree tree cmu =
if BS.length (hexBytes updatedTree) > 1
then Just $ SaplingCommitmentTree updatedTree
else Nothing
where
updatedTree =
withPureBorshVarBuffer $
rustWrapperReadSaplingCommitmentTree
(hexBytes $ sapTree tree)
(hexBytes cmu)
-- | Get the Sapling incremental witness from a commitment tree
getSaplingWitness :: SaplingCommitmentTree -> Maybe SaplingWitness
getSaplingWitness tree =
if BS.length (hexBytes wit) > 1
then Just $ SaplingWitness wit
else Nothing
where
wit =
withPureBorshVarBuffer $
rustWrapperReadSaplingWitness (hexBytes $ sapTree tree)
-- | Get the Sapling note position from a witness
getSaplingNotePosition :: SaplingWitness -> Integer
getSaplingNotePosition =
fromIntegral . rustWrapperReadSaplingPosition . hexBytes . sapWit
updateSaplingWitness :: SaplingWitness -> [HexString] -> SaplingWitness
updateSaplingWitness wit cmus =
SaplingWitness $
withPureBorshVarBuffer $
rustWrapperUpdateSaplingWitness (toBytes $ sapWit wit) (map toBytes cmus)
-- | Encode a SaplingReceiver into HRF text
encodeSaplingAddress :: ZcashNet -> SaplingReceiver -> Maybe T.Text
encodeSaplingAddress net sr = do
case net of
MainNet -> Just $ encodeBech32 (C.pack sapPaymentAddressHrp) (getBytes sr)
TestNet ->
Just $ encodeBech32 (C.pack sapTestPaymentAddressHrp) (getBytes sr)
-- | Helper to get de Nework Id from FFI response
getNetId :: [Word8] -> ZcashNet
getNetId [x] = do
case x of
1 -> MainNet
2 -> TestNet
-- | decode a Sapling address
decodeSaplingAddress :: BS.ByteString -> Maybe SaplingAddress
decodeSaplingAddress sapling_address = do
if BS.length sa > 1
then do
let sa0 = BS.unpack sa
Just $
SaplingAddress (getNetId (take 1 sa0)) $
SaplingReceiver (BS.pack (drop 1 sa0))
else Nothing
where
sa =
withPureBorshVarBuffer $ rustWrapperDecodeSaplingAddress sapling_address

View file

@ -0,0 +1,212 @@
-- Copyright 2022-2024 Vergara Technologies LLC
--
-- This file is part of Zcash-Haskell.
--
-- |
-- Module : ZcashHaskell.Transparent
-- Copyright : 2022-2024 Vergara Technologies
-- License : MIT
--
-- Maintainer : pitmutt@vergara.tech
-- Stability : experimental
-- Portability : unknown
--
-- Functions to interact with the transparent addresses in the Zcash blockchain
--
module ZcashHaskell.Transparent where
import Control.Exception (throwIO)
import Crypto.Hash
import Crypto.Secp256k1
import qualified Data.ByteArray as BA
import qualified Data.ByteString as BS
import Data.ByteString.Base58 (bitcoinAlphabet, decodeBase58, encodeBase58)
import qualified Data.ByteString.Char8 as BC
import Data.Char (chr)
import Data.HexString
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Data.Word
import Haskoin.Address (Address(..))
import qualified Haskoin.Crypto.Hash as H
import Haskoin.Crypto.Keys.Extended
import ZcashHaskell.Types
-- ( AccountId
-- , CoinType(..)
-- , Scope(..)
-- , Seed(..)
-- , ToBytes(..)
-- , TransparentAddress(..)
-- , TransparentReceiver(..)
-- , TransparentSpendingKey(..)
-- , TransparentType(..)
-- , ZcashNet(..)
-- , getTransparentPrefix
-- , getValue
-- )
import ZcashHaskell.Utils (decodeBech32, encodeBech32m)
-- | Required for `TransparentReceiver` encoding and decoding
sha256 :: BS.ByteString -> BS.ByteString
sha256 bs = BA.convert (hash bs :: Digest SHA256)
-- | Encodes a `TransparentReceiver` into the human-readable format per the Zcash Protocol section 5.6.1.1
encodeTransparentReceiver ::
ZcashNet -- ^ The network, `MainNet` or `TestNet`
-> TransparentReceiver -- ^ The address to encode
-> T.Text
encodeTransparentReceiver zNet t =
encodeTransparent' (getTransparentPrefix zNet (tr_type t)) $
toBytes $ tr_bytes t
where
encodeTransparent' :: (Word8, Word8) -> BS.ByteString -> T.Text
encodeTransparent' (a, b) h =
E.decodeUtf8 $ encodeBase58 bitcoinAlphabet $ digest <> BS.take 4 checksum
where
digest = BS.pack [a, b] <> h
checksum = sha256 $ sha256 digest
-- | Generate an Extended Private Key from a known HDSeed.
genTransparentPrvKey ::
Seed -- ^ The cryptographic seed of the wallet
-> CoinType -- ^ The coin type constant to be used
-> AccountId -- ^ The index of the account to be used
-> IO TransparentSpendingKey
genTransparentPrvKey hdseed ctype accid = do
let coin = getValue ctype
ioCtx <- createContext
let path = Deriv :| 44 :| coin :| fromIntegral accid :: DerivPath
let prvKey = makeXPrvKey $ getBytes hdseed
return $ derivePath ioCtx path prvKey
-- | Generate a transparent receiver
genTransparentReceiver ::
Int -- ^ The index of the address to be created
-> Scope -- ^ `External` for wallet addresses or `Internal` for change addresses
-> XPrvKey -- ^ The transparent private key
-> IO TransparentReceiver
genTransparentReceiver i scope xprvk = do
ioCtx <- createContext
let s =
case scope of
External -> 0
Internal -> 1
let path = Deriv :/ s :/ fromIntegral i :: DerivPath
let childPrvKey = derivePath ioCtx path xprvk
let childPubKey = deriveXPubKey ioCtx childPrvKey
let x = xPubAddr ioCtx childPubKey
case x of
PubKeyAddress k -> return $ TransparentReceiver P2PKH $ fromBinary k
ScriptAddress j -> return $ TransparentReceiver P2SH $ fromBinary j
_anyOtherKind -> throwIO $ userError "Unsupported transparent address type"
-- | Generate a transparent receiver
genTransparentSecretKey ::
Int -- ^ The index of the address to be created
-> Scope -- ^ `External` for wallet addresses or `Internal` for change addresses
-> XPrvKey -- ^ The transparent private key
-> IO TransparentSpendingKey
genTransparentSecretKey i scope xprvk = do
ioCtx <- createContext
let s =
case scope of
External -> 0
Internal -> 1
let path = Deriv :/ s :/ fromIntegral i :: DerivPath
return $ derivePath ioCtx path xprvk
-- | decode a Transparent Address in HRF and return a TransparentAddress object
decodeTransparentAddress :: BS.ByteString -> Maybe TransparentAddress
decodeTransparentAddress taddress = do
if BS.length taddress < 34
then Nothing -- Not a valid transparent address
else do
let maybeDecoded = decodeBase58 bitcoinAlphabet taddress
case maybeDecoded of
Nothing -> Nothing
Just decoded -> do
let digest = BS.take 22 decoded
let chksum = BS.drop 22 decoded
let chksumd = BS.take 4 (sha256 $ sha256 digest)
if chksum /= chksumd
then Nothing -- Invalid address ( invalid checksum )
-- build the TransparentAddress Object
else do
let addressType = BS.take 2 digest
let transparentReceiver = BS.drop 2 digest
let fb = BS.index addressType 0
let sb = BS.index addressType 1
case fb of
28 ->
case sb of
189 ->
Just $
TransparentAddress MainNet $
TransparentReceiver
P2SH
(fromRawBytes transparentReceiver)
186 ->
Just $
TransparentAddress TestNet $
TransparentReceiver
P2SH
(fromRawBytes transparentReceiver)
184 ->
Just $
TransparentAddress MainNet $
TransparentReceiver
P2PKH
(fromRawBytes transparentReceiver)
_ -> Nothing
29 ->
if sb == 37
then Just $
TransparentAddress TestNet $
TransparentReceiver
P2PKH
(fromRawBytes transparentReceiver)
else Nothing
_ -> Nothing
-- | Encode an Exchange Addresss into HRF from TransparentReceiver
encodeExchangeAddress :: ZcashNet -> TransparentReceiver -> Maybe T.Text
encodeExchangeAddress net tr = do
case (tr_type tr) of
P2PKH -> do
case net of
MainNet -> do
let vhash = encodeBech32m (BC.pack "tex") (toBytes (tr_bytes tr))
Just vhash
TestNet -> do
let vhash = encodeBech32m (BC.pack "textest") (toBytes (tr_bytes tr))
Just vhash
_ -> Nothing
-- | Decode an Exchange Address into a ExchangeAddress
decodeExchangeAddress :: T.Text -> Maybe ExchangeAddress
decodeExchangeAddress ex = do
if (T.length ex) > 1
then do
let rawd = decodeBech32 (E.encodeUtf8 ex)
let tMain = BS.unpack (BC.pack "tex")
let tTest = BS.unpack (BC.pack "textest")
let tFail = BS.unpack (BC.pack "fail")
let hr = BS.unpack (hrp rawd)
if hr /= tFail
then do
let transparentReceiver = bytes rawd
if hr == tMain
then Just $
ExchangeAddress MainNet $
TransparentReceiver P2PKH (fromRawBytes transparentReceiver)
else do
if hr == tTest
then Just $
ExchangeAddress TestNet $
TransparentReceiver
P2PKH
(fromRawBytes transparentReceiver)
else Nothing
else Nothing
else Nothing

View file

@ -1,75 +1,733 @@
-- Copyright 2022-2024 Vergara Technologies LLC
--
-- This file is part of Zcash-Haskell.
--
-- |
-- Module : ZcashHaskell.Types
-- Copyright : 2022-2024 Vergara Technologies
-- License : MIT
--
-- Maintainer : pitmutt@vergara.tech
-- Stability : experimental
-- Portability : unknown
--
-- The types used by the ZcashHaskell library to interact with the Zcash blockchain
--
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GeneralisedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE DerivingVia #-}
{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverloadedStrings #-}
module ZcashHaskell.Types where module ZcashHaskell.Types where
import qualified Data.ByteString as BS
import Codec.Borsh import Codec.Borsh
import Data.Word import Crypto.Hash
import Data.Aeson
import qualified Data.ByteArray as BA
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C
import qualified Data.ByteString.Lazy.UTF8 as US
import qualified Data.ByteString.Short as BS (ShortByteString, toShort)
import Data.HexString
import Data.Int import Data.Int
import Data.Maybe (fromJust, fromMaybe)
import Data.Structured import Data.Structured
import qualified Generics.SOP as SOP import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Data.Word
import qualified GHC.Generics as GHC import qualified GHC.Generics as GHC
import qualified Generics.SOP as SOP
import Haskoin.Address (Address)
import qualified Haskoin.Crypto.Hash as H (Hash256(..))
import Haskoin.Crypto.Keys.Extended (XPrvKey)
import qualified Haskoin.Transaction.Common as H
data RawData = RawData { hrp :: BS.ByteString, bytes :: BS.ByteString} -- * General
deriving stock (Prelude.Show, GHC.Generic) --
-- | A seed for generating private keys
newtype Seed =
Seed BS.ByteString
deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct Seed
instance ToBytes Seed where
getBytes (Seed x) = x
-- | A mnemonic phrase used to derive seeds
newtype Phrase =
Phrase C.ByteString
deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct Phrase
instance ToBytes Phrase where
getBytes (Phrase x) = x
-- | Scope for addresses/receivers
data Scope
= External -- ^ Addresses used publically to receive payments
| Internal -- ^ Addresses used internally by wallets for change and shielding
deriving (Eq, Prelude.Show, Read)
-- | Type to represent data after Bech32 decoding
data RawData = RawData
{ hrp :: !BS.ByteString -- ^ Human-readable part of the Bech32 encoding
, bytes :: !BS.ByteString -- ^ Decoded bytes
} deriving stock (Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show) deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawData deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawData
data UnifiedFullViewingKey = -- | Type for the different networks of the Zcash blockchain
UnifiedFullViewingKey data ZcashNet
{ net :: Word8 = MainNet
, o_key :: BS.ByteString | TestNet
, s_key :: BS.ByteString | RegTestNet
, t_key :: BS.ByteString deriving (Eq, Prelude.Show, Read)
}
deriving stock (Eq, Prelude.Show, GHC.Generic) type AccountId = Int
-- | Function to get the Base58 prefix for encoding a 'TransparentReceiver'
getTransparentPrefix :: ZcashNet -> TransparentType -> (Word8, Word8)
getTransparentPrefix n t =
case t of
P2SH ->
case n of
MainNet -> (0x1c, 0xbd)
_ -> (0x1c, 0xba)
P2PKH ->
case n of
MainNet -> (0x1c, 0xb8)
_ -> (0x1d, 0x25)
-- ** Constants
-- | Type for coin types on the different networks
data CoinType
= MainNetCoin
| TestNetCoin
| RegTestNetCoin
deriving (Eq, Prelude.Show, Ord)
getValue :: CoinType -> Word32
getValue c =
case c of
MainNetCoin -> 133
TestNetCoin -> 1
RegTestNetCoin -> 1
-- | A Zcash transaction
data Transaction = Transaction
{ tx_id :: !HexString
, tx_height :: !Int
, tx_conf :: !Int
, tx_expiry :: !Int
, tx_transpBundle :: !(Maybe TransparentBundle)
, tx_saplingBundle :: !(Maybe SaplingBundle)
, tx_orchardBundle :: !(Maybe OrchardBundle)
} deriving (Prelude.Show, Eq, Read)
-- | The transparent portion of a Zcash transaction
data TransparentBundle = TransparentBundle
{ tb_vin :: ![H.TxIn]
, tb_vout :: ![H.TxOut]
, tb_coinbase :: !Bool
} deriving (Eq, Prelude.Show, Read)
-- | Read a raw transparent bundle into the Haskell type
fromRawTBundle :: RawTBundle -> Maybe TransparentBundle
fromRawTBundle rtb =
if ztb_empty rtb
then Nothing
else Just $
TransparentBundle
(map fromRawTxIn $ ztb_vin rtb)
(map fromRawTxOut $ ztb_vout rtb)
(ztb_coinbase rtb)
fromRawTxIn :: RawTxIn -> H.TxIn
fromRawTxIn t = H.TxIn op (rti_script t) (rti_seq t)
where
op =
if rop_hash (rti_outpoint t) ==
"\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL"
then H.nullOutPoint
else H.OutPoint
((fromJust .
H.hexToTxHash . toText . fromRawBytes . rop_hash . rti_outpoint)
t)
(rop_n $ rti_outpoint t)
fromRawTxOut :: RawTxOut -> H.TxOut
fromRawTxOut t = H.TxOut (rto_amt t) (rto_script t)
-- *** Constants for Sapling Human-readable part
sapExtSpendingKeyHrp = "secret-extended-key-main" :: String
sapExtFullViewingKeyHrp = "zxviews" :: String
sapPaymentAddressHrp = "zs" :: String
sapTestExtSpendingKeyHrp = "secret-extended-key-test" :: String
sapTestExtFullViewingKeyHrp = "zxviewtestsapling" :: String
sapTestPaymentAddressHrp = "ztestsapling" :: String
-- *** Constants for Unified Human-readable part
uniPaymentAddressHrp = "u" :: T.Text
uniFullViewingKeyHrp = "uview" :: T.Text
uniIncomingViewingKeyHrp = "uivk" :: T.Text
uniTestPaymentAddressHrp = "utest" :: T.Text
uniTestFullViewingKeyHrp = "uviewtest" :: T.Text
uniTestIncomingViewingKeyHrp = "uivktest" :: T.Text
-- * RPC
-- | A type to model Zcash RPC calls
data RpcCall = RpcCall
{ jsonrpc :: !T.Text
, callId :: !T.Text
, method :: !T.Text
, parameters :: ![Data.Aeson.Value]
} deriving stock (Prelude.Show, GHC.Generic)
instance ToJSON RpcCall where
toJSON (RpcCall j c m p) =
object ["jsonrpc" .= j, "id" .= c, "method" .= m, "params" .= p]
-- | A type to model the response of the Zcash RPC
data RpcResponse r = MakeRpcResponse
{ err :: !(Maybe RpcError)
, respId :: !T.Text
, result :: !(Maybe r)
} deriving stock (Prelude.Show, GHC.Generic)
deriving anyclass (ToJSON)
instance (FromJSON r) => FromJSON (RpcResponse r) where
parseJSON =
withObject "RpcResponse" $ \obj -> do
e <- obj .:? "error"
i <- obj .: "id"
r <- obj .:? "result"
pure $ MakeRpcResponse e i r
-- | A type to model the errors from the Zcash RPC
data RpcError = RpcError
{ ecode :: !Double
, emessage :: !T.Text
} deriving stock (Prelude.Show, GHC.Generic)
deriving anyclass (ToJSON)
instance FromJSON RpcError where
parseJSON =
withObject "RpcError" $ \obj -> do
c <- obj .: "code"
m <- obj .: "message"
pure $ RpcError c m
-- ** `zcashd`
-- | Type to represent response from the `zcashd` RPC `getblock` method
data BlockResponse = BlockResponse
{ bl_confirmations :: !Integer -- ^ Block confirmations
, bl_height :: !Integer -- ^ Block height
, bl_time :: !Integer -- ^ Block time
, bl_txs :: ![HexString] -- ^ List of transaction IDs in the block
} deriving (Prelude.Show, Eq)
instance FromJSON BlockResponse where
parseJSON =
withObject "BlockResponse" $ \obj -> do
c <- obj .: "confirmations"
h <- obj .: "height"
t <- obj .:? "time"
txs <- obj .: "tx"
pure $ BlockResponse c h (fromMaybe 0 t) txs
-- | Type to represent response from the `zcashd` RPC `getrawtransaction`
data RawTxResponse = RawTxResponse
{ rt_id :: !HexString
, rt_hex :: !HexString
, rt_shieldedSpends :: ![ShieldedSpend]
, rt_shieldedOutputs :: ![ShieldedOutput]
, rt_orchardActions :: ![OrchardAction]
, rt_blockheight :: !Integer
, rt_confirmations :: !Integer
, rt_blocktime :: !Integer
} deriving (Prelude.Show, Eq, Read)
-- ** `zebrad`
data ZebraTxResponse = ZebraTxResponse
{ ztr_blockheight :: !Int
, ztr_conf :: !Int
, ztr_hex :: !HexString
} deriving (Prelude.Show, Eq, Read)
instance FromJSON ZebraTxResponse where
parseJSON =
withObject "ZebraTxResponse" $ \obj -> do
hex <- obj .: "hex"
height <- obj .: "height"
c <- obj .: "confirmations"
pure $ ZebraTxResponse height c hex
-- | Type to represent a raw deserialized Zebra transaction
data RawZebraTx = RawZebraTx
{ zt_id :: !HexString
, zt_locktime :: !Word32
, zt_expiry :: !Word32
, zt_tBundle :: !RawTBundle
, zt_sBundle :: !RawSBundle
, zt_oBundle :: !RawOBundle
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show) deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct UnifiedFullViewingKey deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawZebraTx
data ShieldedOutput = -- | Type for a raw deserialized Zebra transparent bundle
ShieldedOutput data RawTBundle = RawTBundle
{ s_cv :: BS.ByteString { ztb_empty :: !Bool
, s_cmu :: BS.ByteString , ztb_vin :: ![RawTxIn]
, s_ephKey :: BS.ByteString , ztb_vout :: ![RawTxOut]
, s_encCipherText :: BS.ByteString , ztb_coinbase :: !Bool
, s_outCipherText :: BS.ByteString } deriving stock (Eq, Prelude.Show, GHC.Generic)
, s_proof :: BS.ByteString deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
} deriving anyclass (Data.Structured.Show)
deriving stock (Eq, Prelude.Show, GHC.Generic) deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawTBundle
-- | Type for a raw deserialized Zebra Sapling bundle
data RawSBundle = RawSBundle
{ zsb_empty :: !Bool
, zsb_spends :: ![ShieldedSpend]
, zsb_outputs :: ![ShieldedOutput]
, zsb_value :: !Int64
, zsb_sig :: !HexString
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawSBundle
data SaplingBundle = SaplingBundle
{ sbSpends :: ![ShieldedSpend]
, sbOutputs :: ![ShieldedOutput]
, sbValue :: !Int64
, sbSig :: !HexString
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
fromRawSBundle :: RawSBundle -> Maybe SaplingBundle
fromRawSBundle b =
if zsb_empty b
then Nothing
else Just $
SaplingBundle (zsb_spends b) (zsb_outputs b) (zsb_value b) (zsb_sig b)
-- | Type for a raw deseralized Zebra Orchard bundle
data RawOBundle = RawOBundle
{ zob_empty :: !Bool
, zob_actions :: ![OrchardAction]
, zob_flags :: !OrchardFlags
, zob_value :: !Int64
, zob_anchor :: !HexString
, zob_proof :: !HexString
, zob_sig :: !HexString
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawOBundle
-- | Type for an Orchard Bundle
data OrchardBundle = OrchardBundle
{ obActions :: ![OrchardAction]
, obFlags :: !OrchardFlags
, obValue :: !Int64
, obAnchor :: !HexString
, obProof :: !HexString
, obSig :: !HexString
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
fromRawOBundle :: RawOBundle -> Maybe OrchardBundle
fromRawOBundle b =
if zob_empty b
then Nothing
else Just $
OrchardBundle
(zob_actions b)
(zob_flags b)
(zob_value b)
(zob_anchor b)
(zob_proof b)
(zob_sig b)
-- | Type for the Orchard bundle flags
data OrchardFlags = OrchardFlags
{ of_spends :: !Bool
, of_outputs :: !Bool
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardFlags
-- | Type for the response from the `zebrad` RPC method `getinfo`
data ZebraGetInfo = ZebraGetInfo
{ zgi_build :: !T.Text
, zgi_subversion :: !T.Text
} deriving (Prelude.Show, Eq)
instance FromJSON ZebraGetInfo where
parseJSON =
withObject "ZebraGetInfo" $ \obj -> do
b <- obj .: "build"
s <- obj .: "subversion"
pure $ ZebraGetInfo b s
-- | Type for the response from the `zebrad` RPC method `getblockchaininfo`
data ZebraGetBlockChainInfo = ZebraGetBlockChainInfo
{ zgb_best :: !HexString
, zgb_blocks :: !Int
, zgb_net :: !ZcashNet
} deriving (Prelude.Show, Eq)
instance FromJSON ZebraGetBlockChainInfo where
parseJSON =
withObject "ZebraGetBlockChainInfo" $ \obj -> do
be <- obj .: "bestblockhash"
b <- obj .: "blocks"
c <- obj .: "chain"
pure $
ZebraGetBlockChainInfo
be
b
(case (c :: String) of
"main" -> MainNet
"test" -> TestNet
_ -> RegTestNet)
-- * Transparent
-- | Type to represent the two kinds of transparent addresses
data TransparentType
= P2SH
| P2PKH
deriving (Eq, Prelude.Show, Read)
-- | Type for transparent spending key
type TransparentSpendingKey = XPrvKey
-- | Type to represent a transparent Zcash addresses
data TransparentReceiver = TransparentReceiver
{ tr_type :: !TransparentType
, tr_bytes :: !HexString
} deriving (Eq, Prelude.Show, Read)
-- | Type to represent a transparent Zcash addresses
data TransparentAddress = TransparentAddress
{ ta_network :: !ZcashNet
, ta_receiver :: !TransparentReceiver
} deriving (Eq, Prelude.Show, Read)
-- | Type to represent a TEX Zcash addresses
data ExchangeAddress = ExchangeAddress
{ ex_network :: !ZcashNet
, ex_address :: !TransparentReceiver
} deriving (Eq, Prelude.Show, Read)
-- | Wrapper types for transparent elements
data RawTxIn = RawTxIn
{ rti_outpoint :: !RawOutPoint
, rti_script :: !BS.ByteString
, rti_seq :: !Word32
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawTxIn
data RawTxOut = RawTxOut
{ rto_amt :: !Word64
, rto_script :: !BS.ByteString
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawTxOut
data RawOutPoint = RawOutPoint
{ rop_hash :: !BS.ByteString
, rop_n :: !Word32
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawOutPoint
-- * Sapling
-- | A spending key for Sapling
newtype SaplingSpendingKey =
SaplingSpendingKey BS.ByteString
deriving stock (Eq, Prelude.Show, Read)
instance ToBytes SaplingSpendingKey where
getBytes (SaplingSpendingKey s) = s
-- | A Sapling receiver
newtype SaplingReceiver =
SaplingReceiver BS.ByteString
deriving stock (Eq, Prelude.Show, Read)
instance ToBytes SaplingReceiver where
getBytes (SaplingReceiver s) = s
data SaplingAddress = SaplingAddress
{ net_type :: !ZcashNet
, sa_receiver :: !SaplingReceiver
} deriving (Eq, Prelude.Show, Read)
-- | Type to represent a Sapling Shielded Spend as provided by the @getrawtransaction@ RPC method
data ShieldedSpend = ShieldedSpend
{ sp_cv :: !HexString
, sp_anchor :: !HexString
, sp_nullifier :: !HexString
, sp_rk :: !HexString
, sp_proof :: !HexString
, sp_auth :: !HexString
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct ShieldedSpend
instance FromJSON ShieldedSpend where
parseJSON =
withObject "ShieldedSpend" $ \obj -> do
cv <- obj .: "cv"
anchor <- obj .: "anchor"
nullifier <- obj .: "nullifier"
rk <- obj .: "rk"
p <- obj .: "proof"
sig <- obj .: "spendAuthSig"
pure $ ShieldedSpend cv anchor nullifier rk p sig
-- | Type to represent a Sapling Shielded Output as provided by the @getrawtransaction@ RPC method of @zcashd@.
data ShieldedOutput = ShieldedOutput
{ s_cv :: !HexString -- ^ Value commitment to the input note
, s_cmu :: !HexString -- ^ The u-coordinate of the note commitment for the output note
, s_ephKey :: !HexString -- ^ Ephemeral Jubjub public key
, s_encCipherText :: !HexString -- ^ The output note encrypted to the recipient
, s_outCipherText :: !HexString -- ^ A ciphertext enabling the sender to recover the output note
, s_proof :: !HexString -- ^ Zero-knowledge proof using the Sapling Output circuit
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show) deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct ShieldedOutput deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct ShieldedOutput
data OrchardAction = instance FromJSON ShieldedOutput where
OrchardAction parseJSON =
{ nf :: BS.ByteString withObject "ShieldedOutput" $ \obj -> do
, rk :: BS.ByteString cv <- obj .: "cv"
, cmx :: BS.ByteString cmu <- obj .: "cmu"
, eph_key :: BS.ByteString ephKey <- obj .: "ephemeralKey"
, enc_ciphertext :: BS.ByteString encText <- obj .: "encCiphertext"
, out_ciphertext :: BS.ByteString outText <- obj .: "outCiphertext"
, cv :: BS.ByteString p <- obj .: "proof"
, auth :: BS.ByteString pure $ ShieldedOutput cv cmu ephKey encText outText p
}
deriving stock (Eq, Prelude.Show, GHC.Generic) -- | Type for a Sapling note commitment tree
newtype SaplingCommitmentTree = SaplingCommitmentTree
{ sapTree :: HexString
} deriving (Eq, Prelude.Show, Read)
-- | Type for a Sapling incremental witness
newtype SaplingWitness = SaplingWitness
{ sapWit :: HexString
} deriving (Eq, Prelude.Show, Read)
-- * Orchard
-- | A spending key for Orchard
newtype OrchardSpendingKey =
OrchardSpendingKey BS.ByteString
deriving stock (Eq, Prelude.Show, Read)
instance ToBytes OrchardSpendingKey where
getBytes (OrchardSpendingKey o) = o
-- | An Orchard receiver
newtype OrchardReceiver =
OrchardReceiver BS.ByteString
deriving stock (Eq, Prelude.Show, Read)
instance ToBytes OrchardReceiver where
getBytes (OrchardReceiver o) = o
-- | Type to represent a Unified Address
data UnifiedAddress = UnifiedAddress
{ ua_net :: !ZcashNet
, o_rec :: !(Maybe OrchardReceiver)
, s_rec :: !(Maybe SaplingReceiver)
, t_rec :: !(Maybe TransparentReceiver)
} deriving (Prelude.Show, Eq, Read)
-- | Helper type for marshalling UAs
data RawUA = RawUA
{ raw_net :: !Word8
, raw_o :: !BS.ByteString
, raw_s :: !BS.ByteString
, raw_t :: !BS.ByteString
, raw_to :: !BS.ByteString
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawUA
-- | Type to represent a Unified Full Viewing Key
data UnifiedFullViewingKey = UnifiedFullViewingKey
{ net :: !Word8 -- ^ Number representing the network the key belongs to. @1@ for @mainnet@, @2@ for @testnet@ and @3@ for @regtestnet@.
, o_key :: !BS.ByteString -- ^ Raw bytes of the Orchard Full Viewing Key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
, s_key :: !BS.ByteString -- ^ Raw bytes of the Sapling Full Viewing Key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
, t_key :: !BS.ByteString -- ^ Raw bytes of the P2PKH chain code and public key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct UnifiedFullViewingKey
-- | Type to represent an Orchard Action as provided by the @getrawtransaction@ RPC method of @zcashd@, and defined in the [Zcash Protocol](https://zips.z.cash/protocol/protocol.pdf)
data OrchardAction = OrchardAction
{ nf :: !HexString -- ^ The nullifier of the input note
, rk :: !HexString -- ^ The randomized validating key for @auth@
, cmx :: !HexString -- ^ The x-coordinate of the note commitment for the output note
, eph_key :: !HexString -- ^ An encoding of an ephemeral Pallas public key
, enc_ciphertext :: !HexString -- ^ The output note encrypted to the recipient
, out_ciphertext :: !HexString -- ^ A ciphertext enabling the sender to recover the output note
, cv :: !HexString -- ^ A value commitment to the net value of the input note minus the output note
, auth :: !HexString -- ^ A signature authorizing the spend in this Action
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show) deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardAction deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardAction
data OrchardDecodedAction = instance FromJSON OrchardAction where
OrchardDecodedAction parseJSON =
{ a_value :: Int64 withObject "OrchardAction" $ \obj -> do
, a_recipient :: BS.ByteString n <- obj .: "nullifier"
, a_memo :: BS.ByteString r <- obj .: "rk"
} c <- obj .: "cmx"
deriving stock (Eq, Prelude.Show, GHC.Generic) ephKey <- obj .: "ephemeralKey"
encText <- obj .: "encCiphertext"
outText <- obj .: "outCiphertext"
cval <- obj .: "cv"
a <- obj .: "spendAuthSig"
pure $ OrchardAction n r c ephKey encText outText cval a
-- | Type for a Orchard note commitment tree
newtype OrchardCommitmentTree = OrchardCommitmentTree
{ orchTree :: HexString
} deriving (Eq, Prelude.Show, Read)
-- | Type for a Sapling incremental witness
newtype OrchardWitness = OrchardWitness
{ orchWit :: HexString
} deriving (Eq, Prelude.Show, Read)
-- | Type to represent a decoded note
data DecodedNote = DecodedNote
{ a_value :: !Int64 -- ^ The amount of the transaction in _zatoshis_.
, a_recipient :: !BS.ByteString -- ^ The recipient Orchard receiver.
, a_memo :: !BS.ByteString -- ^ The decoded shielded memo field.
, a_nullifier :: !HexString -- ^ The calculated nullifier
, a_rho :: !BS.ByteString
, a_rseed :: !Rseed
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show) deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardDecodedAction deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct DecodedNote
data Rseed = Rseed
{ rs_kind :: !Word8
, rs_bytes :: !BS.ByteString
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct Rseed
data TransparentTxSpend = TransparentTxSpend
{ ts_sk :: !BS.ByteString
, ts_utxo :: !RawOutPoint
, ts_coin :: !RawTxOut
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct TransparentTxSpend
data SaplingTxSpend = SaplingTxSpend
{ ss_sk :: !BS.ByteString
, ss_note :: !DecodedNote
, ss_iw :: !BS.ByteString
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct SaplingTxSpend
data OrchardTxSpend = OrchardTxSpend
{ ss_sk :: !BS.ByteString
, ss_note :: !DecodedNote
, ss_iw :: !BS.ByteString
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardTxSpend
data OutgoingNote = OutgoingNote
{ on_kind :: !Word8
, on_key :: !BS.ByteString
, on_recipient :: !BS.ByteString
, on_amt :: !Word64
, on_memo :: !BS.ByteString
, on_chg :: !Bool
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OutgoingNote
newtype SaplingSpendParams = SaplingSpendParams
{ sapSParams :: BS.ByteString
} deriving newtype (Eq, Prelude.Show, Read)
newtype SaplingOutputParams = SaplingOutputParams
{ sapOParams :: BS.ByteString
} deriving newtype (Eq, Prelude.Show, Read)
data TxError
= InsufficientFunds
| ChangeRequired
| Fee
| Balance
| TransparentBuild
| SaplingBuild
| OrchardBuild
| OrchardSpend
| OrchardRecipient
| SaplingBuilderNotAvailable
| OrchardBuilderNotAvailable
| ZHError
deriving (Eq, Prelude.Show, Read)
-- * Classes
-- | Class to represent types with a bytestring representation
class ToBytes a where
getBytes :: a -> BS.ByteString
-- * Helpers
-- | Helper function to turn a hex-encoded string to bytestring
decodeHexText :: String -> BS.ByteString
decodeHexText h = BS.pack $ hexRead h
where
hexRead hexText
| null chunk = []
| otherwise =
fromIntegral (read ("0x" <> chunk)) : hexRead (drop 2 hexText)
where
chunk = take 2 hexText

View file

@ -1,30 +1,58 @@
-- Copyright 2022-2024 Vergara Technologies LLC
--
-- This file is part of Zcash-Haskell.
--
-- |
-- Module : ZcashHaskell.Utils
-- Copyright : 2022-2024 Vergara Technologies LLC
-- License : MIT
--
-- Maintainer : pitmutt@vergara.tech
-- Stability : experimental
-- Portability : unknown
--
-- A set of functions to assist in the handling of elements of the Zcash protocol, allowing for decoding of memos, addresses and viewing keys.
--
{-# LANGUAGE OverloadedStrings #-}
module ZcashHaskell.Utils where module ZcashHaskell.Utils where
import C.Zcash import C.Zcash
( rustWrapperBech32Decode ( rustWrapperBech32Decode
, rustWrapperBech32Encode
, rustWrapperBech32mEncode
, rustWrapperCreateTx
, rustWrapperF4Jumble , rustWrapperF4Jumble
, rustWrapperF4UnJumble , rustWrapperF4UnJumble
, rustWrapperTxRead
) )
import Control.Exception (SomeException(..), try)
import Control.Monad.IO.Class
import Data.Aeson
import Data.Binary.Get
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Data.HexString (HexString(..), toBytes)
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Foreign.Rust.Marshall.Variable import Foreign.Rust.Marshall.Variable
import Network.HTTP.Client (HttpException(..))
import Network.HTTP.Simple
import ZcashHaskell.Types import ZcashHaskell.Types
-- | Helper function to turn a hex-encoded strings to bytestring -- * Utility functions
decodeHexText :: String -> BS.ByteString
decodeHexText h = BS.pack $ hexRead h
where
hexRead hexText
| null chunk = []
| otherwise =
fromIntegral (read ("0x" <> chunk)) : hexRead (drop 2 hexText)
where
chunk = take 2 hexText
-- | Decode the given bytestring using Bech32 -- | Decode the given bytestring using Bech32
decodeBech32 :: BS.ByteString -> RawData decodeBech32 :: BS.ByteString -> RawData
decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode
-- | Encode the given Human Readable Part and bytestring as a Bech32m string
encodeBech32m :: BS.ByteString -> BS.ByteString -> T.Text
encodeBech32m h d = withPureBorshVarBuffer $ rustWrapperBech32mEncode h d
-- | Encode the given Human Readable Part and bytestring as a Bech32 string
encodeBech32 :: BS.ByteString -> BS.ByteString -> T.Text
encodeBech32 h d = withPureBorshVarBuffer $ rustWrapperBech32Encode h d
-- | Apply the F4Jumble transformation to the given bytestring -- | Apply the F4Jumble transformation to the given bytestring
f4Jumble :: BS.ByteString -> BS.ByteString f4Jumble :: BS.ByteString -> BS.ByteString
f4Jumble = withPureBorshVarBuffer . rustWrapperF4Jumble f4Jumble = withPureBorshVarBuffer . rustWrapperF4Jumble
@ -32,3 +60,116 @@ f4Jumble = withPureBorshVarBuffer . rustWrapperF4Jumble
-- | Apply the inverse F4Jumble transformation to the given bytestring -- | Apply the inverse F4Jumble transformation to the given bytestring
f4UnJumble :: BS.ByteString -> BS.ByteString f4UnJumble :: BS.ByteString -> BS.ByteString
f4UnJumble = withPureBorshVarBuffer . rustWrapperF4UnJumble f4UnJumble = withPureBorshVarBuffer . rustWrapperF4UnJumble
-- * Node interaction
-- | Make a Zcash RPC call
makeZcashCall ::
(MonadIO m, FromJSON a)
=> BS.ByteString
-> BS.ByteString
-> T.Text
-> [Data.Aeson.Value]
-> m (Response a)
makeZcashCall username password m p = do
let payload = RpcCall "1.0" "test" m p
let myRequest =
setRequestBodyJSON payload $
setRequestPort 8232 $
setRequestBasicAuth username password $
setRequestMethod "POST" defaultRequest
httpJSON myRequest
-- | Make a Zebra RPC call
makeZebraCall ::
FromJSON a
=> T.Text -- ^ Hostname for `zebrad`
-> Int -- ^ Port for `zebrad`
-> T.Text -- ^ RPC method to call
-> [Data.Aeson.Value] -- ^ List of parameters
-> IO (Either String a)
makeZebraCall host port m params = do
let payload = RpcCall "2.0" "zh" m params
let myRequest =
setRequestBodyJSON payload $
setRequestPort port $
setRequestHost (E.encodeUtf8 host) $
setRequestMethod "POST" defaultRequest
r <-
try $ httpJSON myRequest :: FromJSON a1 =>
IO (Either SomeException (Response (RpcResponse a1)))
case r of
Left ex -> return $ Left $ show ex
Right res -> do
let zebraResp = getResponseBody res
case err zebraResp of
Just zErr -> return $ Left $ T.unpack $ emessage zErr
Nothing ->
case result zebraResp of
Nothing -> return $ Left "Empty response from Zebra"
Just zR -> return $ Right zR
getBlockTime :: HexString -> Int
getBlockTime hex_block =
fromIntegral $
runGet getInt32le $
LBS.fromStrict $ BS.take 4 (BS.drop 100 $ hexBytes hex_block)
readZebraTransaction :: HexString -> Maybe RawZebraTx
readZebraTransaction hex =
if BS.length (hexBytes $ zt_id rawTx) < 1
then Nothing
else Just rawTx
where
rawTx = (withPureBorshVarBuffer . rustWrapperTxRead) $ hexBytes hex
createTransaction ::
Maybe SaplingCommitmentTree -- ^ to obtain the Sapling anchor
-> Maybe OrchardCommitmentTree -- ^ to obtain the Orchard anchor
-> [TransparentTxSpend] -- ^ the list of transparent notes to spend
-> [SaplingTxSpend] -- ^ the list of Sapling notes to spend
-> [OrchardTxSpend] -- ^ the list of Orchard notes to spend
-> [OutgoingNote] -- ^ the list of outgoing notes, including change notes
-> SaplingSpendParams -- ^ the Sapling circuit spending parameters
-> SaplingOutputParams -- ^ the Sapling circuit output parameters
-> ZcashNet -- ^ the network to be used
-> Int -- ^ target block height
-> Bool -- ^ True to build, False to estimate fee
-> Either TxError HexString
createTransaction sapAnchor orchAnchor tSpend sSpend oSpend outgoing sParams oParams znet bh build =
processResult $! txResult
where
processResult :: HexString -> Either TxError HexString
processResult input =
if BS.length (hexBytes input) > 1
then Right input
else case head (BS.unpack $ hexBytes input) of
0 -> Left InsufficientFunds
1 -> Left ChangeRequired
2 -> Left Fee
3 -> Left Balance
4 -> Left TransparentBuild
5 -> Left SaplingBuild
6 -> Left OrchardBuild
7 -> Left OrchardSpend
8 -> Left OrchardRecipient
9 -> Left SaplingBuilderNotAvailable
10 -> Left OrchardBuilderNotAvailable
_ -> Left ZHError
txResult =
withPureBorshVarBuffer $
rustWrapperCreateTx
(case sapAnchor of
Nothing -> "0"
Just sA -> toBytes $ sapTree sA)
(case orchAnchor of
Nothing -> "0"
Just oA -> toBytes $ orchTree oA)
tSpend
sSpend
oSpend
outgoing
(sapSParams sParams)
(sapOParams oParams)
(znet == MainNet)
(fromIntegral bh)
build

View file

@ -1,72 +0,0 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-3.5
# resolver: nightly-2015-09-21
# resolver: ghc-7.10.2
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2018-01-01.yaml
resolver:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/17.yaml
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the resolver.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
extra-deps:
# - acme-missiles-0.3
- git: https://git.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
commit: 787c2e813eb3a5d16c375d4b37dfefbd2adcdf05
- git: https://github.com/well-typed/borsh.git
commit: d2fcfa159e0a844b1ec5e8ed3e232d4b380fa831
- vector-0.13.0.0@sha256:fa5cac81a17a5af388716792e8b99c24b3b66770086756d0d8b23f8272a0244c,9112
- aeson-2.1.2.1@sha256:f10f3c661bd5cf57aee46b94420e47736240b8e209ac15f4bfc1a4e4d55831fa,6344
- generically-0.1.1
#
# extra-deps: []
# Override default flag values for local packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of Stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=2.9"
#
# Override the architecture used by Stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by Stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

File diff suppressed because one or more lines are too long

70
tx.json Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,63 +1,89 @@
cabal-version: 1.12 cabal-version: 3.0
-- This file has been generated from package.yaml by hpack version 0.35.1. -- This file has been generated from package.yaml by hpack version 0.36.0.
-- --
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
name: zcash-haskell name: zcash-haskell
version: 0.1.0 version: 0.6.2.1
synopsis: Utilities to interact with the Zcash blockchain synopsis: Utilities to interact with the Zcash blockchain
description: Please see the README on the repo at <https://git.vergara.tech/Vergara_Tech/haskell-wrapper#readme> description: Please see the README on the repo at <https://git.vergara.tech/Vergara_Tech/zcash-haskell#readme>
category: Blockchain category: Blockchain
author: Rene Vergara author: Rene Vergara
maintainer: rene@vergara.network maintainer: pitmutt@vergara.tech
copyright: (c)2023 Vergara Technologies LLC copyright: (c)2022-2024 Vergara Technologies LLC
license: BOSL license: MIT
license-file: LICENSE license-file: LICENSE
build-type: Simple build-type: Custom
extra-source-files: extra-source-files:
Setup.hs
extra-doc-files:
README.md README.md
CHANGELOG.md CHANGELOG.md
configure
source-repository head custom-setup
type: git setup-depends:
location: https://git.vergara.tech/Vergara_Tech/zcash-haskell base >= 4.7 && < 5
, Cabal >= 3.0.0.0
, directory >= 1.3.6.0
, filepath >= 1.3.0.2
, envy
, regex-compat
, regex-base
library library
exposed-modules: exposed-modules:
C.Zcash C.Zcash
ZcashHaskell.Keys
ZcashHaskell.Orchard ZcashHaskell.Orchard
ZcashHaskell.Sapling ZcashHaskell.Sapling
ZcashHaskell.Transparent
ZcashHaskell.Types ZcashHaskell.Types
ZcashHaskell.Utils ZcashHaskell.Utils
other-modules:
Paths_zcash_haskell
hs-source-dirs: hs-source-dirs:
src src
pkgconfig-depends:
rustzcash_wrapper-uninstalled
build-depends: build-depends:
base >=4.7 && <5 aeson
, base >=4.7 && <5
, base58-bytestring
, borsh >=0.2 , borsh >=0.2
, bytestring , bytestring
, cryptonite
, foreign-rust , foreign-rust
, generics-sop , generics-sop
, hexstring >=0.12.1
, http-conduit
, http-client
, memory
, binary
, text , text
, haskoin-core
, secp256k1-haskell >= 1.1
, utf8-string
build-tool-depends:
c2hs:c2hs
default-language: Haskell2010 default-language: Haskell2010
test-suite zcash-haskell-test test-suite zcash-haskell-test
type: exitcode-stdio-1.0 type: exitcode-stdio-1.0
main-is: Spec.hs main-is: Spec.hs
other-modules:
Paths_zcash_haskell
hs-source-dirs: hs-source-dirs:
test test
ghc-options: -threaded -rtsopts -with-rtsopts=-N ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: build-depends:
base >=4.7 && <5 aeson
, base >=4.7 && <5
, bytestring , bytestring
, haskoin-core
, hexstring >= 0.12.1
, hspec , hspec
, HUnit
, QuickCheck
, quickcheck-transformer
, text , text
, zcash-haskell , zcash-haskell
, binary
, cryptonite
, secp256k1-haskell
pkgconfig-depends: rustzcash_wrapper
default-language: Haskell2010 default-language: Haskell2010

20
zebrablock.json Normal file
View file

@ -0,0 +1,20 @@
{
"result": {
"hash": "0041ee9cb0e256a73c92bb72d830143c402ea350152f56f19f74d23cf51418fb",
"confirmations": 3583,
"height": 2767099,
"tx": [
"d169ec3eda57dc750edfc1aa6b8ffb4ed2065780bfd5964de34b529503ec372f",
"987fcdb9bd37cbb5b205a8336de60d043f7028bebaa372828d81f3da296c7ef9"
],
"trees": {
"sapling": {
"size": 129349
},
"orchard": {
"size": 39382
}
}
},
"id": 123
}

4
zebrahexblock.json Normal file

File diff suppressed because one or more lines are too long

8
zebratx.json Normal file
View file

@ -0,0 +1,8 @@
{
"result": {
"hex": "0400008085202f8900010829d200000000001976a91484ae5002305847e7176362d7c12c19c5bdbbaf8088ac0000000023392a00f02cd200000000000192331caef004cc758fb666bed1908e61daa82d5c9835c0544afd8369589d350b04a7488a9870983860779ca2e0079a286fe71f60d5c583c3427d24ff968bad3246c1c838b90f465becc1ddfea5839b730ec219d577ed182f6da8f493350b422c86943b7c8ff42de8aee0fe01f4b91c8bb204008f06f85c3dffdb622632d2d4e8b8f0c7457cfa0f4238c7ef4c8903a89559e9307c26e844747ccb9b8dd5e7e83637983746b2fec3de051312306eb8b15db4766b3ef5fe3086d53d388cf2b3b209389ff3644e47d6bfdbe2fafef1bc2311093ad0b49f4600925f55328da337e73f01f83097acd8f2aca7a85f28e75fb4efec6551e026a1ebb35c25efde455cc44002bb8cc79288ed738423432558ebb583874aa5c356abe5be794e1bfaeaf6a7eccf67e5d938751a3a351bc21d4422d2ff0f36f5b30759d79b1ef2d83618d9c1769694454002d2f2be74de3ac10d39829369c87a70e1e9769e7d5ae7c865282a04487a8ae4cf5beeecaea6a3be1c864bdd8d61df88f08a76ac49d28a3a069d2c0d02068a10e88674b39c9d03da49256d914319d267c0d1db08ee7777668e90a94c50a065977222ee620f2291f6ca3fa464fafe8fc3fedf64a836eef5a2ca16aaae5573ee082a77f046d388750fa4ce3853c846ae3f338741c7976f72db4ade4abd4211e8d335ec8c83309bc7d7140a99dfb64a29839b9acc74de4ac0949bcbec4e76be9096a45ab6ca19b165f4097e24ab92d7b58694b0897789c3cdcca2b3d4b0a9da153fafe68f940031b6548d3c37c1301faa9adcfc41c417e613c0838340e28801f72610289d7435910fd276ca243d119541e0a121d263fdda149ac40f293e6fee6d5ddc32532ad947548eb5d20a5bfea97543965fe09313f1a5a78ce51ecac9c36b54cb573780da15d197f5ffacf1fa0d2b5495057a29104d610936c1898d1058f6f7b90e614bc2e3ff56b1e75aa4708128e3782f602dbdd29ece268311965592ddd536ea63841ea953b20677e0dd911852d23b85a3382420d22cd276b216e81638540b04966210a9308e8f9fb46958c967e3c2e36ae081a95cec8865a87d85d5689f660fe6c616ebfc2dab0f6e41d3e8c2906405fb98a506d90a8e8c6201d520a0deaa65e92e91f965288128101427d58e0b1e3ad8a49526feed27f3bcc6d505591483e2e4cc4a9b678d63f3abc905f26f91083bc595b89ff0b6cc3caa9d93013127ab7b30fbe18fad6f7f380fd6d5668fb6c3fdea3771fdd3004994e5752275ff7b186f9ad95f9d7ff01263f1165de34c1ae867e8954d66186880a90d73eace4dc1b8b17c76815242342821b4fab93755c3dc24e60aafd1cd3e283a7414de3af18c61328d92e9141916b8bb816de024a5a047a66508340a3287f698a41804e297916ff04f2921a0eeb8fcc5690c7fc024f57ab1fb6c6bc9a0caf9bf9e0e9aad64ceb2634bedbda6716235e4b93b67cd07ae06fde6abd2893143b55628be83fd4b347ce407dabf28e288f99d23b031376bfc1b1552cac1557e4730b03be581a92feae7d39fa2cf1c565a6cbe59a83b64b90ef8fc73ff6f8b9562d77fae1221df8f5ddb029f12ae80c3f128b87e56f78224b875af54a2fa1434749bb2e1c7ad9331497a71015ae0fc63903f36023e7f34b97c6ec5976ba3740845e5870c85f1b2042cdca86620881e08595215332de7d5828844e9e44124e42e1c60f6821cb71640c6643b01681553c932d310632a8b21154445176eb1a9a3c87dff22508bdbe4f1500e19131a072c42ff1d106ade135722a9e37e95e7e93917378e7907aae4be92dab78b1cd5a771d6064f6e3afc26ff84943a84de7f6ca6b0ab5993d1013b061da4053d77398cbeb329a6ae16f76493f85df1164b4f1fdff69bf113c8f18274a4ce6a05dd4c1ccbacb8d2c3760210e312c3a344294b43b23d06b7ce7263d3178e4fd530ba5838dc0e517b7d6fff2a0d9c4d69105a8fdab3f0c51a219c1ec10337b7cf05f8f3b1fb0a09f600308e5c21ae6ae06d6f87a6766d29e3a34f331f520d80524d580bd54b25716b6b937534233b856e022d20e53779b3a4a3615a3d62d1824c2bfa906e7804d629cc6712a3aee8c3703e99ec807cdb2d381acf126d63b83a2ce1d8f5cb768270bf41ae5637976acbaad8a1fa52cfb7a2f012966f3d29867cf2c28e504043a09eeff91917f6e96dc35a7df124074da73a20b87c7c8e2196f344cc08bd4c2406daaf6064488b5f9983131d90141fba82b13b0b1ff60565be66d53c36df3a9b4c772bffd428b34f94060ad32c59c9c029eba5fabd7a01b4e7252406c0ce7bb93c831034b100cc71090b37a436f96ce902973e2dca9594886b602ed6142697413aa448652529fe688a2e62fa96f8031ade066bb2bdc682f0ae3a526c7ad3c5d01e243b999a58aa5f6816dcd7a0cdd49202e128b99436f71e7fb7033bf96d8e3930e39e024530ec4b7932d334e54a66bfc3630b472336b6719d5a38e6e9bed938f71fe49e0af0b20c5db5408cabb3227b1690e904ea3116ee568330f56a5a698b914570962da4d831f5f5acde9acb257d272d0cd14e3133c89307f2d1575e32b8cc1582d1e4a680d35a1a2cace6233dfb4b0a7fea26f41785e1ac6007dd20d8b6dc3bd6857fa487c52b39f86647a67931b33910b746331305199d20ecd2e4d3b454226a134240831ea5a35c1e2d603c48eea209868b839c79a9318b6fd1078bc0f2bb9b0e931b64d63fbbcbf22b41e3cf7bee5cecb3c0e7b3ae39cf736fce8645ab33becbc9586a9154e29dd88f42ec7deecb2a4c08ac020ce54607f8006d2aa05a689ea688419215f0a10043820d85965a0001f102915fa6b2edfc4d6db7011a725db79b3974e9c1fc1636781bc9609359cfb0c5c921b83fc1115f7ed2568e49991ef93f8b8ff93a0d778251f0bcaa00ad64de8438d40aa05adbd1d1d1d2bca05ea9471a2c1a3733e92bcdf896d47dbe41b9f0d8b8b75de1ccd7cd7b7802fc01c4536a1a7b52ce70736e2cdfc547b58401023e34a608c1b09d0f13ab83d7b3fcde0e050c8cb4635508ddc143a9e6edb1e5a489a48ae0f4d5b0cede7d1b0ed8177709edbd61d859f6d9bad93a4c640684b7b8d994d8f5c0c8773da2b7a5b57d28b58d3f00c53430671d4af1537a262e8ea44a1b943c9bfc5082ad86d6690de32bb6527c815da065061bf79562d292e3d4799aa0df968fb939f64203f541dd4d006e5bd0b34b39215a972c36b229fc2f8e7f10e154b369d7b8f85f89daaaba6ec9836ad748dd79be4a58210341a458202a16e152ca2b0338a116a8490a7fa52c02",
"height": 2767099,
"confirmations": 3582
},
"id": 123
}