diff --git a/.gitignore b/.gitignore index b3621c0..d8c3f88 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /target/ **/*.rs.bk *.pdb +.cargo/config.toml # IDE .vscode/ diff --git a/Cargo.lock b/Cargo.lock index 29c7110..3de64d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,9 +63,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arraydeque" @@ -435,9 +435,9 @@ dependencies = [ [[package]] name = "chia-sdk-client" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f44eebc9bb4a596f0c770822facc117416a02db9c78d10b451956597011a3e" +checksum = "09a9ab7609f5c98ff34fc5ba33ad50bfdecca771165640eb88e8054ccef18916" dependencies = [ "chia-protocol", "chia-sdk-types", @@ -454,9 +454,9 @@ dependencies = [ [[package]] name = "chia-sdk-coinset" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cac592b1eece9eb9e46db9027d58f4c3ec9b549c5419e249998c53ed7795bd" +checksum = "bb55e723e4b847fdbb9e729fef1a0f21c624b618bda8a17c9c205ff9db64a1e1" dependencies = [ "chia-protocol", "hex", @@ -468,9 +468,9 @@ dependencies = [ [[package]] name = "chia-sdk-derive" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7ac9360740b8af343eadcb60f3155d6f9f56bef2f56d79b71e3e6be2a5d529" +checksum = "add9e60902df26dfe987d87f1b19ab7e359c6269fa4f222a9d79c02a9dba969d" dependencies = [ "convert_case", "quote", @@ -479,9 +479,9 @@ dependencies = [ [[package]] name = "chia-sdk-driver" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca91b1e0ec55edbe736cf9f7a33b492ca05c635ccb022fe9511be83b6ba3e235" +checksum = "260c97751f8986e7f82091e3bee504044efb79857f26bfcd2b5d37cba674f79e" dependencies = [ "bigdecimal", "bip39", @@ -511,9 +511,9 @@ dependencies = [ [[package]] name = "chia-sdk-signer" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd70865cfd9881f5282d4a9c5e42905f96f88b2ec35efda8cf23c944e258d20" +checksum = "d71037389cc3bdebc47c9c6cfebc898244393e4e7246b486d64922a9c23bbac6" dependencies = [ "chia-bls 0.26.0", "chia-consensus", @@ -529,9 +529,9 @@ dependencies = [ [[package]] name = "chia-sdk-test" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c459f50deea22e03ab715868d9ed0c11922d7325a0dd8d328d07b3ad5df63e5c" +checksum = "365b95611176b670cd61455ce6578cccf740a66b7d27cd3b31395c12f4073bc2" dependencies = [ "anyhow", "bip39", @@ -567,9 +567,9 @@ dependencies = [ [[package]] name = "chia-sdk-types" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b14123f03a5ccb66c245b216481436749d11c8f394c0fe7a2bf1e35f2a582f6f" +checksum = "298b92f005cd884861678808813cb49dca3545231b6b442d691e01535ed86825" dependencies = [ "chia-bls 0.26.0", "chia-consensus", @@ -589,9 +589,9 @@ dependencies = [ [[package]] name = "chia-sdk-utils" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca897c36475cbc6832271cacdc4c5d13f5963ef61f99cebec246fd91e981306f" +checksum = "738bc2a53dcece78184aca4de617df666e984af0c86560131213039889d927fc" dependencies = [ "bech32", "chia-protocol", @@ -678,9 +678,9 @@ dependencies = [ [[package]] name = "chia-wallet-sdk" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae886c1c212efcbd43564e8039920d3bd94a8db35e8fbd649e6b01ebe8c167e" +checksum = "94547c50b141ad9ae84f9bcc26c0bf467b7570f0354c906fb203eeea69886a4c" dependencies = [ "chia-bls 0.26.0", "chia-protocol", @@ -921,9 +921,9 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "datalayer-driver" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0e7ee25be16a809900191178eb535f16d4543a9a7c504f94516ae10d20909f0" +checksum = "7abd50de97bd63bae84bc92766f3c5570689fba4e6c45b0e4855471351f8749c" dependencies = [ "chia", "chia-puzzles", @@ -933,6 +933,7 @@ dependencies = [ "futures-util", "hex", "hex-literal", + "indexmap", "num-bigint", "openssl", "openssl-sys", @@ -1605,9 +1606,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", @@ -2520,18 +2521,28 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -2540,14 +2551,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 733f2a8..62122ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" rust-version = "1.70" [dependencies] -datalayer-driver = "1.0.1" -chia-wallet-sdk = "0.29.0" +datalayer-driver = "2.0.0" +chia-wallet-sdk = "0.30.0" chia = "0.26.0" bip39 = "2.0" thiserror = "1.0" diff --git a/src/wallet.rs b/src/wallet.rs index 2d35b51..a444682 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -7,29 +7,21 @@ use base64::{engine::general_purpose, Engine as _}; use bip39::{Language, Mnemonic}; use chia::protocol::CoinState; use chia::puzzles::cat::CatArgs; -use chia_wallet_sdk::driver::{Cat, Puzzle}; -use chia_wallet_sdk::prelude::{Allocator, ToClvm, TreeHash}; -use chia_wallet_sdk::types::MAINNET_CONSTANTS; +use chia_wallet_sdk::driver::Cat; +use chia_wallet_sdk::prelude::TreeHash; +use datalayer_driver::wallet::DIG_ASSET_ID; use datalayer_driver::{ address_to_puzzle_hash, connect_random, get_coin_id, master_public_key_to_first_puzzle_hash, master_public_key_to_wallet_synthetic_key, master_secret_key_to_wallet_synthetic_secret_key, puzzle_hash_to_address, secret_key_to_public_key, sign_message, verify_signature, Bytes, Bytes32, Coin, CoinSpend, NetworkType, Peer, PublicKey, SecretKey, Signature, }; -use hex_literal::hex; -use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::env; use std::fs; use std::path::PathBuf; -pub static DIG_MIN_HEIGHT: u32 = 5777842; -pub static DIG_COIN_ASSET_ID: Lazy = Lazy::new(|| { - Bytes32::new(hex!( - "a406d3a9de984d03c9591c10d917593b434d5263cabe2b42f6b367df16832f81" - )) -}); const KEYRING_FILE: &str = "keyring.json"; // Cache duration constant - keeping for potential future use #[allow(dead_code)] @@ -48,6 +40,7 @@ struct KeyringData { wallets: HashMap, } +#[derive(Debug, Clone)] pub struct Wallet { mnemonic: Option, wallet_name: String, @@ -276,15 +269,14 @@ impl Wallet { } /// Get all unspent DIG Token coins - // todo: this should be moved to the driver - pub async fn get_all_unspent_dig_coins( + pub async fn get_all_unspent_dig_cats( &self, peer: &Peer, omit_coins: Vec, verbose: bool, - ) -> Result, WalletError> { - let p2 = self.get_owner_puzzle_hash().await?; - let dig_cat_ph = CatArgs::curry_tree_hash(*DIG_COIN_ASSET_ID, TreeHash::from(p2)); + ) -> Result, WalletError> { + let owner_puzzle_hash = self.get_owner_puzzle_hash().await?; + let dig_cat_ph = CatArgs::curry_tree_hash(DIG_ASSET_ID, TreeHash::from(owner_puzzle_hash)); let dig_cat_ph_bytes = Bytes32::from(dig_cat_ph.to_bytes()); // Get unspent coin states from the DataLayer-Driver async API @@ -299,16 +291,13 @@ impl Wallet { // Convert coin states to coins and filter out omitted coins let omit_coin_ids: Vec = omit_coins.iter().map(get_coin_id).collect(); - let available_coin_states: Vec = unspent_coin_states .coin_states .into_iter() .filter(|coin_state| !omit_coin_ids.contains(&get_coin_id(&coin_state.coin))) .collect(); - let mut proved_dig_token_coins: Vec = vec![]; - - let mut allocator = Allocator::new(); + let mut proved_dig_cats: Vec = vec![]; for coin_state in &available_coin_states { let coin = &coin_state.coin; @@ -329,136 +318,14 @@ impl Wallet { } }; - // 1) Request parent coin state - let parent_state_result = peer - .request_coin_state( - vec![coin.parent_coin_info], - None, - MAINNET_CONSTANTS.genesis_challenge, - false, - ) - .await; - - let parent_state_response = match parent_state_result { - Ok(response) => response, - Err(error) => { - if verbose { - eprintln!( - "ERROR: coin_id {} | {}", - coin_id, - WalletError::NetworkError(format!( - "Failed to get coin state: {}", - error - )) - ); - } - continue; - } - }; - - let parent_state = match parent_state_response { - Ok(state) => state, - Err(_) => { - if verbose { - eprintln!( - "ERROR: coin_id {} | {}", - coin_id, - WalletError::CoinSetError("Coin state rejected".to_string()) - ); - } - continue; - } - }; - - // 2) Request parent puzzle and solution - let parent_puzzle_and_solution_result = peer - .request_puzzle_and_solution(parent_state.coin_ids[0], coin_created_height) - .await; - - let parent_puzzle_and_solution_response = match parent_puzzle_and_solution_result { - Ok(response) => response, - Err(error) => { - if verbose { - eprintln!( - "ERROR: coin_id {} | {}", - coin_id, - WalletError::NetworkError(format!( - "Failed to get puzzle and solution: {}", - error - )) - ); - } - continue; - } - }; - - let parent_puzzle_and_solution = match parent_puzzle_and_solution_response { - Ok(v) => v, - Err(_) => { - if verbose { - eprintln!( - "ERROR: coin_id {} | {}", - coin_id, - WalletError::CoinSetError( - "Parent puzzle solution rejected".to_string() - ) - ); - } - continue; - } - }; - - // 3) Convert puzzle to CLVM - let parent_puzzle_ptr = match parent_puzzle_and_solution.puzzle.to_clvm(&mut allocator) - { - Ok(ptr) => ptr, - Err(error) => { - if verbose { - eprintln!( - "ERROR: coin_id {} | {}", - coin_id, - WalletError::CoinSetError(format!( - "Failed to parse puzzle and solution: {}", - error - )) - ); - } - continue; - } - }; - - let parent_puzzle = Puzzle::parse(&allocator, parent_puzzle_ptr); - - // 4) Convert solution to CLVM - let parent_solution = match parent_puzzle_and_solution.solution.to_clvm(&mut allocator) - { - Ok(solution) => solution, - Err(error) => { - if verbose { - eprintln!( - "ERROR: coin_id {} | {}", - coin_id, - WalletError::CoinSetError(format!( - "Failed to parse puzzle and solution: {}", - error - )) - ); - } - continue; - } - }; - - // 5) Parse CAT to prove lineage - let cat_parse_result = Cat::parse_children( - &mut allocator, - parent_state.coin_states[0].coin, - parent_puzzle, - parent_solution, - ); + //Parse CAT to prove lineage + let cat_parse_result = + datalayer_driver::async_api::prove_dig_cat_coin(peer, coin, coin_created_height) + .await; match cat_parse_result { - Ok(_) => { + Ok(parsed_cat) => { // lineage proved. append coin in question - proved_dig_token_coins.push(*coin); + proved_dig_cats.push(parsed_cat); } Err(error) => { if verbose { @@ -476,38 +343,45 @@ impl Wallet { } } - Ok(proved_dig_token_coins) + Ok(proved_dig_cats) } - pub async fn select_unspent_dig_token_coins( + pub async fn select_unspent_dig_cats( &self, peer: &Peer, coin_amount: u64, - fee: u64, omit_coins: Vec, verbose: bool, - ) -> Result, WalletError> { - let total_needed = coin_amount + fee; - let available_dig_coins = self - .get_all_unspent_dig_coins(peer, omit_coins, verbose) + ) -> Result, WalletError> { + let available_dig_cats = self + .get_all_unspent_dig_cats(peer, omit_coins, verbose) .await?; + let dig_coins = available_dig_cats + .iter() + .map(|cat| cat.coin) + .collect::>(); + // Use the DataLayer-Driver's select_coins function - let selected_coins = datalayer_driver::select_coins(&available_dig_coins, total_needed) + let selected_coins = datalayer_driver::select_coins(&dig_coins, coin_amount) .map_err(|e| WalletError::DataLayerError(format!("Coin selection failed: {}", e)))?; if selected_coins.is_empty() { return Err(WalletError::NoUnspentCoins); } - Ok(selected_coins) + let selected_coins_ids: HashSet = selected_coins.iter().map(get_coin_id).collect(); + let selected_cats = available_dig_cats + .into_iter() + .filter(|cat| selected_coins_ids.contains(&cat.coin.coin_id())) + .collect::>(); + + Ok(selected_cats) } pub async fn get_dig_balance(&self, peer: &Peer, verbose: bool) -> Result { - let dig_coins = self - .get_all_unspent_dig_coins(peer, vec![], verbose) - .await?; - let dig_balance = dig_coins.iter().map(|c| c.amount).sum::(); + let dig_cats = self.get_all_unspent_dig_cats(peer, vec![], verbose).await?; + let dig_balance = dig_cats.iter().map(|c| c.coin.amount).sum::(); Ok(dig_balance) }