Compare commits
No commits in common. "c17f4502537fb1d1878a771f4670d14f28d4591d" and "2f8d9a0c11011b9f0575af130ba95f390e15f322" have entirely different histories.
c17f450253
...
2f8d9a0c11
12 changed files with 70 additions and 658 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -9,20 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Added
|
### 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
|
- Haddock annotations
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Rearranged modules for cleaner dependencies.
|
|
||||||
- Upgrade to Haskell LTS 21.6
|
- Upgrade to Haskell LTS 21.6
|
||||||
|
|
||||||
## [0.1.0] - 2023-06-14
|
## [0.1.0] - 2023-06-14
|
||||||
|
|
75
block.json
75
block.json
|
@ -1,75 +0,0 @@
|
||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
|
@ -1,10 +1,7 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
io::{
|
io::Write,
|
||||||
Write,
|
|
||||||
Cursor
|
|
||||||
},
|
|
||||||
fmt::{Debug, Display, Formatter}
|
fmt::{Debug, Display, Formatter}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,24 +19,18 @@ use haskell_ffi::{
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
zip32::Scope as SaplingScope,
|
zip32::Scope as SaplingScope,
|
||||||
transaction::components::sapling::{
|
transaction::components::sapling::{
|
||||||
read_zkproof,
|
|
||||||
GrothProofBytes,
|
GrothProofBytes,
|
||||||
OutputDescription,
|
OutputDescription,
|
||||||
CompactOutputDescription
|
CompactOutputDescription
|
||||||
},
|
},
|
||||||
sapling::{
|
sapling::{
|
||||||
value::ValueCommitment as SaplingValueCommitment,
|
value::ValueCommitment as SaplingValueCommitment,
|
||||||
keys::{
|
keys::FullViewingKey as SaplingViewingKey,
|
||||||
FullViewingKey as SaplingViewingKey,
|
|
||||||
PreparedIncomingViewingKey as SaplingPreparedIncomingViewingKey
|
|
||||||
},
|
|
||||||
note_encryption::SaplingDomain,
|
note_encryption::SaplingDomain,
|
||||||
PaymentAddress,
|
PaymentAddress,
|
||||||
note::ExtractedNoteCommitment as SaplingExtractedNoteCommitment
|
note::ExtractedNoteCommitment as SaplingExtractedNoteCommitment
|
||||||
},
|
},
|
||||||
transaction::Transaction,
|
|
||||||
consensus::{
|
consensus::{
|
||||||
BranchId::Nu5,
|
|
||||||
MainNetwork,
|
MainNetwork,
|
||||||
BlockHeight
|
BlockHeight
|
||||||
}
|
}
|
||||||
|
@ -47,7 +38,7 @@ use zcash_primitives::{
|
||||||
|
|
||||||
use zcash_address::{
|
use zcash_address::{
|
||||||
Network,
|
Network,
|
||||||
unified::{Address, Encoding, Ufvk, Container, Fvk, Receiver},
|
unified::{Address, Encoding, Ufvk, Container, Fvk},
|
||||||
ZcashAddress
|
ZcashAddress
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,20 +86,6 @@ impl<RW> ToHaskell<RW> for RawData {
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
|
|
||||||
#[derive(BorshSerialize, BorshDeserialize)]
|
|
||||||
pub struct HrawTx {
|
|
||||||
bytes: Vec<u8>,
|
|
||||||
s: bool,
|
|
||||||
o: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<RW> ToHaskell<RW> for HrawTx {
|
|
||||||
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
||||||
self.serialize(writer)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(BorshSerialize, BorshDeserialize)]
|
#[derive(BorshSerialize, BorshDeserialize)]
|
||||||
pub struct HshieldedOutput {
|
pub struct HshieldedOutput {
|
||||||
cv: Vec<u8>,
|
cv: Vec<u8>,
|
||||||
|
@ -126,20 +103,6 @@ impl<RW> FromHaskell<RW> for HshieldedOutput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<RW> ToHaskell<RW> for HshieldedOutput {
|
|
||||||
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
||||||
self.serialize(writer)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HshieldedOutput {
|
|
||||||
fn from_object(s: OutputDescription<GrothProofBytes>) -> Result<HshieldedOutput> {
|
|
||||||
let o = HshieldedOutput { cv: s.cv().to_bytes().to_vec(), cmu: s.cmu().to_bytes().to_vec(), eph_key: s.ephemeral_key().0.to_vec(), enc_txt: s.enc_ciphertext().to_vec(), out_txt: s.out_ciphertext().to_vec(), proof: s.zkproof().to_vec() };
|
|
||||||
Ok(o)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(BorshSerialize, BorshDeserialize)]
|
#[derive(BorshSerialize, BorshDeserialize)]
|
||||||
pub struct Haction {
|
pub struct Haction {
|
||||||
nf: Vec<u8>,
|
nf: Vec<u8>,
|
||||||
|
@ -320,42 +283,6 @@ pub extern "C" fn rust_wrapper_svk_check_address(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn rust_wrapper_ufvk_check_address(
|
|
||||||
key_input: *const u8,
|
|
||||||
key_input_len: usize,
|
|
||||||
address_input: *const u8,
|
|
||||||
address_input_len: usize
|
|
||||||
) -> bool {
|
|
||||||
let key: String = marshall_from_haskell_var(key_input, key_input_len, RW);
|
|
||||||
let addy: String = marshall_from_haskell_var(address_input, address_input_len, RW);
|
|
||||||
let dec_key = Ufvk::decode(&key);
|
|
||||||
let dec_addy = Address::decode(&addy);
|
|
||||||
match dec_key {
|
|
||||||
Ok((n, ufvk)) => {
|
|
||||||
let i = ufvk.items();
|
|
||||||
if let Fvk::Orchard(k) = i[0] {
|
|
||||||
let orch_key = FullViewingKey::from_bytes(&k).unwrap();
|
|
||||||
let orch_addy = orch_key.address_at(0u32, Scope::External).to_raw_address_bytes();
|
|
||||||
match dec_addy {
|
|
||||||
Ok((n, recs)) => {
|
|
||||||
let j = recs.items();
|
|
||||||
j[0] == Receiver::Orchard(orch_addy)
|
|
||||||
},
|
|
||||||
Err(_e) => {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(_e) => {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_wrapper_ufvk_decode(
|
pub extern "C" fn rust_wrapper_ufvk_decode(
|
||||||
input: *const u8,
|
input: *const u8,
|
||||||
|
@ -384,51 +311,35 @@ pub extern "C" fn rust_wrapper_ufvk_decode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
//#[no_mangle]
|
||||||
pub extern "C" fn rust_wrapper_sapling_note_decrypt_v2(
|
//pub extern "C" fn rust_wrapper_sapling_note_decrypt(
|
||||||
key: *const u8,
|
//key: *const u8,
|
||||||
key_len: usize,
|
//key_len: usize,
|
||||||
note: *const u8,
|
//note: *const u8,
|
||||||
note_len: usize,
|
//note_len: usize,
|
||||||
out: *mut u8,
|
//out: *mut u8,
|
||||||
out_len: &mut usize
|
//out_len: &mut usize
|
||||||
){
|
//){
|
||||||
let evk: Vec<u8> = marshall_from_haskell_var(key, key_len, RW);
|
//let evk: Vec<u8> = marshall_from_haskell_var(key, key_len, RW);
|
||||||
let note_input: Vec<u8> = marshall_from_haskell_var(note,note_len,RW);
|
//let note_input: HshieldedOutput = marshall_from_haskell_var(note,note_len,RW);
|
||||||
let mut note_reader = Cursor::new(note_input);
|
//let svk = ExtendedFullViewingKey::read(&*evk);
|
||||||
let svk = ExtendedFullViewingKey::read(&*evk);
|
//match svk {
|
||||||
match svk {
|
//Ok(k) => {
|
||||||
Ok(k) => {
|
//let domain = SaplingDomain::for_height(MainNetwork, BlockHeight::from_u32(2000000));
|
||||||
let domain = SaplingDomain::for_height(MainNetwork, BlockHeight::from_u32(2000000));
|
//let action: CompactOutputDescription = CompactOutputDescription {
|
||||||
let action2 = OutputDescription::read(&mut note_reader);
|
//ephemeral_key: EphemeralKeyBytes(to_array(note_input.eph_key)),
|
||||||
match action2 {
|
//cmu: SaplingExtractedNoteCommitment::from_bytes(&to_array(note_input.cmu)).unwrap(),
|
||||||
Ok(action3) => {
|
//enc_ciphertext: to_array(note_input.enc_txt)
|
||||||
let fvk = k.to_diversifiable_full_viewing_key().to_ivk(SaplingScope::External);
|
//};
|
||||||
let pivk = SaplingPreparedIncomingViewingKey::new(&fvk);
|
//let fvk = k.to_diversifiable_full_viewing_key().to_ivk(SaplingScope::External);
|
||||||
let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action3);
|
//let result = zcash_note_encryption::try_note_decryption(&domain, &ivk, &action);
|
||||||
match result {
|
//}
|
||||||
Some((n, r, m)) => {
|
//Err(_e) => {
|
||||||
let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec() };
|
//let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
|
||||||
marshall_to_haskell_var(&hn, out, out_len, RW);
|
//marshall_to_haskell_var(&hn0, out, out_len, RW);
|
||||||
}
|
//}
|
||||||
None => {
|
//}
|
||||||
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
|
//}
|
||||||
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(_e1) => {
|
|
||||||
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
|
|
||||||
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_e) => {
|
|
||||||
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
|
|
||||||
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_wrapper_orchard_note_decrypt(
|
pub extern "C" fn rust_wrapper_orchard_note_decrypt(
|
||||||
|
@ -473,45 +384,3 @@ pub extern "C" fn rust_wrapper_orchard_note_decrypt(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn rust_wrapper_tx_parse(
|
|
||||||
tx: *const u8,
|
|
||||||
tx_len: usize,
|
|
||||||
out: *mut u8,
|
|
||||||
out_len: &mut usize
|
|
||||||
){
|
|
||||||
let tx_input: Vec<u8> = marshall_from_haskell_var(tx, tx_len, RW);
|
|
||||||
let tx_bytes: Vec<u8> = tx_input.clone();
|
|
||||||
let mut tx_reader = Cursor::new(tx_input);
|
|
||||||
let s_o = false;
|
|
||||||
let o_a = false;
|
|
||||||
let parsed_tx = Transaction::read(&mut tx_reader, Nu5);
|
|
||||||
match parsed_tx {
|
|
||||||
Ok(t) => {
|
|
||||||
let s_bundle = t.sapling_bundle();
|
|
||||||
match s_bundle {
|
|
||||||
Some(b) => {
|
|
||||||
let mut s_output = Vec::new();
|
|
||||||
for s_each_out in b.shielded_outputs().iter() {
|
|
||||||
let mut out_bytes = Vec::new();
|
|
||||||
let _ = s_each_out.write_v4(&mut out_bytes);
|
|
||||||
s_output.push(out_bytes);
|
|
||||||
}
|
|
||||||
marshall_to_haskell_var(&s_output, out, out_len, RW);
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
let mut z = Vec::new();
|
|
||||||
z.push(vec![0]);
|
|
||||||
marshall_to_haskell_var(&z, out, out_len, RW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
Err(_e) => {
|
|
||||||
let mut y = Vec::new();
|
|
||||||
y.push(vec![0]);
|
|
||||||
marshall_to_haskell_var(&y, out, out_len, RW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -31,8 +31,6 @@ library:
|
||||||
- text
|
- text
|
||||||
- foreign-rust
|
- foreign-rust
|
||||||
- generics-sop
|
- generics-sop
|
||||||
- aeson
|
|
||||||
- http-conduit
|
|
||||||
pkg-config-dependencies:
|
pkg-config-dependencies:
|
||||||
- rustzcash_wrapper-uninstalled
|
- rustzcash_wrapper-uninstalled
|
||||||
|
|
||||||
|
@ -49,4 +47,3 @@ tests:
|
||||||
- hspec
|
- hspec
|
||||||
- bytestring
|
- bytestring
|
||||||
- text
|
- text
|
||||||
- aeson
|
|
||||||
|
|
|
@ -72,21 +72,6 @@ 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* `BS.ByteString'&
|
|
||||||
, 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'&
|
||||||
|
@ -97,14 +82,7 @@ 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 DecodedNote'&
|
, getVarBuffer `Buffer OrchardDecodedAction'&
|
||||||
}
|
|
||||||
-> `()'
|
|
||||||
#}
|
|
||||||
|
|
||||||
{# fun unsafe rust_wrapper_tx_parse as rustWrapperTxParse
|
|
||||||
{ toBorshVar* `BS.ByteString'&
|
|
||||||
, getVarBuffer `Buffer [BS.ByteString]'&
|
|
||||||
}
|
}
|
||||||
-> `()'
|
-> `()'
|
||||||
#}
|
#}
|
||||||
|
|
|
@ -13,7 +13,6 @@ module ZcashHaskell.Orchard where
|
||||||
|
|
||||||
import C.Zcash
|
import C.Zcash
|
||||||
( rustWrapperIsUA
|
( rustWrapperIsUA
|
||||||
, rustWrapperOrchardCheck
|
|
||||||
, rustWrapperOrchardNoteDecode
|
, rustWrapperOrchardNoteDecode
|
||||||
, rustWrapperUfvkDecode
|
, rustWrapperUfvkDecode
|
||||||
)
|
)
|
||||||
|
@ -34,14 +33,10 @@ 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@.
|
-- | Attempts to decode the given @OrchardAction@ using the given @UnifiedFullViewingKey@.
|
||||||
decryptOrchardAction ::
|
decryptOrchardAction ::
|
||||||
UnifiedFullViewingKey -> OrchardAction -> Maybe DecodedNote
|
OrchardAction -> UnifiedFullViewingKey -> Maybe OrchardDecodedAction
|
||||||
decryptOrchardAction key encAction =
|
decryptOrchardAction encAction key =
|
||||||
case a_value decodedAction of
|
case a_value decodedAction of
|
||||||
0 -> Nothing
|
0 -> Nothing
|
||||||
_ -> Just decodedAction
|
_ -> Just decodedAction
|
||||||
|
|
|
@ -1,84 +1,20 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module ZcashHaskell.Sapling where
|
module ZcashHaskell.Sapling where
|
||||||
|
|
||||||
import C.Zcash
|
import C.Zcash
|
||||||
( rustWrapperIsShielded
|
( rustWrapperIsShielded
|
||||||
, rustWrapperSaplingCheck
|
, rustWrapperSaplingCheck
|
||||||
, rustWrapperSaplingNoteDecode
|
|
||||||
, rustWrapperSaplingVkDecode
|
, rustWrapperSaplingVkDecode
|
||||||
, rustWrapperTxParse
|
|
||||||
)
|
)
|
||||||
import Data.Aeson
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import Foreign.Rust.Marshall.Variable (withPureBorshVarBuffer)
|
|
||||||
import ZcashHaskell.Types
|
|
||||||
( DecodedNote(..)
|
|
||||||
, RawData(..)
|
|
||||||
, RawTxResponse(..)
|
|
||||||
, ShieldedOutput(..)
|
|
||||||
, decodeHexText
|
|
||||||
)
|
|
||||||
import ZcashHaskell.Utils (decodeBech32)
|
|
||||||
|
|
||||||
-- | 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 :: BS.ByteString -> [BS.ByteString]
|
|
||||||
getShieldedOutputs t = withPureBorshVarBuffer $ rustWrapperTxParse t
|
|
||||||
|
|
||||||
-- | 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 k =
|
isValidSaplingViewingKey = rustWrapperSaplingVkDecode
|
||||||
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 -> BS.ByteString -> 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"
|
|
||||||
case o of
|
|
||||||
Nothing ->
|
|
||||||
pure $
|
|
||||||
RawTxResponse
|
|
||||||
i
|
|
||||||
(decodeHexText h)
|
|
||||||
(getShieldedOutputs (decodeHexText h))
|
|
||||||
[]
|
|
||||||
ht
|
|
||||||
c
|
|
||||||
b
|
|
||||||
Just o' -> do
|
|
||||||
a <- o' .: "actions"
|
|
||||||
pure $
|
|
||||||
RawTxResponse
|
|
||||||
i
|
|
||||||
(decodeHexText h)
|
|
||||||
(getShieldedOutputs (decodeHexText h))
|
|
||||||
a
|
|
||||||
ht
|
|
||||||
c
|
|
||||||
b
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
{-# LANGUAGE DuplicateRecordFields #-}
|
|
||||||
{-# LANGUAGE DeriveAnyClass #-}
|
{-# LANGUAGE DeriveAnyClass #-}
|
||||||
{-# LANGUAGE DerivingVia #-}
|
{-# LANGUAGE DerivingVia #-}
|
||||||
{-# LANGUAGE UndecidableInstances #-}
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
-- |
|
-- |
|
||||||
-- Module : ZcashHaskell.Types
|
-- Module : ZcashHaskell.Types
|
||||||
|
@ -19,17 +17,13 @@
|
||||||
module ZcashHaskell.Types where
|
module ZcashHaskell.Types where
|
||||||
|
|
||||||
import Codec.Borsh
|
import Codec.Borsh
|
||||||
import Data.Aeson
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.ByteString.Char8 as C
|
|
||||||
import Data.Int
|
import Data.Int
|
||||||
import Data.Structured
|
import Data.Structured
|
||||||
import qualified Data.Text as T
|
|
||||||
import Data.Word
|
import Data.Word
|
||||||
import qualified GHC.Generics as GHC
|
import qualified GHC.Generics as GHC
|
||||||
import qualified Generics.SOP as SOP
|
import qualified Generics.SOP as SOP
|
||||||
|
|
||||||
-- * General
|
|
||||||
-- | Type to represent data after Bech32 decoding
|
-- | Type to represent data after Bech32 decoding
|
||||||
data RawData = RawData
|
data RawData = RawData
|
||||||
{ hrp :: BS.ByteString -- ^ Human-readable part of the Bech32 encoding
|
{ hrp :: BS.ByteString -- ^ Human-readable part of the Bech32 encoding
|
||||||
|
@ -39,78 +33,17 @@ data RawData = RawData
|
||||||
deriving anyclass (Data.Structured.Show)
|
deriving anyclass (Data.Structured.Show)
|
||||||
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawData
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawData
|
||||||
|
|
||||||
-- * `zcashd` RPC
|
-- | Type to represent a Unified Full Viewing Key
|
||||||
-- | A type to model Zcash RPC calls
|
data UnifiedFullViewingKey = UnifiedFullViewingKey
|
||||||
data RpcCall = RpcCall
|
{ net :: Word8 -- ^ Number representing the network the key belongs to. @1@ for @mainnet@, @2@ for @testnet@ and @3@ for @regtestnet@.
|
||||||
{ jsonrpc :: T.Text
|
, o_key :: BS.ByteString -- ^ Raw bytes of the Orchard Full Viewing Key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
|
||||||
, callId :: T.Text
|
, s_key :: BS.ByteString -- ^ Raw bytes of the Sapling Full Viewing Key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
|
||||||
, method :: T.Text
|
, 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)
|
||||||
, parameters :: [Data.Aeson.Value]
|
} deriving stock (Eq, Prelude.Show, GHC.Generic)
|
||||||
} deriving stock (Prelude.Show, GHC.Generic)
|
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
||||||
|
deriving anyclass (Data.Structured.Show)
|
||||||
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct UnifiedFullViewingKey
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
-- | 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 :: [T.Text] -- ^ 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 t txs
|
|
||||||
|
|
||||||
-- | Type to represent response from the `zcashd` RPC `getrawtransaction`
|
|
||||||
data RawTxResponse = RawTxResponse
|
|
||||||
{ rt_id :: T.Text
|
|
||||||
, rt_hex :: BS.ByteString
|
|
||||||
, rt_shieldedOutputs :: [BS.ByteString]
|
|
||||||
, rt_orchardActions :: [OrchardAction]
|
|
||||||
, rt_blockheight :: Integer
|
|
||||||
, rt_confirmations :: Integer
|
|
||||||
, rt_blocktime :: Integer
|
|
||||||
} deriving (Prelude.Show, Eq)
|
|
||||||
|
|
||||||
-- * Sapling
|
|
||||||
-- | Type to represent a Sapling Shielded Output as provided by the @getrawtransaction@ RPC method of @zcashd@.
|
-- | Type to represent a Sapling Shielded Output as provided by the @getrawtransaction@ RPC method of @zcashd@.
|
||||||
data ShieldedOutput = ShieldedOutput
|
data ShieldedOutput = ShieldedOutput
|
||||||
{ s_cv :: BS.ByteString -- ^ Value commitment to the input note
|
{ s_cv :: BS.ByteString -- ^ Value commitment to the input note
|
||||||
|
@ -124,36 +57,6 @@ data ShieldedOutput = ShieldedOutput
|
||||||
deriving anyclass (Data.Structured.Show)
|
deriving anyclass (Data.Structured.Show)
|
||||||
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct ShieldedOutput
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct ShieldedOutput
|
||||||
|
|
||||||
instance FromJSON ShieldedOutput where
|
|
||||||
parseJSON =
|
|
||||||
withObject "ShieldedOutput" $ \obj -> do
|
|
||||||
cv <- obj .: "cv"
|
|
||||||
cmu <- obj .: "cmu"
|
|
||||||
ephKey <- obj .: "ephemeralKey"
|
|
||||||
encText <- obj .: "encCiphertext"
|
|
||||||
outText <- obj .: "outCiphertext"
|
|
||||||
p <- obj .: "proof"
|
|
||||||
pure $
|
|
||||||
ShieldedOutput
|
|
||||||
(decodeHexText cv)
|
|
||||||
(decodeHexText cmu)
|
|
||||||
(decodeHexText ephKey)
|
|
||||||
(decodeHexText encText)
|
|
||||||
(decodeHexText outText)
|
|
||||||
(decodeHexText p)
|
|
||||||
|
|
||||||
-- * Orchard
|
|
||||||
-- | 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)
|
-- | 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
|
data OrchardAction = OrchardAction
|
||||||
{ nf :: BS.ByteString -- ^ The nullifier of the input note
|
{ nf :: BS.ByteString -- ^ The nullifier of the input note
|
||||||
|
@ -169,46 +72,12 @@ data OrchardAction = OrchardAction
|
||||||
deriving anyclass (Data.Structured.Show)
|
deriving anyclass (Data.Structured.Show)
|
||||||
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardAction
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardAction
|
||||||
|
|
||||||
instance FromJSON OrchardAction where
|
-- | Type to represent a decoded Orchard Action
|
||||||
parseJSON =
|
data OrchardDecodedAction = OrchardDecodedAction
|
||||||
withObject "OrchardAction" $ \obj -> do
|
|
||||||
n <- obj .: "nullifier"
|
|
||||||
r <- obj .: "rk"
|
|
||||||
c <- obj .: "cmx"
|
|
||||||
ephKey <- obj .: "ephemeralKey"
|
|
||||||
encText <- obj .: "encCiphertext"
|
|
||||||
outText <- obj .: "outCiphertext"
|
|
||||||
cval <- obj .: "cv"
|
|
||||||
a <- obj .: "spendAuthSig"
|
|
||||||
pure $
|
|
||||||
OrchardAction
|
|
||||||
(decodeHexText n)
|
|
||||||
(decodeHexText r)
|
|
||||||
(decodeHexText c)
|
|
||||||
(decodeHexText ephKey)
|
|
||||||
(decodeHexText encText)
|
|
||||||
(decodeHexText outText)
|
|
||||||
(decodeHexText cval)
|
|
||||||
(decodeHexText a)
|
|
||||||
|
|
||||||
-- | Type to represent a decoded note
|
|
||||||
data DecodedNote = DecodedNote
|
|
||||||
{ a_value :: Int64 -- ^ The amount of the transaction in _zatoshis_.
|
{ a_value :: Int64 -- ^ The amount of the transaction in _zatoshis_.
|
||||||
, a_recipient :: BS.ByteString -- ^ The recipient Orchard receiver.
|
, a_recipient :: BS.ByteString -- ^ The recipient Orchard receiver.
|
||||||
, a_memo :: BS.ByteString -- ^ The decoded shielded memo field.
|
, a_memo :: BS.ByteString -- ^ The decoded shielded memo field.
|
||||||
} deriving stock (Eq, Prelude.Show, GHC.Generic)
|
} 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 DecodedNote
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardDecodedAction
|
||||||
|
|
||||||
-- * 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
|
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
--
|
--
|
||||||
-- A set of functions to assist in the handling of elements of the Zcash protocol, allowing for decoding of memos, addresses and viewing keys.
|
-- 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
|
||||||
|
@ -18,14 +16,22 @@ import C.Zcash
|
||||||
, rustWrapperF4Jumble
|
, rustWrapperF4Jumble
|
||||||
, rustWrapperF4UnJumble
|
, rustWrapperF4UnJumble
|
||||||
)
|
)
|
||||||
import Control.Monad.IO.Class
|
|
||||||
import Data.Aeson
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.Text as T
|
|
||||||
import Foreign.Rust.Marshall.Variable
|
import Foreign.Rust.Marshall.Variable
|
||||||
import Network.HTTP.Simple
|
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
|
|
||||||
|
-- | 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
|
||||||
|
|
||||||
-- | 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
|
||||||
|
@ -37,20 +43,3 @@ 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
|
||||||
|
|
||||||
-- | 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
|
|
||||||
|
|
75
test/Spec.hs
75
test/Spec.hs
File diff suppressed because one or more lines are too long
70
tx.json
70
tx.json
File diff suppressed because one or more lines are too long
|
@ -38,13 +38,11 @@ library
|
||||||
pkgconfig-depends:
|
pkgconfig-depends:
|
||||||
rustzcash_wrapper-uninstalled
|
rustzcash_wrapper-uninstalled
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson
|
base >=4.7 && <5
|
||||||
, base >=4.7 && <5
|
|
||||||
, borsh >=0.2
|
, borsh >=0.2
|
||||||
, bytestring
|
, bytestring
|
||||||
, foreign-rust
|
, foreign-rust
|
||||||
, generics-sop
|
, generics-sop
|
||||||
, http-conduit
|
|
||||||
, text
|
, text
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
@ -57,8 +55,7 @@ test-suite zcash-haskell-test
|
||||||
test
|
test
|
||||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson
|
base >=4.7 && <5
|
||||||
, base >=4.7 && <5
|
|
||||||
, bytestring
|
, bytestring
|
||||||
, hspec
|
, hspec
|
||||||
, text
|
, text
|
||||||
|
|
Loading…
Reference in a new issue