-
Notifications
You must be signed in to change notification settings - Fork 0
feat: shielded TX support #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: zcash_support
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,11 +8,13 @@ pub const GAS_FOR_FT_ON_TRANSFER_CALL_BACK: Gas = Gas::from_tgas(100); | |
#[near(serializers = [json])] | ||
pub enum TokenReceiverMessage { | ||
DepositProtocolFee, | ||
// Here is the withdraw message structure that will be sent from user or dApp to the btc/zcash connector | ||
Withdraw { | ||
target_btc_address: String, | ||
input: Vec<OutPoint>, | ||
output: Vec<TxOut>, | ||
max_gas_fee: Option<U128>, | ||
orchard_bundle_bytes: Option<String>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The naming of this is confusing. It's a String containing the hex bytes of the Orchard section of the transaction. This should probably be documented I think (if it's what you intend). We normally use "bundle" to refer to the in-memory |
||
}, | ||
} | ||
|
||
|
@@ -51,14 +53,16 @@ impl FungibleTokenReceiver for Contract { | |
target_btc_address, | ||
input, | ||
output, | ||
max_gas_fee | ||
max_gas_fee, | ||
orchard_bundle_bytes, | ||
} => self.ft_on_transfer_withdraw_chain_specific( | ||
sender_id, | ||
amount, | ||
target_btc_address, | ||
input, | ||
output, | ||
max_gas_fee | ||
max_gas_fee, | ||
orchard_bundle_bytes.map(|b| hex::decode(b).unwrap()), | ||
), | ||
} | ||
} | ||
|
@@ -94,7 +98,7 @@ impl Contract { | |
&vutxos, | ||
amount, | ||
withdraw_fee, | ||
max_gas_fee | ||
max_gas_fee, | ||
); | ||
|
||
let need_signature_num = psbt.get_input_num(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -185,7 +185,7 @@ impl Contract { | |
} | ||
}); | ||
require!( | ||
actual_received_amounts.len() == 1, | ||
actual_received_amounts.len() <= 1, | ||
"only one user output is allowed." | ||
); | ||
let actual_received_amount = actual_received_amounts[0]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Next come the checks of the amount the user will receive. In shielded transactions we don’t know this amount and don’t know how much was spent on gas. |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,11 +6,12 @@ use crate::zcash_utils::transaction::Transaction; | |
use bitcoin::hashes::Hash; | ||
use bitcoin::{OutPoint, TxOut}; | ||
use near_sdk::require; | ||
use zcash_primitives::transaction::components::orchard::read_v5_bundle; | ||
use zcash_primitives::transaction::fees::transparent::{InputSize, OutputView}; | ||
use zcash_primitives::transaction::fees::FeeRule; | ||
use zcash_primitives::transaction::{TransactionData, TxVersion}; | ||
use zcash_protocol::consensus::{BlockHeight, BranchId}; | ||
use zcash_protocol::value::Zatoshis; | ||
use zcash_protocol::value::{ZatBalance, Zatoshis}; | ||
use zcash_transparent::bundle::Authorized; | ||
use zcash_transparent::bundle::TxIn as ZcashTxIn; | ||
use zcash_transparent::bundle::TxOut as ZcashTxOut; | ||
|
@@ -22,12 +23,14 @@ pub struct PsbtWrapper { | |
vin: Vec<ZcashTxIn<Authorized>>, | ||
vout: Vec<ZcashTxOut>, | ||
inputs_utxo: Vec<ZcashTxOut>, | ||
orchard_bundle: Option<orchard::Bundle<orchard::bundle::Authorized, ZatBalance>>, | ||
} | ||
|
||
impl PsbtWrapper { | ||
pub fn new( | ||
input: Vec<OutPoint>, | ||
output: Vec<TxOut>, | ||
orchard_bundle_bytes: Option<Vec<u8>>, | ||
expiry_height: u32, | ||
config: &Config, | ||
) -> Self { | ||
|
@@ -61,12 +64,28 @@ impl PsbtWrapper { | |
vin.len() | ||
]; | ||
|
||
// TODO: pass the recipient address and amount to verify the orchard output | ||
// let recipient_address = "<SOME ZCASH ADDRESS>"; | ||
// let value = "<Amount of the output>"; | ||
|
||
// TODO: verify orchard bundle | ||
// How to verify orchard bundle value and recipient? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can't verify that just based on the bytes of the Orchard section of the transaction. You need to have the data that was encrypted and encoded to produce those bytes. That is available in the PCZT. I think @str4d will need to explain this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
// Should we call orchard_bundle.unwrap().verify_proof(vk) here? what is the vk? | ||
// We have to take into account the gas cost and limits | ||
let orchard_bundle = if let Some(orchard_bundle_bytes) = orchard_bundle_bytes { | ||
let mut reader = Cursor::new(orchard_bundle_bytes); | ||
read_v5_bundle(&mut reader).unwrap() | ||
} else { | ||
None | ||
}; | ||
|
||
Self { | ||
branch_id: get_branch_id(expiry_height, config), | ||
expiry_height, | ||
vout, | ||
vin, | ||
inputs_utxo: inputs, | ||
orchard_bundle, | ||
} | ||
} | ||
|
||
|
@@ -95,6 +114,7 @@ impl PsbtWrapper { | |
vin: original_psbt.vin, | ||
vout, | ||
inputs_utxo: original_psbt.inputs_utxo, | ||
orchard_bundle: original_psbt.orchard_bundle, | ||
} | ||
} | ||
|
||
|
@@ -140,7 +160,7 @@ impl PsbtWrapper { | |
|
||
pub fn to_bytes(&self) -> Vec<u8> { | ||
let mut buf = Vec::<u8>::new(); | ||
let version: u8 = 2; | ||
let version: u8 = 3; | ||
buf.push(version); | ||
match self.branch_id { | ||
BranchId::Nu6 => buf.write_all(&[7u8; 1]).unwrap(), | ||
|
@@ -211,12 +231,19 @@ impl PsbtWrapper { | |
inputs.push(ZcashTxOut::read(&mut rdr).unwrap()); | ||
} | ||
|
||
let orchard_bundle = if version >= 3 { | ||
read_v5_bundle(&mut rdr).unwrap() | ||
} else { | ||
None | ||
}; | ||
|
||
Self { | ||
branch_id, | ||
expiry_height, | ||
vin, | ||
vout, | ||
inputs_utxo: inputs, | ||
orchard_bundle, | ||
} | ||
} | ||
|
||
|
@@ -231,6 +258,7 @@ impl PsbtWrapper { | |
authorization: zcash_transparent::bundle::Authorized, | ||
}; | ||
|
||
// Here we encode the Zcash transaction with orchard bundle so it can be submited to the network | ||
let inner_tx = TransactionData::from_parts( | ||
TxVersion::V5, | ||
self.branch_id, | ||
|
@@ -239,7 +267,7 @@ impl PsbtWrapper { | |
Some(transparent_bundle), | ||
None, | ||
None, | ||
None, | ||
self.orchard_bundle.clone(), | ||
) | ||
.freeze() | ||
.unwrap(); | ||
|
@@ -260,6 +288,7 @@ impl PsbtWrapper { | |
self.expiry_height, | ||
public_key, | ||
self.branch_id, | ||
&self.orchard_bundle, | ||
); | ||
let txid_parts = tx_data.digest(zcash_primitives::transaction::txid::TxIdDigester); | ||
let script = &self.inputs_utxo[vin].script_pubkey; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And for what reasons might we need orchard_bundle in active UTXO management? I suggest removing it from here.