darkfi_money_contract/client/
pow_reward_v1.rs1use darkfi::{
20 zk::{Proof, ProvingKey},
21 zkas::ZkBinary,
22 Result,
23};
24use darkfi_sdk::{
25 blockchain::expected_reward,
26 crypto::{note::AeadEncryptedNote, pasta_prelude::*, Blind, FuncId, Keypair, PublicKey},
27 pasta::pallas,
28};
29use darkfi_serial::serialize;
30use rand::rngs::OsRng;
31use tracing::debug;
32
33use crate::{
34 client::{
35 transfer_v1::{proof::create_transfer_mint_proof, TransferCallOutput},
36 MoneyNote,
37 },
38 model::{ClearInput, Coin, MoneyPoWRewardParamsV1, Output, DARK_TOKEN_ID},
39};
40
41pub struct PoWRewardCallDebris {
42 pub params: MoneyPoWRewardParamsV1,
43 pub proofs: Vec<Proof>,
44}
45
46pub struct PoWRewardRevealed {
47 pub coin: Coin,
48 pub value_commit: pallas::Point,
49 pub token_commit: pallas::Base,
50}
51
52impl PoWRewardRevealed {
53 pub fn to_vec(&self) -> Vec<pallas::Base> {
54 let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
55
56 vec![self.coin.inner(), *valcom_coords.x(), *valcom_coords.y(), self.token_commit]
59 }
60}
61
62pub struct PoWRewardCallBuilder {
64 pub signature_keypair: Keypair,
66 pub block_height: u32,
68 pub fees: u64,
70 pub recipient: Option<PublicKey>,
72 pub spend_hook: Option<FuncId>,
74 pub user_data: Option<pallas::Base>,
76 pub mint_zkbin: ZkBinary,
78 pub mint_pk: ProvingKey,
80}
81
82impl PoWRewardCallBuilder {
83 fn _build(&self, value: u64) -> Result<PoWRewardCallDebris> {
84 debug!(target: "contract::money::client::pow_reward", "Building Money::PoWRewardV1 contract call");
85
86 let token_id = *DARK_TOKEN_ID;
89
90 let value_blind = Blind::random(&mut OsRng);
92 let token_blind = Blind::random(&mut OsRng);
93 let coin_blind = Blind::random(&mut OsRng);
94 let c_input = ClearInput {
95 value,
96 token_id,
97 value_blind,
98 token_blind,
99 signature_public: self.signature_keypair.public,
100 };
101
102 let spend_hook = self.spend_hook.unwrap_or(FuncId::none());
104 let user_data = self.user_data.unwrap_or(pallas::Base::ZERO);
105
106 let output = TransferCallOutput {
108 public_key: self.recipient.unwrap_or(self.signature_keypair.public),
109 value,
110 token_id,
111 spend_hook,
112 user_data,
113 blind: Blind::random(&mut OsRng),
114 };
115
116 debug!(target: "contract::money::client::pow_reward", "Creating token mint proof for output");
117 let (proof, public_inputs) = create_transfer_mint_proof(
118 &self.mint_zkbin,
119 &self.mint_pk,
120 &output,
121 value_blind,
122 token_blind,
123 spend_hook,
124 user_data,
125 coin_blind,
126 )?;
127
128 let note = MoneyNote {
129 value: output.value,
130 token_id: output.token_id,
131 spend_hook,
132 user_data,
133 coin_blind,
134 value_blind,
135 token_blind,
136 memo: serialize(&self.signature_keypair.secret),
137 };
138
139 let encrypted_note = AeadEncryptedNote::encrypt(¬e, &output.public_key, &mut OsRng)?;
140
141 let c_output = Output {
142 value_commit: public_inputs.value_commit,
143 token_commit: public_inputs.token_commit,
144 coin: public_inputs.coin,
145 note: encrypted_note,
146 };
147
148 let params = MoneyPoWRewardParamsV1 { input: c_input, output: c_output };
149 let debris = PoWRewardCallDebris { params, proofs: vec![proof] };
150 Ok(debris)
151 }
152
153 pub fn build(&self) -> Result<PoWRewardCallDebris> {
154 let reward = expected_reward(self.block_height) + self.fees;
155 self._build(reward)
156 }
157
158 pub fn build_with_custom_reward(&self, reward: u64) -> Result<PoWRewardCallDebris> {
160 self._build(reward + self.fees)
161 }
162}