money.rs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  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 rand::rngs::OsRng;
  21. use rusqlite::types::Value;
  22. use darkfi::{tx::Transaction, zk::halo2::Field, Error, Result};
  23. use darkfi_money_contract::{
  24. client::{MoneyNote, OwnCoin},
  25. model::{
  26. Coin, MoneyTokenFreezeParamsV1, MoneyTokenMintParamsV1, MoneyTransferParamsV1, Nullifier,
  27. TokenId,
  28. },
  29. MoneyFunction,
  30. };
  31. use darkfi_sdk::{
  32. bridgetree,
  33. crypto::{
  34. note::AeadEncryptedNote, BaseBlind, FuncId, Keypair, MerkleNode, MerkleTree, PublicKey,
  35. ScalarBlind, SecretKey, MONEY_CONTRACT_ID,
  36. },
  37. pasta::pallas,
  38. };
  39. use darkfi_serial::{deserialize, serialize};
  40. use crate::{
  41. convert_named_params,
  42. error::{WalletDbError, WalletDbResult},
  43. kaching, Drk,
  44. };
  45. // Wallet SQL table constant names. These have to represent the `wallet.sql`
  46. // SQL schema. Table names are prefixed with the contract ID to avoid collisions.
  47. lazy_static! {
  48. pub static ref MONEY_INFO_TABLE: String =
  49. format!("{}_money_info", MONEY_CONTRACT_ID.to_string());
  50. pub static ref MONEY_TREE_TABLE: String =
  51. format!("{}_money_tree", MONEY_CONTRACT_ID.to_string());
  52. pub static ref MONEY_KEYS_TABLE: String =
  53. format!("{}_money_keys", MONEY_CONTRACT_ID.to_string());
  54. pub static ref MONEY_COINS_TABLE: String =
  55. format!("{}_money_coins", MONEY_CONTRACT_ID.to_string());
  56. pub static ref MONEY_TOKENS_TABLE: String =
  57. format!("{}_money_tokens", MONEY_CONTRACT_ID.to_string());
  58. pub static ref MONEY_ALIASES_TABLE: String =
  59. format!("{}_money_aliases", MONEY_CONTRACT_ID.to_string());
  60. }
  61. // MONEY_INFO_TABLE
  62. pub const MONEY_INFO_COL_LAST_SCANNED_BLOCK: &str = "last_scanned_block";
  63. // MONEY_TREE_TABLE
  64. pub const MONEY_TREE_COL_TREE: &str = "tree";
  65. // MONEY_KEYS_TABLE
  66. pub const MONEY_KEYS_COL_KEY_ID: &str = "key_id";
  67. pub const MONEY_KEYS_COL_IS_DEFAULT: &str = "is_default";
  68. pub const MONEY_KEYS_COL_PUBLIC: &str = "public";
  69. pub const MONEY_KEYS_COL_SECRET: &str = "secret";
  70. // MONEY_COINS_TABLE
  71. pub const MONEY_COINS_COL_COIN: &str = "coin";
  72. pub const MONEY_COINS_COL_IS_SPENT: &str = "is_spent";
  73. pub const MONEY_COINS_COL_SERIAL: &str = "serial";
  74. pub const MONEY_COINS_COL_VALUE: &str = "value";
  75. pub const MONEY_COINS_COL_TOKEN_ID: &str = "token_id";
  76. pub const MONEY_COINS_COL_SPEND_HOOK: &str = "spend_hook";
  77. pub const MONEY_COINS_COL_USER_DATA: &str = "user_data";
  78. pub const MONEY_COINS_COL_VALUE_BLIND: &str = "value_blind";
  79. pub const MONEY_COINS_COL_TOKEN_BLIND: &str = "token_blind";
  80. pub const MONEY_COINS_COL_SECRET: &str = "secret";
  81. pub const MONEY_COINS_COL_NULLIFIER: &str = "nullifier";
  82. pub const MONEY_COINS_COL_LEAF_POSITION: &str = "leaf_position";
  83. pub const MONEY_COINS_COL_MEMO: &str = "memo";
  84. // MONEY_TOKENS_TABLE
  85. pub const MONEY_TOKENS_COL_MINT_AUTHORITY: &str = "mint_authority";
  86. pub const MONEY_TOKENS_COL_TOKEN_ID: &str = "token_id";
  87. pub const MONEY_TOKENS_COL_IS_FROZEN: &str = "is_frozen";
  88. // MONEY_ALIASES_TABLE
  89. pub const MONEY_ALIASES_COL_ALIAS: &str = "alias";
  90. pub const MONEY_ALIASES_COL_TOKEN_ID: &str = "token_id";
  91. pub const BALANCE_BASE10_DECIMALS: usize = 8;
  92. impl Drk {
  93. /// Initialize wallet with tables for the Money contract.
  94. pub async fn initialize_money(&self) -> WalletDbResult<()> {
  95. // Initialize Money wallet schema
  96. let wallet_schema = include_str!("../money.sql");
  97. self.wallet.exec_batch_sql(wallet_schema).await?;
  98. // Check if we have to initialize the Merkle tree.
  99. // We check if we find a row in the tree table, and if not, we create a
  100. // new tree and push it into the table.
  101. // For now, on success, we don't care what's returned, but in the future
  102. // we should actually check it.
  103. if self.get_money_tree().await.is_err() {
  104. eprintln!("Initializing Money Merkle tree");
  105. let mut tree = MerkleTree::new(100);
  106. tree.append(MerkleNode::from(pallas::Base::ZERO));
  107. let _ = tree.mark().unwrap();
  108. self.put_money_tree(&tree).await?;
  109. eprintln!("Successfully initialized Merkle tree for the Money contract");
  110. }
  111. // We maintain the last scanned block as part of the Money contract,
  112. // but at this moment it is also somewhat applicable to DAO scans.
  113. if self.last_scanned_block().await.is_err() {
  114. let query = format!(
  115. "INSERT INTO {} ({}) VALUES (?1);",
  116. *MONEY_INFO_TABLE, MONEY_INFO_COL_LAST_SCANNED_BLOCK
  117. );
  118. self.wallet.exec_sql(&query, rusqlite::params![0]).await?;
  119. }
  120. Ok(())
  121. }
  122. /// Generate a new keypair and place it into the wallet.
  123. pub async fn money_keygen(&self) -> WalletDbResult<()> {
  124. eprintln!("Generating a new keypair");
  125. // TODO: We might want to have hierarchical deterministic key derivation.
  126. let keypair = Keypair::random(&mut OsRng);
  127. let is_default = 0;
  128. let query = format!(
  129. "INSERT INTO {} ({}, {}, {}) VALUES (?1, ?2, ?3);",
  130. *MONEY_KEYS_TABLE,
  131. MONEY_KEYS_COL_IS_DEFAULT,
  132. MONEY_KEYS_COL_PUBLIC,
  133. MONEY_KEYS_COL_SECRET
  134. );
  135. self.wallet
  136. .exec_sql(
  137. &query,
  138. rusqlite::params![
  139. is_default,
  140. serialize(&keypair.public),
  141. serialize(&keypair.secret)
  142. ],
  143. )
  144. .await?;
  145. eprintln!("New address:");
  146. eprintln!("{}", keypair.public);
  147. Ok(())
  148. }
  149. /// Fetch default secret key from the wallet.
  150. pub async fn default_secret(&self) -> Result<SecretKey> {
  151. let row = match self
  152. .wallet
  153. .query_single(
  154. &MONEY_KEYS_TABLE,
  155. &[MONEY_KEYS_COL_SECRET],
  156. convert_named_params! {(MONEY_KEYS_COL_IS_DEFAULT, 1)},
  157. )
  158. .await
  159. {
  160. Ok(r) => r,
  161. Err(e) => {
  162. return Err(Error::RusqliteError(format!(
  163. "[default_secret] Default secret key retrieval failed: {e:?}"
  164. )))
  165. }
  166. };
  167. let Value::Blob(ref key_bytes) = row[0] else {
  168. return Err(Error::ParseFailed("[default_secret] Key bytes parsing failed"))
  169. };
  170. let secret_key: SecretKey = deserialize(key_bytes)?;
  171. Ok(secret_key)
  172. }
  173. /// Fetch default pubkey from the wallet.
  174. pub async fn default_address(&self) -> Result<PublicKey> {
  175. let row = match self
  176. .wallet
  177. .query_single(
  178. &MONEY_KEYS_TABLE,
  179. &[MONEY_KEYS_COL_PUBLIC],
  180. convert_named_params! {(MONEY_KEYS_COL_IS_DEFAULT, 1)},
  181. )
  182. .await
  183. {
  184. Ok(r) => r,
  185. Err(e) => {
  186. return Err(Error::RusqliteError(format!(
  187. "[default_address] Default address retrieval failed: {e:?}"
  188. )))
  189. }
  190. };
  191. let Value::Blob(ref key_bytes) = row[0] else {
  192. return Err(Error::ParseFailed("[default_address] Key bytes parsing failed"))
  193. };
  194. let public_key: PublicKey = deserialize(key_bytes)?;
  195. Ok(public_key)
  196. }
  197. /// Set provided index address as default in the wallet.
  198. pub async fn set_default_address(&self, idx: usize) -> WalletDbResult<()> {
  199. // First we update previous default record
  200. let is_default = 0;
  201. let query = format!("UPDATE {} SET {} = ?1", *MONEY_KEYS_TABLE, MONEY_KEYS_COL_IS_DEFAULT,);
  202. self.wallet.exec_sql(&query, rusqlite::params![is_default]).await?;
  203. // and then we set the new one
  204. let is_default = 1;
  205. let query = format!(
  206. "UPDATE {} SET {} = ?1 WHERE {} = ?2",
  207. *MONEY_KEYS_TABLE, MONEY_KEYS_COL_IS_DEFAULT, MONEY_KEYS_COL_KEY_ID,
  208. );
  209. self.wallet.exec_sql(&query, rusqlite::params![is_default, idx]).await
  210. }
  211. /// Fetch all pukeys from the wallet.
  212. pub async fn addresses(&self) -> Result<Vec<(u64, PublicKey, SecretKey, u64)>> {
  213. let rows = match self.wallet.query_multiple(&MONEY_KEYS_TABLE, &[], &[]).await {
  214. Ok(r) => r,
  215. Err(e) => {
  216. return Err(Error::RusqliteError(format!(
  217. "[addresses] Addresses retrieval failed: {e:?}"
  218. )))
  219. }
  220. };
  221. let mut vec = Vec::with_capacity(rows.len());
  222. for row in rows {
  223. let Value::Integer(key_id) = row[0] else {
  224. return Err(Error::ParseFailed("[addresses] Key ID parsing failed"))
  225. };
  226. let Ok(key_id) = u64::try_from(key_id) else {
  227. return Err(Error::ParseFailed("[addresses] Key ID parsing failed"))
  228. };
  229. let Value::Integer(is_default) = row[1] else {
  230. return Err(Error::ParseFailed("[addresses] Is default parsing failed"))
  231. };
  232. let Ok(is_default) = u64::try_from(is_default) else {
  233. return Err(Error::ParseFailed("[addresses] Is default parsing failed"))
  234. };
  235. let Value::Blob(ref key_bytes) = row[2] else {
  236. return Err(Error::ParseFailed("[addresses] Public key bytes parsing failed"))
  237. };
  238. let public_key: PublicKey = deserialize(key_bytes)?;
  239. let Value::Blob(ref key_bytes) = row[3] else {
  240. return Err(Error::ParseFailed("[addresses] Secret key bytes parsing failed"))
  241. };
  242. let secret_key: SecretKey = deserialize(key_bytes)?;
  243. vec.push((key_id, public_key, secret_key, is_default));
  244. }
  245. Ok(vec)
  246. }
  247. /// Fetch all secret keys from the wallet.
  248. pub async fn get_money_secrets(&self) -> Result<Vec<SecretKey>> {
  249. let rows = match self
  250. .wallet
  251. .query_multiple(&MONEY_KEYS_TABLE, &[MONEY_KEYS_COL_SECRET], &[])
  252. .await
  253. {
  254. Ok(r) => r,
  255. Err(e) => {
  256. return Err(Error::RusqliteError(format!(
  257. "[get_money_secrets] Secret keys retrieval failed: {e:?}"
  258. )))
  259. }
  260. };
  261. let mut secrets = Vec::with_capacity(rows.len());
  262. // Let's scan through the rows and see if we got anything.
  263. for row in rows {
  264. let Value::Blob(ref key_bytes) = row[0] else {
  265. return Err(Error::ParseFailed(
  266. "[get_money_secrets] Secret key bytes parsing failed",
  267. ))
  268. };
  269. let secret_key: SecretKey = deserialize(key_bytes)?;
  270. secrets.push(secret_key);
  271. }
  272. Ok(secrets)
  273. }
  274. /// Import given secret keys into the wallet.
  275. /// If the key already exists, it will be skipped.
  276. /// Returns the respective PublicKey objects for the imported keys.
  277. pub async fn import_money_secrets(&self, secrets: Vec<SecretKey>) -> Result<Vec<PublicKey>> {
  278. let existing_secrets = self.get_money_secrets().await?;
  279. let mut ret = Vec::with_capacity(secrets.len());
  280. for secret in secrets {
  281. // Check if secret already exists
  282. if existing_secrets.contains(&secret) {
  283. eprintln!("Existing key found: {secret}");
  284. continue
  285. }
  286. ret.push(PublicKey::from_secret(secret));
  287. let is_default = 0;
  288. let public = serialize(&PublicKey::from_secret(secret));
  289. let secret = serialize(&secret);
  290. let query = format!(
  291. "INSERT INTO {} ({}, {}, {}) VALUES (?1, ?2, ?3);",
  292. *MONEY_KEYS_TABLE,
  293. MONEY_KEYS_COL_IS_DEFAULT,
  294. MONEY_KEYS_COL_PUBLIC,
  295. MONEY_KEYS_COL_SECRET
  296. );
  297. if let Err(e) =
  298. self.wallet.exec_sql(&query, rusqlite::params![is_default, public, secret]).await
  299. {
  300. return Err(Error::RusqliteError(format!(
  301. "[import_money_secrets] Inserting new address failed: {e:?}"
  302. )))
  303. }
  304. }
  305. Ok(ret)
  306. }
  307. /// Fetch known unspent balances from the wallet and return them as a hashmap.
  308. pub async fn money_balance(&self) -> Result<HashMap<String, u64>> {
  309. let mut coins = self.get_coins(false).await?;
  310. coins.retain(|x| x.0.note.spend_hook == FuncId::none());
  311. // Fill this map with balances
  312. let mut balmap: HashMap<String, u64> = HashMap::new();
  313. for coin in coins {
  314. let mut value = coin.0.note.value;
  315. if let Some(prev) = balmap.get(&coin.0.note.token_id.to_string()) {
  316. value += prev;
  317. }
  318. balmap.insert(coin.0.note.token_id.to_string(), value);
  319. }
  320. Ok(balmap)
  321. }
  322. /// Fetch all coins and their metadata related to the Money contract from the wallet.
  323. /// Optionally also fetch spent ones.
  324. /// The boolean in the returned tuple notes if the coin was marked as spent.
  325. pub async fn get_coins(&self, fetch_spent: bool) -> Result<Vec<(OwnCoin, bool)>> {
  326. let query = if fetch_spent {
  327. self.wallet.query_multiple(&MONEY_COINS_TABLE, &[], &[]).await
  328. } else {
  329. self.wallet
  330. .query_multiple(
  331. &MONEY_COINS_TABLE,
  332. &[],
  333. convert_named_params! {(MONEY_COINS_COL_IS_SPENT, false)},
  334. )
  335. .await
  336. };
  337. let rows = match query {
  338. Ok(r) => r,
  339. Err(e) => {
  340. return Err(Error::RusqliteError(format!(
  341. "[get_coins] Coins retrieval failed: {e:?}"
  342. )))
  343. }
  344. };
  345. let mut owncoins = Vec::with_capacity(rows.len());
  346. for row in rows {
  347. let Value::Blob(ref coin_bytes) = row[0] else {
  348. return Err(Error::ParseFailed("[get_coins] Coin bytes parsing failed"))
  349. };
  350. let coin: Coin = deserialize(coin_bytes)?;
  351. let Value::Integer(is_spent) = row[1] else {
  352. return Err(Error::ParseFailed("[get_coins] Is spent parsing failed"))
  353. };
  354. let Ok(is_spent) = u64::try_from(is_spent) else {
  355. return Err(Error::ParseFailed("[get_coins] Is spent parsing failed"))
  356. };
  357. let is_spent = is_spent > 0;
  358. let Value::Blob(ref value_bytes) = row[2] else {
  359. return Err(Error::ParseFailed("[get_coins] Value bytes parsing failed"))
  360. };
  361. let value: u64 = deserialize(value_bytes)?;
  362. let Value::Blob(ref token_id_bytes) = row[3] else {
  363. return Err(Error::ParseFailed("[get_coins] Token ID bytes parsing failed"))
  364. };
  365. let token_id: TokenId = deserialize(token_id_bytes)?;
  366. let Value::Blob(ref spend_hook_bytes) = row[4] else {
  367. return Err(Error::ParseFailed("[get_coins] Spend hook bytes parsing failed"))
  368. };
  369. let spend_hook: pallas::Base = deserialize(spend_hook_bytes)?;
  370. let Value::Blob(ref user_data_bytes) = row[5] else {
  371. return Err(Error::ParseFailed("[get_coins] User data bytes parsing failed"))
  372. };
  373. let user_data: pallas::Base = deserialize(user_data_bytes)?;
  374. let Value::Blob(ref coin_blind_bytes) = row[6] else {
  375. return Err(Error::ParseFailed("[get_coins] Coin blind bytes parsing failed"))
  376. };
  377. let coin_blind: BaseBlind = deserialize(coin_blind_bytes)?;
  378. let Value::Blob(ref value_blind_bytes) = row[7] else {
  379. return Err(Error::ParseFailed("[get_coins] Value blind bytes parsing failed"))
  380. };
  381. let value_blind: ScalarBlind = deserialize(value_blind_bytes)?;
  382. let Value::Blob(ref token_blind_bytes) = row[8] else {
  383. return Err(Error::ParseFailed("[get_coins] Token blind bytes parsing failed"))
  384. };
  385. let token_blind: BaseBlind = deserialize(token_blind_bytes)?;
  386. let Value::Blob(ref secret_bytes) = row[9] else {
  387. return Err(Error::ParseFailed("[get_coins] Secret bytes parsing failed"))
  388. };
  389. let secret: SecretKey = deserialize(secret_bytes)?;
  390. // TODO: Remove from SQL store, can be derived ondemand
  391. let Value::Blob(ref nullifier_bytes) = row[10] else {
  392. return Err(Error::ParseFailed("[get_coins] Nullifier bytes parsing failed"))
  393. };
  394. let nullifier: Nullifier = deserialize(nullifier_bytes)?;
  395. let Value::Blob(ref leaf_position_bytes) = row[11] else {
  396. return Err(Error::ParseFailed("[get_coins] Leaf position bytes parsing failed"))
  397. };
  398. let leaf_position: bridgetree::Position = deserialize(leaf_position_bytes)?;
  399. let Value::Blob(ref memo) = row[12] else {
  400. return Err(Error::ParseFailed("[get_coins] Memo parsing failed"))
  401. };
  402. let note = MoneyNote {
  403. value,
  404. token_id,
  405. spend_hook: spend_hook.into(),
  406. user_data,
  407. coin_blind,
  408. value_blind,
  409. token_blind,
  410. memo: memo.clone(),
  411. };
  412. let owncoin = OwnCoin { coin, note, secret, leaf_position };
  413. owncoins.push((owncoin, is_spent))
  414. }
  415. Ok(owncoins)
  416. }
  417. /// Create an alias record for provided Token ID.
  418. pub async fn add_alias(&self, alias: String, token_id: TokenId) -> WalletDbResult<()> {
  419. eprintln!("Generating alias {alias} for Token: {token_id}");
  420. let query = format!(
  421. "INSERT OR REPLACE INTO {} ({}, {}) VALUES (?1, ?2);",
  422. *MONEY_ALIASES_TABLE, MONEY_ALIASES_COL_ALIAS, MONEY_ALIASES_COL_TOKEN_ID,
  423. );
  424. self.wallet
  425. .exec_sql(&query, rusqlite::params![serialize(&alias), serialize(&token_id)])
  426. .await
  427. }
  428. /// Fetch all aliases from the wallet.
  429. /// Optionally filter using alias name and/or token id.
  430. pub async fn get_aliases(
  431. &self,
  432. alias_filter: Option<String>,
  433. token_id_filter: Option<TokenId>,
  434. ) -> Result<HashMap<String, TokenId>> {
  435. let rows = match self.wallet.query_multiple(&MONEY_ALIASES_TABLE, &[], &[]).await {
  436. Ok(r) => r,
  437. Err(e) => {
  438. return Err(Error::RusqliteError(format!(
  439. "[get_aliases] Aliases retrieval failed: {e:?}"
  440. )))
  441. }
  442. };
  443. // Fill this map with aliases
  444. let mut map: HashMap<String, TokenId> = HashMap::new();
  445. for row in rows {
  446. let Value::Blob(ref alias_bytes) = row[0] else {
  447. return Err(Error::ParseFailed("[get_aliases] Alias bytes parsing failed"))
  448. };
  449. let alias: String = deserialize(alias_bytes)?;
  450. if alias_filter.is_some() && alias_filter.as_ref().unwrap() != &alias {
  451. continue
  452. }
  453. let Value::Blob(ref token_id_bytes) = row[1] else {
  454. return Err(Error::ParseFailed("[get_aliases] TokenId bytes parsing failed"))
  455. };
  456. let token_id: TokenId = deserialize(token_id_bytes)?;
  457. if token_id_filter.is_some() && token_id_filter.as_ref().unwrap() != &token_id {
  458. continue
  459. }
  460. map.insert(alias, token_id);
  461. }
  462. Ok(map)
  463. }
  464. /// Fetch all aliases from the wallet, mapped by token id.
  465. pub async fn get_aliases_mapped_by_token(&self) -> Result<HashMap<String, String>> {
  466. let aliases = self.get_aliases(None, None).await?;
  467. let mut map: HashMap<String, String> = HashMap::new();
  468. for (alias, token_id) in aliases {
  469. let aliases_string = if let Some(prev) = map.get(&token_id.to_string()) {
  470. format!("{}, {}", prev, alias)
  471. } else {
  472. alias
  473. };
  474. map.insert(token_id.to_string(), aliases_string);
  475. }
  476. Ok(map)
  477. }
  478. /// Remove provided alias record from the wallet database.
  479. pub async fn remove_alias(&self, alias: String) -> WalletDbResult<()> {
  480. eprintln!("Removing alias: {alias}");
  481. let query = format!(
  482. "DELETE FROM {} WHERE {} = ?1;",
  483. *MONEY_ALIASES_TABLE, MONEY_ALIASES_COL_ALIAS,
  484. );
  485. self.wallet.exec_sql(&query, rusqlite::params![serialize(&alias)]).await
  486. }
  487. /// Mark a given coin in the wallet as unspent.
  488. pub async fn unspend_coin(&self, coin: &Coin) -> WalletDbResult<()> {
  489. let is_spend = 0;
  490. let query = format!(
  491. "UPDATE {} SET {} = ?1 WHERE {} = ?2",
  492. *MONEY_COINS_TABLE, MONEY_COINS_COL_IS_SPENT, MONEY_COINS_COL_COIN,
  493. );
  494. self.wallet.exec_sql(&query, rusqlite::params![is_spend, serialize(&coin.inner())]).await
  495. }
  496. /// Replace the Money Merkle tree in the wallet.
  497. pub async fn put_money_tree(&self, tree: &MerkleTree) -> WalletDbResult<()> {
  498. // First we remove old record
  499. let query = format!("DELETE FROM {};", *MONEY_TREE_TABLE);
  500. self.wallet.exec_sql(&query, &[]).await?;
  501. // then we insert the new one
  502. let query =
  503. format!("INSERT INTO {} ({}) VALUES (?1);", *MONEY_TREE_TABLE, MONEY_TREE_COL_TREE,);
  504. self.wallet.exec_sql(&query, rusqlite::params![serialize(tree)]).await
  505. }
  506. /// Fetch the Money Merkle tree from the wallet.
  507. pub async fn get_money_tree(&self) -> Result<MerkleTree> {
  508. let row =
  509. match self.wallet.query_single(&MONEY_TREE_TABLE, &[MONEY_TREE_COL_TREE], &[]).await {
  510. Ok(r) => r,
  511. Err(e) => {
  512. return Err(Error::RusqliteError(format!(
  513. "[get_money_tree] Tree retrieval failed: {e:?}"
  514. )))
  515. }
  516. };
  517. let Value::Blob(ref tree_bytes) = row[0] else {
  518. return Err(Error::ParseFailed("[get_money_tree] Tree bytes parsing failed"))
  519. };
  520. let tree = deserialize(tree_bytes)?;
  521. Ok(tree)
  522. }
  523. /// Get the last scanned block height from the wallet.
  524. pub async fn last_scanned_block(&self) -> WalletDbResult<u64> {
  525. let ret = self
  526. .wallet
  527. .query_single(&MONEY_INFO_TABLE, &[MONEY_INFO_COL_LAST_SCANNED_BLOCK], &[])
  528. .await?;
  529. let Value::Integer(height) = ret[0] else {
  530. return Err(WalletDbError::ParseColumnValueError);
  531. };
  532. let Ok(height) = u64::try_from(height) else {
  533. return Err(WalletDbError::ParseColumnValueError);
  534. };
  535. Ok(height)
  536. }
  537. /// Append data related to Money contract transactions into the wallet database.
  538. pub async fn apply_tx_money_data(&self, tx: &Transaction, _confirm: bool) -> Result<()> {
  539. let cid = *MONEY_CONTRACT_ID;
  540. let mut nullifiers: Vec<Nullifier> = vec![];
  541. let mut coins: Vec<Coin> = vec![];
  542. let mut notes: Vec<AeadEncryptedNote> = vec![];
  543. let mut freezes: Vec<TokenId> = vec![];
  544. for (i, call) in tx.calls.iter().enumerate() {
  545. if call.data.contract_id == cid && call.data.data[0] == MoneyFunction::TransferV1 as u8
  546. {
  547. eprintln!("Found Money::TransferV1 in call {i}");
  548. let params: MoneyTransferParamsV1 = deserialize(&call.data.data[1..])?;
  549. for input in params.inputs {
  550. nullifiers.push(input.nullifier);
  551. }
  552. for output in params.outputs {
  553. coins.push(output.coin);
  554. notes.push(output.note);
  555. }
  556. continue
  557. }
  558. if call.data.contract_id == cid && call.data.data[0] == MoneyFunction::OtcSwapV1 as u8 {
  559. eprintln!("Found Money::OtcSwapV1 in call {i}");
  560. let params: MoneyTransferParamsV1 = deserialize(&call.data.data[1..])?;
  561. for input in params.inputs {
  562. nullifiers.push(input.nullifier);
  563. }
  564. for output in params.outputs {
  565. coins.push(output.coin);
  566. notes.push(output.note);
  567. }
  568. continue
  569. }
  570. if call.data.contract_id == cid && call.data.data[0] == MoneyFunction::TokenMintV1 as u8
  571. {
  572. eprintln!("Found Money::MintV1 in call {i}");
  573. let params: MoneyTokenMintParamsV1 = deserialize(&call.data.data[1..])?;
  574. coins.push(params.coin);
  575. //notes.push(output.note);
  576. continue
  577. }
  578. if call.data.contract_id == cid &&
  579. call.data.data[0] == MoneyFunction::TokenFreezeV1 as u8
  580. {
  581. eprintln!("Found Money::FreezeV1 in call {i}");
  582. let params: MoneyTokenFreezeParamsV1 = deserialize(&call.data.data[1..])?;
  583. let token_id = TokenId::derive_public(params.mint_public);
  584. freezes.push(token_id);
  585. }
  586. }
  587. let secrets = self.get_money_secrets().await?;
  588. let dao_secrets = self.get_dao_secrets().await?;
  589. let mut tree = self.get_money_tree().await?;
  590. let mut owncoins = vec![];
  591. for (coin, note) in coins.iter().zip(notes.iter()) {
  592. // Append the new coin to the Merkle tree. Every coin has to be added.
  593. tree.append(MerkleNode::from(coin.inner()));
  594. // Attempt to decrypt the note
  595. for secret in secrets.iter().chain(dao_secrets.iter()) {
  596. if let Ok(note) = note.decrypt::<MoneyNote>(secret) {
  597. eprintln!("Successfully decrypted a Money Note");
  598. eprintln!("Witnessing coin in Merkle tree");
  599. let leaf_position = tree.mark().unwrap();
  600. let owncoin =
  601. OwnCoin { coin: *coin, note: note.clone(), secret: *secret, leaf_position };
  602. owncoins.push(owncoin);
  603. }
  604. }
  605. }
  606. if let Err(e) = self.put_money_tree(&tree).await {
  607. return Err(Error::RusqliteError(format!(
  608. "[apply_tx_money_data] Put Money tree failed: {e:?}"
  609. )))
  610. }
  611. if !nullifiers.is_empty() {
  612. self.mark_spent_coins(&nullifiers).await?;
  613. }
  614. // This is the SQL query we'll be executing to insert new coins
  615. // into the wallet
  616. let query = format!(
  617. "INSERT INTO {} ({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13);",
  618. *MONEY_COINS_TABLE,
  619. MONEY_COINS_COL_COIN,
  620. MONEY_COINS_COL_IS_SPENT,
  621. MONEY_COINS_COL_SERIAL,
  622. MONEY_COINS_COL_VALUE,
  623. MONEY_COINS_COL_TOKEN_ID,
  624. MONEY_COINS_COL_SPEND_HOOK,
  625. MONEY_COINS_COL_USER_DATA,
  626. MONEY_COINS_COL_VALUE_BLIND,
  627. MONEY_COINS_COL_TOKEN_BLIND,
  628. MONEY_COINS_COL_SECRET,
  629. MONEY_COINS_COL_NULLIFIER,
  630. MONEY_COINS_COL_LEAF_POSITION,
  631. MONEY_COINS_COL_MEMO,
  632. );
  633. eprintln!("Found {} OwnCoin(s) in transaction", owncoins.len());
  634. for owncoin in &owncoins {
  635. eprintln!("OwnCoin: {:?}", owncoin.coin);
  636. let params = rusqlite::params![
  637. serialize(&owncoin.coin),
  638. 0, // <-- is_spent
  639. serialize(&owncoin.note.coin_blind),
  640. serialize(&owncoin.note.value),
  641. serialize(&owncoin.note.token_id),
  642. serialize(&owncoin.note.spend_hook),
  643. serialize(&owncoin.note.user_data),
  644. serialize(&owncoin.note.value_blind),
  645. serialize(&owncoin.note.token_blind),
  646. serialize(&owncoin.secret),
  647. serialize(&owncoin.nullifier()),
  648. serialize(&owncoin.leaf_position),
  649. serialize(&owncoin.note.memo),
  650. ];
  651. if let Err(e) = self.wallet.exec_sql(&query, params).await {
  652. return Err(Error::RusqliteError(format!(
  653. "[apply_tx_money_data] Inserting Money coin failed: {e:?}"
  654. )))
  655. }
  656. }
  657. for token_id in freezes {
  658. let query = format!(
  659. "UPDATE {} SET {} = 1 WHERE {} = ?1;",
  660. *MONEY_TOKENS_TABLE, MONEY_TOKENS_COL_IS_FROZEN, MONEY_TOKENS_COL_TOKEN_ID,
  661. );
  662. if let Err(e) =
  663. self.wallet.exec_sql(&query, rusqlite::params![serialize(&token_id)]).await
  664. {
  665. return Err(Error::RusqliteError(format!(
  666. "[apply_tx_money_data] Inserting Money coin failed: {e:?}"
  667. )))
  668. }
  669. }
  670. if !owncoins.is_empty() {
  671. kaching().await;
  672. }
  673. Ok(())
  674. }
  675. /// Mark a coin in the wallet as spent
  676. pub async fn mark_spent_coin(&self, coin: &Coin) -> WalletDbResult<()> {
  677. let query = format!(
  678. "UPDATE {} SET {} = ?1 WHERE {} = ?2;",
  679. *MONEY_COINS_TABLE, MONEY_COINS_COL_IS_SPENT, MONEY_COINS_COL_COIN
  680. );
  681. let is_spent = 1;
  682. self.wallet.exec_sql(&query, rusqlite::params![is_spent, serialize(&coin.inner())]).await
  683. }
  684. /// Marks all coins in the wallet as spent, if their nullifier is in the given set
  685. pub async fn mark_spent_coins(&self, nullifiers: &[Nullifier]) -> Result<()> {
  686. if nullifiers.is_empty() {
  687. return Ok(())
  688. }
  689. for (coin, _) in self.get_coins(false).await? {
  690. if nullifiers.contains(&coin.nullifier()) {
  691. if let Err(e) = self.mark_spent_coin(&coin.coin).await {
  692. return Err(Error::RusqliteError(format!(
  693. "[mark_spent_coins] Marking spent coin failed: {e:?}"
  694. )))
  695. }
  696. }
  697. }
  698. Ok(())
  699. }
  700. /// Reset the Money Merkle tree in the wallet
  701. pub async fn reset_money_tree(&self) -> WalletDbResult<()> {
  702. eprintln!("Resetting Money Merkle tree");
  703. let mut tree = MerkleTree::new(100);
  704. tree.append(MerkleNode::from(pallas::Base::ZERO));
  705. let _ = tree.mark().unwrap();
  706. self.put_money_tree(&tree).await?;
  707. eprintln!("Successfully reset Money Merkle tree");
  708. Ok(())
  709. }
  710. /// Reset the Money coins in the wallet
  711. pub async fn reset_money_coins(&self) -> WalletDbResult<()> {
  712. eprintln!("Resetting coins");
  713. let query = format!("DELETE FROM {};", *MONEY_COINS_TABLE);
  714. self.wallet.exec_sql(&query, &[]).await?;
  715. eprintln!("Successfully reset coins");
  716. Ok(())
  717. }
  718. /// Retrieve token by provided string.
  719. /// Input string represents either an alias or a token id.
  720. pub async fn get_token(&self, input: String) -> Result<TokenId> {
  721. // Check if input is an alias(max 5 characters)
  722. if input.chars().count() <= 5 {
  723. let aliases = self.get_aliases(Some(input.clone()), None).await?;
  724. if let Some(token_id) = aliases.get(&input) {
  725. return Ok(*token_id)
  726. }
  727. }
  728. // Else parse input
  729. Ok(TokenId::from_str(input.as_str())?)
  730. }
  731. }