Skip to content

Commit

Permalink
Partial example
Browse files Browse the repository at this point in the history
  • Loading branch information
Rigidity committed Mar 16, 2024
1 parent 7c8d034 commit 5b41dd3
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 14 deletions.
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/target
test.sqlite
test.sqlite-wal
test.sqlite-shm
*.sqlite
*.sqlite-wal
*.sqlite-shm
*.crt
*.key
35 changes: 31 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ authors = ["Brandon Haggstrom <me@rigidnetwork.com>"]
homepage = "https://github.com/Rigidity/chia-wallet-sdk"
repository = "https://github.com/Rigidity/chia-wallet-sdk"

[workspace]
resolver = "2"
members = ["examples/*"]

[dependencies]
tokio = { version = "1.33.0", features = ["macros"] }
tokio-tungstenite = { version = "0.21.0", features = ["native-tls"] }
Expand Down
15 changes: 15 additions & 0 deletions examples/wallet/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "wallet"
version = "0.1.0"
edition = "2021"

[dependencies]
bip39 = "2.0.0"
chia-bls = "0.5.1"
chia-client = "0.5.1"
chia-protocol = "0.5.1"
chia-wallet = "0.5.1"
chia-wallet-sdk = { path = "../.." }
sqlx = { version = "0.7.4", features = ["runtime-tokio", "sqlite"] }
thiserror = "1.0.58"
tokio = { version = "1.36.0", features = ["full"] }
149 changes: 149 additions & 0 deletions examples/wallet/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
use std::{collections::HashSet, str::FromStr, sync::Arc};

use bip39::Mnemonic;
use chia_bls::{
derive_keys::{
master_to_wallet_hardened_intermediate, master_to_wallet_unhardened_intermediate,
},
SecretKey,
};
use chia_client::Peer;
use chia_protocol::{Bytes32, CoinState, NodeType};
use chia_wallet::standard::DEFAULT_HIDDEN_PUZZLE_HASH;
use chia_wallet_sdk::{
connect_peer, create_tls_connector, load_ssl_cert, migrate, CoinStore, HardenedKeyStore,
PuzzleStore, UnhardenedKeyStore,
};
use sqlx::SqlitePool;
use thiserror::Error;

struct Wallet {
peer: Arc<Peer>,
hardened_keys: HardenedKeyStore,
unhardened_keys: UnhardenedKeyStore,
standard_coins: CoinStore,
}

#[derive(Debug, Error)]
enum WalletError {
#[error("peer error: {0}")]
Peer(#[from] chia_client::Error<()>),
}

impl Wallet {
async fn initial_sync(&self) -> Result<(), WalletError> {
let mut hardened_phs = HashSet::new();
let mut unhardened_phs = HashSet::new();
let mut puzzle_hashes = Vec::new();

for puzzle_hash in self.hardened_keys.puzzle_hashes().await {
hardened_phs.insert(Bytes32::new(puzzle_hash));
puzzle_hashes.push(Bytes32::new(puzzle_hash));
}

for puzzle_hash in self.unhardened_keys.puzzle_hashes().await {
unhardened_phs.insert(Bytes32::new(puzzle_hash));
puzzle_hashes.push(Bytes32::new(puzzle_hash));
}

for puzzle_hashes in puzzle_hashes.chunks(10000) {
let coin_states = self
.peer
.register_for_ph_updates(puzzle_hashes.to_vec(), 0)
.await?;

self.apply_updates(coin_states).await?;
}

Ok(())
}

async fn apply_updates(&self, coin_states: Vec<CoinState>) -> Result<(), WalletError> {
let mut p2_puzzle_hashes: HashSet<Bytes32> = self
.hardened_keys
.puzzle_hashes()
.await
.into_iter()
.map(Bytes32::new)
.collect();

p2_puzzle_hashes.extend(
self.unhardened_keys
.puzzle_hashes()
.await
.into_iter()
.map(Bytes32::new),
);

let mut standard_coins = Vec::new();

for coin_state in coin_states {
if p2_puzzle_hashes.contains(&coin_state.coin.puzzle_hash) {
standard_coins.push(coin_state);
} else {
println!(
"Found hinted coin state for unknown puzzle hash {:?}, with id {:?}",
coin_state.coin.puzzle_hash,
coin_state.coin.coin_id()
);
}
}

self.standard_coins.apply_updates(standard_coins).await;

Ok(())
}
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cert = load_ssl_cert("wallet.key", "wallet.crt");
let tls_connector = create_tls_connector(&cert);
let peer = connect_peer("localhost:56342", tls_connector).await?;

peer.send_handshake("simulator0".to_string(), NodeType::Wallet)
.await?;

let pool = SqlitePool::connect("sqlite://wallet.sqlite?mode=rwc").await?;
migrate(&pool).await?;

let mnemonic = Mnemonic::from_str(
"
destroy name laptop bleak august silent supreme tide
cry velvet tooth edge result human common grab
brush play walnut heavy harvest upper fat just
",
)?;
let seed = mnemonic.to_seed("");
let sk = SecretKey::from_seed(&seed);

let root_sk = master_to_wallet_hardened_intermediate(&sk);
let hardened_keys = HardenedKeyStore::new(pool.clone(), root_sk, DEFAULT_HIDDEN_PUZZLE_HASH);

let root_pk = master_to_wallet_unhardened_intermediate(&sk.public_key());
let unhardened_keys =
UnhardenedKeyStore::new(pool.clone(), root_pk, DEFAULT_HIDDEN_PUZZLE_HASH);

let standard_coins = CoinStore::new(pool.clone());

let wallet = Wallet {
peer,
hardened_keys,
unhardened_keys,
standard_coins,
};

wallet.initial_sync().await?;

println!(
"Synced {} balance",
wallet
.standard_coins
.unspent_coins()
.await
.iter()
.fold(0u128, |acc, coin| acc + coin.amount as u128)
);

Ok(())
}
7 changes: 0 additions & 7 deletions migrations/20240314021456_init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ CREATE TABLE `unhardened_keys` (
`p2_puzzle_hash` BLOB NOT NULL
);

CREATE TABLE `hardened_cats` (
`puzzle_hash` BLOB NOT NULL PRIMARY KEY,
`asset_id` BLOB NOT NULL,
`public_key` BLOB NOT NULL,
`puzzle_hash` BLOB NOT NULL
);

CREATE TABLE `coin_states` (
`coin_id` BLOB NOT NULL PRIMARY KEY,
`parent_coin_info` BLOB NOT NULL,
Expand Down
6 changes: 6 additions & 0 deletions src/sqlite.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
use sqlx::{migrate::MigrateError, SqlitePool};

mod coin_store;
mod hardened_key_store;
mod unhardened_key_store;

pub use coin_store::*;
pub use hardened_key_store::*;
pub use unhardened_key_store::*;

pub async fn migrate(pool: &SqlitePool) -> Result<(), MigrateError> {
sqlx::migrate!("./migrations").run(pool).await
}
Empty file removed src/sqlite/hardened_cat_store.rs
Empty file.
Empty file removed src/sqlite/unhardened_cat_store.rs
Empty file.

0 comments on commit 5b41dd3

Please sign in to comment.