money.rs 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{collections::HashMap, str::FromStr};
  19. use lazy_static::lazy_static;
  20. use num_bigint::BigUint;
  21. use rand::rngs::OsRng;
  22. use rusqlite::types::Value;
  23. use darkfi::{
  24. tx::Transaction,
  25. zk::{halo2::Field, proof::ProvingKey, vm::ZkCircuit, vm_heap::empty_witnesses, Proof},
  26. zkas::ZkBinary,
  27. Error, Result,
  28. };
  29. use darkfi_money_contract::{
  30. client::{
  31. compute_remainder_blind,
  32. fee_v1::{create_fee_proof, FeeCallInput, FeeCallOutput, FEE_CALL_GAS},
  33. MoneyNote, OwnCoin,
  34. },
  35. model::{
  36. Coin, Input, MoneyAuthTokenFreezeParamsV1, MoneyAuthTokenMintParamsV1, MoneyFeeParamsV1,
  37. MoneyGenesisMintParamsV1, MoneyPoWRewardParamsV1, MoneyTokenMintParamsV1,
  38. MoneyTransferParamsV1, Nullifier, Output, TokenId, DARK_TOKEN_ID,
  39. },
  40. MoneyFunction, MONEY_CONTRACT_ZKAS_FEE_NS_V1,
  41. };
  42. use darkfi_sdk::{
  43. bridgetree,
  44. crypto::{
  45. note::AeadEncryptedNote,
  46. pasta_prelude::PrimeField,
  47. smt::{PoseidonFp, EMPTY_NODES_FP},
  48. BaseBlind, FuncId, Keypair, MerkleNode, MerkleTree, PublicKey, ScalarBlind, SecretKey,
  49. MONEY_CONTRACT_ID,
  50. },
  51. dark_tree::DarkLeaf,
  52. pasta::pallas,
  53. ContractCall,
  54. };
  55. use darkfi_serial::{deserialize_async, serialize_async, AsyncEncodable};
  56. use crate::{
  57. cli_util::kaching,
  58. convert_named_params,
  59. error::WalletDbResult,
  60. walletdb::{WalletSmt, WalletStorage},
  61. Drk,
  62. };
  63. // Wallet SQL table constant names. These have to represent the `money.sql`
  64. // SQL schema. Table names are prefixed with the contract ID to avoid collisions.
  65. lazy_static! {
  66. pub static ref MONEY_TREE_TABLE: String =
  67. format!("{}_money_tree", MONEY_CONTRACT_ID.to_string());
  68. pub static ref MONEY_SMT_TABLE: String = format!("{}_money_smt", MONEY_CONTRACT_ID.to_string());
  69. pub static ref MONEY_KEYS_TABLE: String =
  70. format!("{}_money_keys", MONEY_CONTRACT_ID.to_string());
  71. pub static ref MONEY_COINS_TABLE: String =
  72. format!("{}_money_coins", MONEY_CONTRACT_ID.to_string());
  73. pub static ref MONEY_TOKENS_TABLE: String =
  74. format!("{}_money_tokens", MONEY_CONTRACT_ID.to_string());
  75. pub static ref MONEY_ALIASES_TABLE: String =
  76. format!("{}_money_aliases", MONEY_CONTRACT_ID.to_string());
  77. }
  78. // MONEY_TREE_TABLE
  79. pub const MONEY_TREE_COL_TREE: &str = "tree";
  80. // MONEY_SMT_TABLE
  81. pub const MONEY_SMT_COL_KEY: &str = "smt_key";
  82. pub const MONEY_SMT_COL_VALUE: &str = "smt_value";
  83. // MONEY_KEYS_TABLE
  84. pub const MONEY_KEYS_COL_KEY_ID: &str = "key_id";
  85. pub const MONEY_KEYS_COL_IS_DEFAULT: &str = "is_default";
  86. pub const MONEY_KEYS_COL_PUBLIC: &str = "public";
  87. pub const MONEY_KEYS_COL_SECRET: &str = "secret";
  88. // MONEY_COINS_TABLE
  89. pub const MONEY_COINS_COL_COIN: &str = "coin";
  90. pub const MONEY_COINS_COL_IS_SPENT: &str = "is_spent";
  91. pub const MONEY_COINS_COL_VALUE: &str = "value";
  92. pub const MONEY_COINS_COL_TOKEN_ID: &str = "token_id";
  93. pub const MONEY_COINS_COL_SPEND_HOOK: &str = "spend_hook";
  94. pub const MONEY_COINS_COL_USER_DATA: &str = "user_data";
  95. pub const MONEY_COINS_COL_COIN_BLIND: &str = "coin_blind";
  96. pub const MONEY_COINS_COL_VALUE_BLIND: &str = "value_blind";
  97. pub const MONEY_COINS_COL_TOKEN_BLIND: &str = "token_blind";
  98. pub const MONEY_COINS_COL_SECRET: &str = "secret";
  99. pub const MONEY_COINS_COL_LEAF_POSITION: &str = "leaf_position";
  100. pub const MONEY_COINS_COL_MEMO: &str = "memo";
  101. pub const MONEY_COINS_COL_SPENT_TX_HASH: &str = "spent_tx_hash";
  102. // MONEY_TOKENS_TABLE
  103. pub const MONEY_TOKENS_COL_TOKEN_ID: &str = "token_id";
  104. pub const MONEY_TOKENS_COL_MINT_AUTHORITY: &str = "mint_authority";
  105. pub const MONEY_TOKENS_COL_TOKEN_BLIND: &str = "token_blind";
  106. pub const MONEY_TOKENS_COL_IS_FROZEN: &str = "is_frozen";
  107. // MONEY_ALIASES_TABLE
  108. pub const MONEY_ALIASES_COL_ALIAS: &str = "alias";
  109. pub const MONEY_ALIASES_COL_TOKEN_ID: &str = "token_id";
  110. pub const BALANCE_BASE10_DECIMALS: usize = 8;
  111. impl Drk {
  112. /// Initialize wallet with tables for the Money contract.
  113. pub async fn initialize_money(&self) -> WalletDbResult<()> {
  114. // Initialize Money wallet schema
  115. let wallet_schema = include_str!("../money.sql");
  116. self.wallet.exec_batch_sql(wallet_schema)?;
  117. // Check if we have to initialize the Merkle tree.
  118. // We check if we find a row in the tree table, and if not, we create a
  119. // new tree and push it into the table.
  120. // For now, on success, we don't care what's returned, but in the future
  121. // we should actually check it.
  122. if self.get_money_tree().await.is_err() {
  123. println!("Initializing Money Merkle tree");
  124. let mut tree = MerkleTree::new(1);
  125. tree.append(MerkleNode::from(pallas::Base::ZERO));
  126. let _ = tree.mark().unwrap();
  127. let query =
  128. format!("INSERT INTO {} ({}) VALUES (?1);", *MONEY_TREE_TABLE, MONEY_TREE_COL_TREE);
  129. self.wallet.exec_sql(&query, rusqlite::params![serialize_async(&tree).await])?;
  130. println!("Successfully initialized Merkle tree for the Money contract");
  131. }
  132. // Insert DRK alias
  133. self.add_alias("DRK".to_string(), *DARK_TOKEN_ID).await?;
  134. Ok(())
  135. }
  136. /// Generate a new keypair and place it into the wallet.
  137. pub async fn money_keygen(&self) -> WalletDbResult<()> {
  138. println!("Generating a new keypair");
  139. // TODO: We might want to have hierarchical deterministic key derivation.
  140. let keypair = Keypair::random(&mut OsRng);
  141. let is_default = 0;
  142. let query = format!(
  143. "INSERT INTO {} ({}, {}, {}) VALUES (?1, ?2, ?3);",
  144. *MONEY_KEYS_TABLE,
  145. MONEY_KEYS_COL_IS_DEFAULT,
  146. MONEY_KEYS_COL_PUBLIC,
  147. MONEY_KEYS_COL_SECRET
  148. );
  149. self.wallet.exec_sql(
  150. &query,
  151. rusqlite::params![
  152. is_default,
  153. serialize_async(&keypair.public).await,
  154. serialize_async(&keypair.secret).await
  155. ],
  156. )?;
  157. println!("New address:");
  158. println!("{}", keypair.public);
  159. Ok(())
  160. }
  161. /// Fetch default secret key from the wallet.
  162. pub async fn default_secret(&self) -> Result<SecretKey> {
  163. let row = match self.wallet.query_single(
  164. &MONEY_KEYS_TABLE,
  165. &[MONEY_KEYS_COL_SECRET],
  166. convert_named_params! {(MONEY_KEYS_COL_IS_DEFAULT, 1)},
  167. ) {
  168. Ok(r) => r,
  169. Err(e) => {
  170. return Err(Error::DatabaseError(format!(
  171. "[default_secret] Default secret key retrieval failed: {e:?}"
  172. )))
  173. }
  174. };
  175. let Value::Blob(ref key_bytes) = row[0] else {
  176. return Err(Error::ParseFailed("[default_secret] Key bytes parsing failed"))
  177. };
  178. let secret_key: SecretKey = deserialize_async(key_bytes).await?;
  179. Ok(secret_key)
  180. }
  181. /// Fetch default pubkey from the wallet.
  182. pub async fn default_address(&self) -> Result<PublicKey> {
  183. let row = match self.wallet.query_single(
  184. &MONEY_KEYS_TABLE,
  185. &[MONEY_KEYS_COL_PUBLIC],
  186. convert_named_params! {(MONEY_KEYS_COL_IS_DEFAULT, 1)},
  187. ) {
  188. Ok(r) => r,
  189. Err(e) => {
  190. return Err(Error::DatabaseError(format!(
  191. "[default_address] Default address retrieval failed: {e:?}"
  192. )))
  193. }
  194. };
  195. let Value::Blob(ref key_bytes) = row[0] else {
  196. return Err(Error::ParseFailed("[default_address] Key bytes parsing failed"))
  197. };
  198. let public_key: PublicKey = deserialize_async(key_bytes).await?;
  199. Ok(public_key)
  200. }
  201. /// Set provided index address as default in the wallet.
  202. pub fn set_default_address(&self, idx: usize) -> WalletDbResult<()> {
  203. // First we update previous default record
  204. let is_default = 0;
  205. let query = format!("UPDATE {} SET {} = ?1", *MONEY_KEYS_TABLE, MONEY_KEYS_COL_IS_DEFAULT,);
  206. self.wallet.exec_sql(&query, rusqlite::params![is_default])?;
  207. // and then we set the new one
  208. let is_default = 1;
  209. let query = format!(
  210. "UPDATE {} SET {} = ?1 WHERE {} = ?2",
  211. *MONEY_KEYS_TABLE, MONEY_KEYS_COL_IS_DEFAULT, MONEY_KEYS_COL_KEY_ID,
  212. );
  213. self.wallet.exec_sql(&query, rusqlite::params![is_default, idx])
  214. }
  215. /// Fetch all pukeys from the wallet.
  216. pub async fn addresses(&self) -> Result<Vec<(u64, PublicKey, SecretKey, u64)>> {
  217. let rows = match self.wallet.query_multiple(&MONEY_KEYS_TABLE, &[], &[]) {
  218. Ok(r) => r,
  219. Err(e) => {
  220. return Err(Error::DatabaseError(format!(
  221. "[addresses] Addresses retrieval failed: {e:?}"
  222. )))
  223. }
  224. };
  225. let mut vec = Vec::with_capacity(rows.len());
  226. for row in rows {
  227. let Value::Integer(key_id) = row[0] else {
  228. return Err(Error::ParseFailed("[addresses] Key ID parsing failed"))
  229. };
  230. let Ok(key_id) = u64::try_from(key_id) else {
  231. return Err(Error::ParseFailed("[addresses] Key ID parsing failed"))
  232. };
  233. let Value::Integer(is_default) = row[1] else {
  234. return Err(Error::ParseFailed("[addresses] Is default parsing failed"))
  235. };
  236. let Ok(is_default) = u64::try_from(is_default) else {
  237. return Err(Error::ParseFailed("[addresses] Is default parsing failed"))
  238. };
  239. let Value::Blob(ref key_bytes) = row[2] else {
  240. return Err(Error::ParseFailed("[addresses] Public key bytes parsing failed"))
  241. };
  242. let public_key: PublicKey = deserialize_async(key_bytes).await?;
  243. let Value::Blob(ref key_bytes) = row[3] else {
  244. return Err(Error::ParseFailed("[addresses] Secret key bytes parsing failed"))
  245. };
  246. let secret_key: SecretKey = deserialize_async(key_bytes).await?;
  247. vec.push((key_id, public_key, secret_key, is_default));
  248. }
  249. Ok(vec)
  250. }
  251. /// Fetch all secret keys from the wallet.
  252. pub async fn get_money_secrets(&self) -> Result<Vec<SecretKey>> {
  253. let rows =
  254. match self.wallet.query_multiple(&MONEY_KEYS_TABLE, &[MONEY_KEYS_COL_SECRET], &[]) {
  255. Ok(r) => r,
  256. Err(e) => {
  257. return Err(Error::DatabaseError(format!(
  258. "[get_money_secrets] Secret keys retrieval failed: {e:?}"
  259. )))
  260. }
  261. };
  262. let mut secrets = Vec::with_capacity(rows.len());
  263. // Let's scan through the rows and see if we got anything.
  264. for row in rows {
  265. let Value::Blob(ref key_bytes) = row[0] else {
  266. return Err(Error::ParseFailed(
  267. "[get_money_secrets] Secret key bytes parsing failed",
  268. ))
  269. };
  270. let secret_key: SecretKey = deserialize_async(key_bytes).await?;
  271. secrets.push(secret_key);
  272. }
  273. Ok(secrets)
  274. }
  275. /// Import given secret keys into the wallet.
  276. /// If the key already exists, it will be skipped.
  277. /// Returns the respective PublicKey objects for the imported keys.
  278. pub async fn import_money_secrets(&self, secrets: Vec<SecretKey>) -> Result<Vec<PublicKey>> {
  279. let existing_secrets = self.get_money_secrets().await?;
  280. let mut ret = Vec::with_capacity(secrets.len());
  281. for secret in secrets {
  282. // Check if secret already exists
  283. if existing_secrets.contains(&secret) {
  284. println!("Existing key found: {secret}");
  285. continue
  286. }
  287. ret.push(PublicKey::from_secret(secret));
  288. let is_default = 0;
  289. let public = serialize_async(&PublicKey::from_secret(secret)).await;
  290. let secret = serialize_async(&secret).await;
  291. let query = format!(
  292. "INSERT INTO {} ({}, {}, {}) VALUES (?1, ?2, ?3);",
  293. *MONEY_KEYS_TABLE,
  294. MONEY_KEYS_COL_IS_DEFAULT,
  295. MONEY_KEYS_COL_PUBLIC,
  296. MONEY_KEYS_COL_SECRET
  297. );
  298. if let Err(e) =
  299. self.wallet.exec_sql(&query, rusqlite::params![is_default, public, secret])
  300. {
  301. return Err(Error::DatabaseError(format!(
  302. "[import_money_secrets] Inserting new address failed: {e:?}"
  303. )))
  304. }
  305. }
  306. Ok(ret)
  307. }
  308. /// Fetch known unspent balances from the wallet and return them as a hashmap.
  309. pub async fn money_balance(&self) -> Result<HashMap<String, u64>> {
  310. let mut coins = self.get_coins(false).await?;
  311. coins.retain(|x| x.0.note.spend_hook == FuncId::none());
  312. // Fill this map with balances
  313. let mut balmap: HashMap<String, u64> = HashMap::new();
  314. for coin in coins {
  315. let mut value = coin.0.note.value;
  316. if let Some(prev) = balmap.get(&coin.0.note.token_id.to_string()) {
  317. value += prev;
  318. }
  319. balmap.insert(coin.0.note.token_id.to_string(), value);
  320. }
  321. Ok(balmap)
  322. }
  323. /// Fetch all coins and their metadata related to the Money contract from the wallet.
  324. /// Optionally also fetch spent ones.
  325. /// The boolean in the returned tuple notes if the coin was marked as spent.
  326. pub async fn get_coins(&self, fetch_spent: bool) -> Result<Vec<(OwnCoin, bool, String)>> {
  327. let query = if fetch_spent {
  328. self.wallet.query_multiple(&MONEY_COINS_TABLE, &[], &[])
  329. } else {
  330. self.wallet.query_multiple(
  331. &MONEY_COINS_TABLE,
  332. &[],
  333. convert_named_params! {(MONEY_COINS_COL_IS_SPENT, false)},
  334. )
  335. };
  336. let rows = match query {
  337. Ok(r) => r,
  338. Err(e) => {
  339. return Err(Error::DatabaseError(format!(
  340. "[get_coins] Coins retrieval failed: {e:?}"
  341. )))
  342. }
  343. };
  344. let mut owncoins = Vec::with_capacity(rows.len());
  345. for row in rows {
  346. owncoins.push(self.parse_coin_record(&row).await?)
  347. }
  348. Ok(owncoins)
  349. }
  350. /// Fetch provided transaction coins from the wallet.
  351. pub async fn get_transaction_coins(&self, spent_tx_hash: &String) -> Result<Vec<OwnCoin>> {
  352. let query = self.wallet.query_multiple(
  353. &MONEY_COINS_TABLE,
  354. &[],
  355. convert_named_params! {(MONEY_COINS_COL_SPENT_TX_HASH, spent_tx_hash)},
  356. );
  357. let rows = match query {
  358. Ok(r) => r,
  359. Err(e) => {
  360. return Err(Error::DatabaseError(format!(
  361. "[get_transaction_coins] Coins retrieval failed: {e:?}"
  362. )))
  363. }
  364. };
  365. let mut owncoins = Vec::with_capacity(rows.len());
  366. for row in rows {
  367. owncoins.push(self.parse_coin_record(&row).await?.0)
  368. }
  369. Ok(owncoins)
  370. }
  371. /// Fetch provided token unspend balances from the wallet.
  372. pub async fn get_token_coins(&self, token_id: &TokenId) -> Result<Vec<OwnCoin>> {
  373. let query = self.wallet.query_multiple(
  374. &MONEY_COINS_TABLE,
  375. &[],
  376. convert_named_params! {(MONEY_COINS_COL_IS_SPENT, false), (MONEY_COINS_COL_TOKEN_ID, serialize_async(token_id).await), (MONEY_COINS_COL_SPEND_HOOK, serialize_async(&FuncId::none()).await)},
  377. );
  378. let rows = match query {
  379. Ok(r) => r,
  380. Err(e) => {
  381. return Err(Error::DatabaseError(format!(
  382. "[get_token_coins] Coins retrieval failed: {e:?}"
  383. )))
  384. }
  385. };
  386. let mut owncoins = Vec::with_capacity(rows.len());
  387. for row in rows {
  388. owncoins.push(self.parse_coin_record(&row).await?.0)
  389. }
  390. Ok(owncoins)
  391. }
  392. /// Fetch provided contract specified token unspend balances from the wallet.
  393. pub async fn get_contract_token_coins(
  394. &self,
  395. token_id: &TokenId,
  396. spend_hook: &FuncId,
  397. user_data: &pallas::Base,
  398. ) -> Result<Vec<OwnCoin>> {
  399. let query = self.wallet.query_multiple(
  400. &MONEY_COINS_TABLE,
  401. &[],
  402. convert_named_params! {(MONEY_COINS_COL_IS_SPENT, false), (MONEY_COINS_COL_TOKEN_ID, serialize_async(token_id).await), (MONEY_COINS_COL_SPEND_HOOK, serialize_async(spend_hook).await), (MONEY_COINS_COL_USER_DATA, serialize_async(user_data).await)},
  403. );
  404. let rows = match query {
  405. Ok(r) => r,
  406. Err(e) => {
  407. return Err(Error::DatabaseError(format!(
  408. "[get_contract_token_coins] Coins retrieval failed: {e:?}"
  409. )))
  410. }
  411. };
  412. let mut owncoins = Vec::with_capacity(rows.len());
  413. for row in rows {
  414. owncoins.push(self.parse_coin_record(&row).await?.0)
  415. }
  416. Ok(owncoins)
  417. }
  418. /// Auxiliary function to parse a `MONEY_COINS_TABLE` record.
  419. /// The boolean in the returned tuple notes if the coin was marked as spent.
  420. async fn parse_coin_record(&self, row: &[Value]) -> Result<(OwnCoin, bool, String)> {
  421. let Value::Blob(ref coin_bytes) = row[0] else {
  422. return Err(Error::ParseFailed("[parse_coin_record] Coin bytes parsing failed"))
  423. };
  424. let coin: Coin = deserialize_async(coin_bytes).await?;
  425. let Value::Integer(is_spent) = row[1] else {
  426. return Err(Error::ParseFailed("[parse_coin_record] Is spent parsing failed"))
  427. };
  428. let Ok(is_spent) = u64::try_from(is_spent) else {
  429. return Err(Error::ParseFailed("[parse_coin_record] Is spent parsing failed"))
  430. };
  431. let is_spent = is_spent > 0;
  432. let Value::Blob(ref value_bytes) = row[2] else {
  433. return Err(Error::ParseFailed("[parse_coin_record] Value bytes parsing failed"))
  434. };
  435. let value: u64 = deserialize_async(value_bytes).await?;
  436. let Value::Blob(ref token_id_bytes) = row[3] else {
  437. return Err(Error::ParseFailed("[parse_coin_record] Token ID bytes parsing failed"))
  438. };
  439. let token_id: TokenId = deserialize_async(token_id_bytes).await?;
  440. let Value::Blob(ref spend_hook_bytes) = row[4] else {
  441. return Err(Error::ParseFailed("[parse_coin_record] Spend hook bytes parsing failed"))
  442. };
  443. let spend_hook: pallas::Base = deserialize_async(spend_hook_bytes).await?;
  444. let Value::Blob(ref user_data_bytes) = row[5] else {
  445. return Err(Error::ParseFailed("[parse_coin_record] User data bytes parsing failed"))
  446. };
  447. let user_data: pallas::Base = deserialize_async(user_data_bytes).await?;
  448. let Value::Blob(ref coin_blind_bytes) = row[6] else {
  449. return Err(Error::ParseFailed("[parse_coin_record] Coin blind bytes parsing failed"))
  450. };
  451. let coin_blind: BaseBlind = deserialize_async(coin_blind_bytes).await?;
  452. let Value::Blob(ref value_blind_bytes) = row[7] else {
  453. return Err(Error::ParseFailed("[parse_coin_record] Value blind bytes parsing failed"))
  454. };
  455. let value_blind: ScalarBlind = deserialize_async(value_blind_bytes).await?;
  456. let Value::Blob(ref token_blind_bytes) = row[8] else {
  457. return Err(Error::ParseFailed("[parse_coin_record] Token blind bytes parsing failed"))
  458. };
  459. let token_blind: BaseBlind = deserialize_async(token_blind_bytes).await?;
  460. let Value::Blob(ref secret_bytes) = row[9] else {
  461. return Err(Error::ParseFailed("[parse_coin_record] Secret bytes parsing failed"))
  462. };
  463. let secret: SecretKey = deserialize_async(secret_bytes).await?;
  464. let Value::Blob(ref leaf_position_bytes) = row[10] else {
  465. return Err(Error::ParseFailed("[parse_coin_record] Leaf position bytes parsing failed"))
  466. };
  467. let leaf_position: bridgetree::Position = deserialize_async(leaf_position_bytes).await?;
  468. let Value::Blob(ref memo) = row[11] else {
  469. return Err(Error::ParseFailed("[parse_coin_record] Memo parsing failed"))
  470. };
  471. let Value::Text(ref spent_tx_hash) = row[12] else {
  472. return Err(Error::ParseFailed(
  473. "[parse_coin_record] Spent transaction hash parsing failed",
  474. ))
  475. };
  476. let note = MoneyNote {
  477. value,
  478. token_id,
  479. spend_hook: spend_hook.into(),
  480. user_data,
  481. coin_blind,
  482. value_blind,
  483. token_blind,
  484. memo: memo.clone(),
  485. };
  486. Ok((OwnCoin { coin, note, secret, leaf_position }, is_spent, spent_tx_hash.clone()))
  487. }
  488. /// Create an alias record for provided Token ID.
  489. pub async fn add_alias(&self, alias: String, token_id: TokenId) -> WalletDbResult<()> {
  490. println!("Generating alias {alias} for Token: {token_id}");
  491. let query = format!(
  492. "INSERT OR REPLACE INTO {} ({}, {}) VALUES (?1, ?2);",
  493. *MONEY_ALIASES_TABLE, MONEY_ALIASES_COL_ALIAS, MONEY_ALIASES_COL_TOKEN_ID,
  494. );
  495. self.wallet.exec_sql(
  496. &query,
  497. rusqlite::params![serialize_async(&alias).await, serialize_async(&token_id).await],
  498. )
  499. }
  500. /// Fetch all aliases from the wallet.
  501. /// Optionally filter using alias name and/or token id.
  502. pub async fn get_aliases(
  503. &self,
  504. alias_filter: Option<String>,
  505. token_id_filter: Option<TokenId>,
  506. ) -> Result<HashMap<String, TokenId>> {
  507. let rows = match self.wallet.query_multiple(&MONEY_ALIASES_TABLE, &[], &[]) {
  508. Ok(r) => r,
  509. Err(e) => {
  510. return Err(Error::DatabaseError(format!(
  511. "[get_aliases] Aliases retrieval failed: {e:?}"
  512. )))
  513. }
  514. };
  515. // Fill this map with aliases
  516. let mut map: HashMap<String, TokenId> = HashMap::new();
  517. for row in rows {
  518. let Value::Blob(ref alias_bytes) = row[0] else {
  519. return Err(Error::ParseFailed("[get_aliases] Alias bytes parsing failed"))
  520. };
  521. let alias: String = deserialize_async(alias_bytes).await?;
  522. if alias_filter.is_some() && alias_filter.as_ref().unwrap() != &alias {
  523. continue
  524. }
  525. let Value::Blob(ref token_id_bytes) = row[1] else {
  526. return Err(Error::ParseFailed("[get_aliases] TokenId bytes parsing failed"))
  527. };
  528. let token_id: TokenId = deserialize_async(token_id_bytes).await?;
  529. if token_id_filter.is_some() && token_id_filter.as_ref().unwrap() != &token_id {
  530. continue
  531. }
  532. map.insert(alias, token_id);
  533. }
  534. Ok(map)
  535. }
  536. /// Fetch all aliases from the wallet, mapped by token id.
  537. pub async fn get_aliases_mapped_by_token(&self) -> Result<HashMap<String, String>> {
  538. let aliases = self.get_aliases(None, None).await?;
  539. let mut map: HashMap<String, String> = HashMap::new();
  540. for (alias, token_id) in aliases {
  541. let aliases_string = if let Some(prev) = map.get(&token_id.to_string()) {
  542. format!("{}, {}", prev, alias)
  543. } else {
  544. alias
  545. };
  546. map.insert(token_id.to_string(), aliases_string);
  547. }
  548. Ok(map)
  549. }
  550. /// Remove provided alias record from the wallet database.
  551. pub async fn remove_alias(&self, alias: String) -> WalletDbResult<()> {
  552. println!("Removing alias: {alias}");
  553. let query = format!(
  554. "DELETE FROM {} WHERE {} = ?1;",
  555. *MONEY_ALIASES_TABLE, MONEY_ALIASES_COL_ALIAS,
  556. );
  557. self.wallet.exec_sql(&query, rusqlite::params![serialize_async(&alias).await])
  558. }
  559. /// Mark a given coin in the wallet as unspent.
  560. pub async fn unspend_coin(&self, coin: &Coin) -> WalletDbResult<()> {
  561. let is_spend = 0;
  562. let query = format!(
  563. "UPDATE {} SET {} = ?1, {} = ?2 WHERE {} = ?3;",
  564. *MONEY_COINS_TABLE,
  565. MONEY_COINS_COL_IS_SPENT,
  566. MONEY_COINS_COL_SPENT_TX_HASH,
  567. MONEY_COINS_COL_COIN
  568. );
  569. self.wallet.exec_sql(
  570. &query,
  571. rusqlite::params![is_spend, "-", serialize_async(&coin.inner()).await],
  572. )
  573. }
  574. /// Replace the Money Merkle tree in the wallet.
  575. pub async fn put_money_tree(&self, tree: &MerkleTree) -> WalletDbResult<()> {
  576. let query = format!("UPDATE {} SET {} = ?1;", *MONEY_TREE_TABLE, MONEY_TREE_COL_TREE);
  577. self.wallet.exec_sql(&query, rusqlite::params![serialize_async(tree).await])
  578. }
  579. /// Fetch the Money Merkle tree from the wallet.
  580. pub async fn get_money_tree(&self) -> Result<MerkleTree> {
  581. let row = match self.wallet.query_single(&MONEY_TREE_TABLE, &[MONEY_TREE_COL_TREE], &[]) {
  582. Ok(r) => r,
  583. Err(e) => {
  584. return Err(Error::DatabaseError(format!(
  585. "[get_money_tree] Tree retrieval failed: {e:?}"
  586. )))
  587. }
  588. };
  589. let Value::Blob(ref tree_bytes) = row[0] else {
  590. return Err(Error::ParseFailed("[get_money_tree] Tree bytes parsing failed"))
  591. };
  592. let tree = deserialize_async(tree_bytes).await?;
  593. Ok(tree)
  594. }
  595. /// Auxiliary function to fetch the current Money Merkle tree state,
  596. /// as an update query.
  597. pub async fn get_money_tree_state_query(&self) -> Result<String> {
  598. // Grab current money tree
  599. let tree = self.get_money_tree().await?;
  600. // Create the update query
  601. match self.wallet.create_prepared_statement(
  602. &format!("UPDATE {} SET {} = ?1;", *MONEY_TREE_TABLE, MONEY_TREE_COL_TREE),
  603. rusqlite::params![serialize_async(&tree).await],
  604. ) {
  605. Ok(q) => Ok(q),
  606. Err(e) => Err(Error::DatabaseError(format!(
  607. "[get_money_tree_state_query] Creating query for money tree failed: {e:?}"
  608. ))),
  609. }
  610. }
  611. /// Fetch the Money nullifiers SMT from the wallet, as a map.
  612. pub async fn get_nullifiers_smt(&self) -> Result<HashMap<BigUint, pallas::Base>> {
  613. let rows = match self.wallet.query_multiple(&MONEY_SMT_TABLE, &[], &[]) {
  614. Ok(r) => r,
  615. Err(e) => {
  616. return Err(Error::DatabaseError(format!(
  617. "[get_nullifiers_smt] SMT records retrieval failed: {e:?}"
  618. )))
  619. }
  620. };
  621. let mut smt = HashMap::new();
  622. for row in rows {
  623. let Value::Blob(ref key_bytes) = row[0] else {
  624. return Err(Error::ParseFailed("[get_nullifiers_smt] Key bytes parsing failed"))
  625. };
  626. let key = BigUint::from_bytes_le(key_bytes);
  627. let Value::Blob(ref value_bytes) = row[1] else {
  628. return Err(Error::ParseFailed("[get_nullifiers_smt] Value bytes parsing failed"))
  629. };
  630. let mut repr = [0; 32];
  631. repr.copy_from_slice(value_bytes);
  632. let Some(value) = pallas::Base::from_repr(repr).into() else {
  633. return Err(Error::ParseFailed("[get_nullifiers_smt] Value conversion failed"))
  634. };
  635. smt.insert(key, value);
  636. }
  637. Ok(smt)
  638. }
  639. /// Auxiliary function to grab all the nullifiers, coins, notes and freezes from
  640. /// a transaction money call.
  641. async fn parse_money_call(
  642. &self,
  643. call_idx: usize,
  644. calls: &[DarkLeaf<ContractCall>],
  645. ) -> Result<(Vec<Nullifier>, Vec<Coin>, Vec<AeadEncryptedNote>, Vec<TokenId>)> {
  646. let mut nullifiers: Vec<Nullifier> = vec![];
  647. let mut coins: Vec<Coin> = vec![];
  648. let mut notes: Vec<AeadEncryptedNote> = vec![];
  649. let mut freezes: Vec<TokenId> = vec![];
  650. let call = &calls[call_idx];
  651. let data = &call.data.data;
  652. match MoneyFunction::try_from(data[0])? {
  653. MoneyFunction::FeeV1 => {
  654. println!("[parse_money_call] Found Money::FeeV1 call");
  655. let params: MoneyFeeParamsV1 = deserialize_async(&data[9..]).await?;
  656. nullifiers.push(params.input.nullifier);
  657. coins.push(params.output.coin);
  658. notes.push(params.output.note);
  659. }
  660. MoneyFunction::GenesisMintV1 => {
  661. println!("[parse_money_call] Found Money::GenesisMintV1 call");
  662. let params: MoneyGenesisMintParamsV1 = deserialize_async(&data[1..]).await?;
  663. coins.push(params.output.coin);
  664. notes.push(params.output.note);
  665. }
  666. MoneyFunction::PoWRewardV1 => {
  667. println!("[parse_money_call] Found Money::PoWRewardV1 call");
  668. let params: MoneyPoWRewardParamsV1 = deserialize_async(&data[1..]).await?;
  669. coins.push(params.output.coin);
  670. notes.push(params.output.note);
  671. }
  672. MoneyFunction::TransferV1 => {
  673. println!("[parse_money_call] Found Money::TransferV1 call");
  674. let params: MoneyTransferParamsV1 = deserialize_async(&data[1..]).await?;
  675. for input in params.inputs {
  676. nullifiers.push(input.nullifier);
  677. }
  678. for output in params.outputs {
  679. coins.push(output.coin);
  680. notes.push(output.note);
  681. }
  682. }
  683. MoneyFunction::OtcSwapV1 => {
  684. println!("[parse_money_call] Found Money::OtcSwapV1 call");
  685. let params: MoneyTransferParamsV1 = deserialize_async(&data[1..]).await?;
  686. for input in params.inputs {
  687. nullifiers.push(input.nullifier);
  688. }
  689. for output in params.outputs {
  690. coins.push(output.coin);
  691. notes.push(output.note);
  692. }
  693. }
  694. MoneyFunction::AuthTokenMintV1 => {
  695. println!("[parse_money_call] Found Money::AuthTokenMintV1 call");
  696. // Handled in TokenMint
  697. }
  698. MoneyFunction::AuthTokenFreezeV1 => {
  699. println!("[parse_money_call] Found Money::AuthTokenFreezeV1 call");
  700. let params: MoneyAuthTokenFreezeParamsV1 = deserialize_async(&data[1..]).await?;
  701. freezes.push(params.token_id);
  702. }
  703. MoneyFunction::TokenMintV1 => {
  704. println!("[parse_money_call] Found Money::TokenMintV1 call");
  705. let params: MoneyTokenMintParamsV1 = deserialize_async(&data[1..]).await?;
  706. coins.push(params.coin);
  707. // Grab the note from the child auth call
  708. let child_idx = call.children_indexes[0];
  709. let child_call = &calls[child_idx];
  710. let params: MoneyAuthTokenMintParamsV1 =
  711. deserialize_async(&child_call.data.data[1..]).await?;
  712. notes.push(params.enc_note);
  713. }
  714. }
  715. Ok((nullifiers, coins, notes, freezes))
  716. }
  717. /// Append data related to Money contract transactions into the wallet database,
  718. /// and store their inverse queries into the cache.
  719. /// Returns a flag indicating if the provided data refer to our own wallet.
  720. pub async fn apply_tx_money_data(
  721. &self,
  722. call_idx: usize,
  723. calls: &[DarkLeaf<ContractCall>],
  724. tx_hash: &String,
  725. ) -> Result<bool> {
  726. let (nullifiers, coins, notes, freezes) = self.parse_money_call(call_idx, calls).await?;
  727. let secrets = self.get_money_secrets().await?;
  728. let dao_notes_secrets = self.get_dao_notes_secrets().await?;
  729. let mut tree = self.get_money_tree().await?;
  730. let mut owncoins = vec![];
  731. for (coin, note) in coins.iter().zip(notes.iter()) {
  732. // Append the new coin to the Merkle tree. Every coin has to be added.
  733. tree.append(MerkleNode::from(coin.inner()));
  734. // Attempt to decrypt the note
  735. for secret in secrets.iter().chain(dao_notes_secrets.iter()) {
  736. if let Ok(note) = note.decrypt::<MoneyNote>(secret) {
  737. println!("[apply_tx_money_data] Successfully decrypted a Money Note");
  738. println!("[apply_tx_money_data] Witnessing coin in Merkle tree");
  739. let leaf_position = tree.mark().unwrap();
  740. let owncoin =
  741. OwnCoin { coin: *coin, note: note.clone(), secret: *secret, leaf_position };
  742. owncoins.push(owncoin);
  743. }
  744. }
  745. }
  746. if let Err(e) = self.put_money_tree(&tree).await {
  747. return Err(Error::DatabaseError(format!(
  748. "[apply_tx_money_data] Put Money tree failed: {e:?}"
  749. )))
  750. }
  751. self.smt_insert(&nullifiers)?;
  752. let wallet_spent_coins = self.mark_spent_coins(&nullifiers, tx_hash).await?;
  753. // This is the SQL query we'll be executing to insert new coins into the wallet
  754. let query = format!(
  755. "INSERT INTO {} ({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12);",
  756. *MONEY_COINS_TABLE,
  757. MONEY_COINS_COL_COIN,
  758. MONEY_COINS_COL_IS_SPENT,
  759. MONEY_COINS_COL_VALUE,
  760. MONEY_COINS_COL_TOKEN_ID,
  761. MONEY_COINS_COL_SPEND_HOOK,
  762. MONEY_COINS_COL_USER_DATA,
  763. MONEY_COINS_COL_COIN_BLIND,
  764. MONEY_COINS_COL_VALUE_BLIND,
  765. MONEY_COINS_COL_TOKEN_BLIND,
  766. MONEY_COINS_COL_SECRET,
  767. MONEY_COINS_COL_LEAF_POSITION,
  768. MONEY_COINS_COL_MEMO,
  769. );
  770. // This is its inverse query
  771. let inverse_query =
  772. format!("DELETE FROM {} WHERE {} = ?1;", *MONEY_COINS_TABLE, MONEY_COINS_COL_COIN);
  773. println!("Found {} OwnCoin(s) in transaction", owncoins.len());
  774. for owncoin in &owncoins {
  775. println!("OwnCoin: {:?}", owncoin.coin);
  776. // Grab coin record key
  777. let key = serialize_async(&owncoin.coin).await;
  778. // Create its inverse query
  779. let inverse =
  780. match self.wallet.create_prepared_statement(&inverse_query, rusqlite::params![key])
  781. {
  782. Ok(q) => q,
  783. Err(e) => {
  784. return Err(Error::DatabaseError(format!(
  785. "[apply_tx_money_data] Creating Money coin insert inverse query failed: {e:?}"
  786. )))
  787. }
  788. };
  789. // Execute the query
  790. let params = rusqlite::params![
  791. key,
  792. 0, // <-- is_spent
  793. serialize_async(&owncoin.note.value).await,
  794. serialize_async(&owncoin.note.token_id).await,
  795. serialize_async(&owncoin.note.spend_hook).await,
  796. serialize_async(&owncoin.note.user_data).await,
  797. serialize_async(&owncoin.note.coin_blind).await,
  798. serialize_async(&owncoin.note.value_blind).await,
  799. serialize_async(&owncoin.note.token_blind).await,
  800. serialize_async(&owncoin.secret).await,
  801. serialize_async(&owncoin.leaf_position).await,
  802. serialize_async(&owncoin.note.memo).await,
  803. ];
  804. if let Err(e) = self.wallet.exec_sql(&query, params) {
  805. return Err(Error::DatabaseError(format!(
  806. "[apply_tx_money_data] Inserting Money coin failed: {e:?}"
  807. )))
  808. }
  809. // Store its inverse
  810. if let Err(e) = self.wallet.cache_inverse(inverse) {
  811. return Err(Error::DatabaseError(format!(
  812. "[apply_tx_money_data] Inserting inverse query into cache failed: {e:?}"
  813. )))
  814. }
  815. }
  816. // This is the SQL query we'll be executing to update frozen tokens into the wallet
  817. let query = format!(
  818. "UPDATE {} SET {} = 1 WHERE {} = ?1;",
  819. *MONEY_TOKENS_TABLE, MONEY_TOKENS_COL_IS_FROZEN, MONEY_TOKENS_COL_TOKEN_ID,
  820. );
  821. // This is its inverse query
  822. let inverse_query = format!(
  823. "UPDATE {} SET {} = 0 WHERE {} = ?1;",
  824. *MONEY_TOKENS_TABLE, MONEY_TOKENS_COL_IS_FROZEN, MONEY_TOKENS_COL_TOKEN_ID,
  825. );
  826. for token_id in &freezes {
  827. // Grab token record key
  828. let key = serialize_async(token_id).await;
  829. // Create its inverse query
  830. let inverse =
  831. match self.wallet.create_prepared_statement(&inverse_query, rusqlite::params![key])
  832. {
  833. Ok(q) => q,
  834. Err(e) => {
  835. return Err(Error::DatabaseError(format!(
  836. "[apply_tx_money_data] Creating Money token freeze inverse query failed: {e:?}"
  837. )))
  838. }
  839. };
  840. // Execute the query
  841. if let Err(e) = self.wallet.exec_sql(&query, rusqlite::params![key]) {
  842. return Err(Error::DatabaseError(format!(
  843. "[apply_tx_money_data] Update Money token freeze failed: {e:?}"
  844. )))
  845. }
  846. // Store its inverse
  847. if let Err(e) = self.wallet.cache_inverse(inverse) {
  848. return Err(Error::DatabaseError(format!(
  849. "[apply_tx_money_data] Inserting inverse query into cache failed: {e:?}"
  850. )))
  851. }
  852. }
  853. if self.fun && !owncoins.is_empty() {
  854. kaching().await;
  855. }
  856. Ok(wallet_spent_coins || !owncoins.is_empty() || !freezes.is_empty())
  857. }
  858. /// Auxiliary function to grab all the nullifiers from a transaction money call.
  859. async fn money_call_nullifiers(&self, call: &DarkLeaf<ContractCall>) -> Result<Vec<Nullifier>> {
  860. let mut nullifiers: Vec<Nullifier> = vec![];
  861. let data = &call.data.data;
  862. match MoneyFunction::try_from(data[0])? {
  863. MoneyFunction::FeeV1 => {
  864. let params: MoneyFeeParamsV1 = deserialize_async(&data[9..]).await?;
  865. nullifiers.push(params.input.nullifier);
  866. }
  867. MoneyFunction::TransferV1 => {
  868. let params: MoneyTransferParamsV1 = deserialize_async(&data[1..]).await?;
  869. for input in params.inputs {
  870. nullifiers.push(input.nullifier);
  871. }
  872. }
  873. MoneyFunction::OtcSwapV1 => {
  874. let params: MoneyTransferParamsV1 = deserialize_async(&data[1..]).await?;
  875. for input in params.inputs {
  876. nullifiers.push(input.nullifier);
  877. }
  878. }
  879. _ => { /* Do nothing */ }
  880. }
  881. Ok(nullifiers)
  882. }
  883. /// Mark provided transaction input coins as spent.
  884. pub async fn mark_tx_spend(&self, tx: &Transaction) -> Result<()> {
  885. let tx_hash = tx.hash().to_string();
  886. println!("[mark_tx_spend] Processing transaction: {tx_hash}");
  887. for (i, call) in tx.calls.iter().enumerate() {
  888. if call.data.contract_id != *MONEY_CONTRACT_ID {
  889. continue
  890. }
  891. println!("[mark_tx_spend] Found Money contract in call {i}");
  892. let nullifiers = self.money_call_nullifiers(call).await?;
  893. self.mark_spent_coins(&nullifiers, &tx_hash).await?;
  894. }
  895. Ok(())
  896. }
  897. /// Mark a coin in the wallet as spent, and store its inverse query into the cache.
  898. pub async fn mark_spent_coin(&self, coin: &Coin, spent_tx_hash: &String) -> WalletDbResult<()> {
  899. // Grab coin record key
  900. let key = serialize_async(&coin.inner()).await;
  901. // Create an SQL `UPDATE` query to mark rows as spent(1)
  902. let query = format!(
  903. "UPDATE {} SET {} = 1, {} = ?1 WHERE {} = ?2;",
  904. *MONEY_COINS_TABLE,
  905. MONEY_COINS_COL_IS_SPENT,
  906. MONEY_COINS_COL_SPENT_TX_HASH,
  907. MONEY_COINS_COL_COIN
  908. );
  909. // Create its inverse query
  910. let inverse = self.wallet.create_prepared_statement(
  911. &format!(
  912. "UPDATE {} SET {} = 0, {} = '-' WHERE {} = ?1;",
  913. *MONEY_COINS_TABLE,
  914. MONEY_COINS_COL_IS_SPENT,
  915. MONEY_COINS_COL_SPENT_TX_HASH,
  916. MONEY_COINS_COL_COIN
  917. ),
  918. rusqlite::params![key],
  919. )?;
  920. // Execute the query
  921. self.wallet.exec_sql(&query, rusqlite::params![spent_tx_hash, key])?;
  922. // Store its inverse
  923. self.wallet.cache_inverse(inverse)
  924. }
  925. /// Marks all coins in the wallet as spent, if their nullifier is in the given set.
  926. /// Returns a flag indicating if any of the provided nullifiers refer to our own wallet.
  927. pub async fn mark_spent_coins(
  928. &self,
  929. nullifiers: &[Nullifier],
  930. spent_tx_hash: &String,
  931. ) -> Result<bool> {
  932. if nullifiers.is_empty() {
  933. return Ok(false)
  934. }
  935. // First we remark transaction spent coins
  936. let mut wallet_spent_coins = false;
  937. for coin in self.get_transaction_coins(spent_tx_hash).await? {
  938. if let Err(e) = self.mark_spent_coin(&coin.coin, spent_tx_hash).await {
  939. return Err(Error::DatabaseError(format!(
  940. "[mark_spent_coins] Marking spent coin failed: {e:?}"
  941. )))
  942. }
  943. wallet_spent_coins = true;
  944. }
  945. // Then we mark transaction unspent coins
  946. for (coin, _, _) in self.get_coins(false).await? {
  947. if !nullifiers.contains(&coin.nullifier()) {
  948. continue
  949. }
  950. if let Err(e) = self.mark_spent_coin(&coin.coin, spent_tx_hash).await {
  951. return Err(Error::DatabaseError(format!(
  952. "[mark_spent_coins] Marking spent coin failed: {e:?}"
  953. )))
  954. }
  955. wallet_spent_coins = true;
  956. }
  957. Ok(wallet_spent_coins)
  958. }
  959. /// Inserts given slice to the wallets nullifiers Sparse Merkle Tree.
  960. pub fn smt_insert(&self, nullifiers: &[Nullifier]) -> Result<()> {
  961. let store = WalletStorage::new(
  962. &self.wallet,
  963. &MONEY_SMT_TABLE,
  964. MONEY_SMT_COL_KEY,
  965. MONEY_SMT_COL_VALUE,
  966. );
  967. let mut smt = WalletSmt::new(store, PoseidonFp::new(), &EMPTY_NODES_FP);
  968. let leaves: Vec<_> = nullifiers.iter().map(|x| (x.inner(), x.inner())).collect();
  969. smt.insert_batch(leaves)?;
  970. Ok(())
  971. }
  972. /// Reset the Money Merkle tree in the wallet.
  973. pub async fn reset_money_tree(&self) -> WalletDbResult<()> {
  974. println!("Resetting Money Merkle tree");
  975. let mut tree = MerkleTree::new(1);
  976. tree.append(MerkleNode::from(pallas::Base::ZERO));
  977. let _ = tree.mark().unwrap();
  978. self.put_money_tree(&tree).await?;
  979. println!("Successfully reset Money Merkle tree");
  980. Ok(())
  981. }
  982. /// Reset the Money nullifiers Sparse Merkle Tree in the wallet.
  983. pub fn reset_money_smt(&self) -> WalletDbResult<()> {
  984. println!("Resetting Money Sparse Merkle tree");
  985. let query = format!("DELETE FROM {};", *MONEY_SMT_TABLE);
  986. self.wallet.exec_sql(&query, &[])?;
  987. println!("Successfully reset Money Sparse Merkle tree");
  988. Ok(())
  989. }
  990. /// Reset the Money coins in the wallet.
  991. pub fn reset_money_coins(&self) -> WalletDbResult<()> {
  992. println!("Resetting coins");
  993. let query = format!("DELETE FROM {};", *MONEY_COINS_TABLE);
  994. self.wallet.exec_sql(&query, &[])?;
  995. println!("Successfully reset coins");
  996. Ok(())
  997. }
  998. /// Retrieve token by provided string.
  999. /// Input string represents either an alias or a token id.
  1000. pub async fn get_token(&self, input: String) -> Result<TokenId> {
  1001. // Check if input is an alias(max 5 characters)
  1002. if input.chars().count() <= 5 {
  1003. let aliases = self.get_aliases(Some(input.clone()), None).await?;
  1004. if let Some(token_id) = aliases.get(&input) {
  1005. return Ok(*token_id)
  1006. }
  1007. }
  1008. // Else parse input
  1009. Ok(TokenId::from_str(input.as_str())?)
  1010. }
  1011. /// Create and append a `Money::Fee` call to a given [`Transaction`].
  1012. ///
  1013. /// Optionally takes a set of spent coins in order not to reuse them here.
  1014. ///
  1015. /// Returns the `Fee` call, and all necessary data and parameters related.
  1016. pub async fn append_fee_call(
  1017. &self,
  1018. tx: &Transaction,
  1019. money_merkle_tree: &MerkleTree,
  1020. fee_pk: &ProvingKey,
  1021. fee_zkbin: &ZkBinary,
  1022. spent_coins: Option<&[OwnCoin]>,
  1023. ) -> Result<(ContractCall, Vec<Proof>, Vec<SecretKey>)> {
  1024. // First we verify the fee-less transaction to see how much gas it uses for execution
  1025. // and verification.
  1026. let gas_used = FEE_CALL_GAS + self.get_tx_gas(tx, false).await?;
  1027. // Knowing the total gas, we can now find an OwnCoin of enough value
  1028. // so that we can create a valid Money::Fee call.
  1029. let mut available_coins = self.get_token_coins(&DARK_TOKEN_ID).await?;
  1030. available_coins.retain(|x| x.note.value > gas_used);
  1031. if let Some(spent_coins) = spent_coins {
  1032. available_coins.retain(|x| !spent_coins.contains(x));
  1033. }
  1034. if available_coins.is_empty() {
  1035. return Err(Error::Custom("Not enough native tokens to pay for fees".to_string()))
  1036. }
  1037. let coin = &available_coins[0];
  1038. let change_value = coin.note.value - gas_used;
  1039. // Input and output setup
  1040. let input = FeeCallInput {
  1041. coin: coin.clone(),
  1042. merkle_path: money_merkle_tree.witness(coin.leaf_position, 0).unwrap(),
  1043. user_data_blind: BaseBlind::random(&mut OsRng),
  1044. };
  1045. let output = FeeCallOutput {
  1046. public_key: PublicKey::from_secret(coin.secret),
  1047. value: change_value,
  1048. token_id: coin.note.token_id,
  1049. blind: BaseBlind::random(&mut OsRng),
  1050. spend_hook: FuncId::none(),
  1051. user_data: pallas::Base::ZERO,
  1052. };
  1053. // Create blinding factors
  1054. let token_blind = BaseBlind::random(&mut OsRng);
  1055. let input_value_blind = ScalarBlind::random(&mut OsRng);
  1056. let fee_value_blind = ScalarBlind::random(&mut OsRng);
  1057. let output_value_blind = compute_remainder_blind(&[input_value_blind], &[fee_value_blind]);
  1058. // Create an ephemeral signing key
  1059. let signature_secret = SecretKey::random(&mut OsRng);
  1060. // Create the actual fee proof
  1061. let (proof, public_inputs) = create_fee_proof(
  1062. fee_zkbin,
  1063. fee_pk,
  1064. &input,
  1065. input_value_blind,
  1066. &output,
  1067. output_value_blind,
  1068. output.spend_hook,
  1069. output.user_data,
  1070. output.blind,
  1071. token_blind,
  1072. signature_secret,
  1073. )?;
  1074. // Encrypted note for the output
  1075. let note = MoneyNote {
  1076. coin_blind: output.blind,
  1077. value: output.value,
  1078. token_id: output.token_id,
  1079. spend_hook: output.spend_hook,
  1080. user_data: output.user_data,
  1081. value_blind: output_value_blind,
  1082. token_blind,
  1083. memo: vec![],
  1084. };
  1085. let encrypted_note = AeadEncryptedNote::encrypt(&note, &output.public_key, &mut OsRng)?;
  1086. let params = MoneyFeeParamsV1 {
  1087. input: Input {
  1088. value_commit: public_inputs.input_value_commit,
  1089. token_commit: public_inputs.token_commit,
  1090. nullifier: public_inputs.nullifier,
  1091. merkle_root: public_inputs.merkle_root,
  1092. user_data_enc: public_inputs.input_user_data_enc,
  1093. signature_public: public_inputs.signature_public,
  1094. },
  1095. output: Output {
  1096. value_commit: public_inputs.output_value_commit,
  1097. token_commit: public_inputs.token_commit,
  1098. coin: public_inputs.output_coin,
  1099. note: encrypted_note,
  1100. },
  1101. fee_value_blind,
  1102. token_blind,
  1103. };
  1104. // Encode the contract call
  1105. let mut data = vec![MoneyFunction::FeeV1 as u8];
  1106. gas_used.encode_async(&mut data).await?;
  1107. params.encode_async(&mut data).await?;
  1108. let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
  1109. Ok((call, vec![proof], vec![signature_secret]))
  1110. }
  1111. /// Create and attach the fee call to given transaction.
  1112. pub async fn attach_fee(&self, tx: &mut Transaction) -> Result<()> {
  1113. // Grab spent coins nullifiers of the transactions and check no other fee call exists
  1114. let mut tx_nullifiers = vec![];
  1115. for call in &tx.calls {
  1116. if call.data.contract_id != *MONEY_CONTRACT_ID {
  1117. continue
  1118. }
  1119. match MoneyFunction::try_from(call.data.data[0])? {
  1120. MoneyFunction::FeeV1 => {
  1121. return Err(Error::Custom("Fee call already exists".to_string()))
  1122. }
  1123. _ => { /* Do nothing */ }
  1124. }
  1125. let nullifiers = self.money_call_nullifiers(call).await?;
  1126. tx_nullifiers.extend_from_slice(&nullifiers);
  1127. }
  1128. // Grab all native owncoins to check if any is spent
  1129. let mut spent_coins = vec![];
  1130. let available_coins = self.get_token_coins(&DARK_TOKEN_ID).await?;
  1131. for coin in available_coins {
  1132. if tx_nullifiers.contains(&coin.nullifier()) {
  1133. spent_coins.push(coin);
  1134. }
  1135. }
  1136. // Now we need to do a lookup for the zkas proof bincodes, and create
  1137. // the circuit objects and proving keys so we can build the transaction.
  1138. // We also do this through the RPC.
  1139. let zkas_bins = self.lookup_zkas(&MONEY_CONTRACT_ID).await?;
  1140. let Some(fee_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_FEE_NS_V1)
  1141. else {
  1142. return Err(Error::Custom("Fee circuit not found".to_string()))
  1143. };
  1144. let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
  1145. let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
  1146. // Creating Fee circuits proving keys
  1147. let fee_pk = ProvingKey::build(fee_zkbin.k, &fee_circuit);
  1148. // We first have to execute the fee-less tx to gather its used gas, and then we feed
  1149. // it into the fee-creating function.
  1150. let tree = self.get_money_tree().await?;
  1151. let (fee_call, fee_proofs, fee_secrets) =
  1152. self.append_fee_call(tx, &tree, &fee_pk, &fee_zkbin, Some(&spent_coins)).await?;
  1153. // Append the fee call to the transaction
  1154. tx.calls.push(DarkLeaf { data: fee_call, parent_index: None, children_indexes: vec![] });
  1155. tx.proofs.push(fee_proofs);
  1156. let sigs = tx.create_sigs(&fee_secrets)?;
  1157. tx.signatures.push(sigs);
  1158. Ok(())
  1159. }
  1160. }