forked from ordinals/ord
-
Notifications
You must be signed in to change notification settings - Fork 35
/
purse.rs
123 lines (103 loc) Β· 3.02 KB
/
purse.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use super::*;
#[derive(Debug)]
pub(crate) struct Purse {
pub(crate) wallet: bdk::wallet::Wallet<SqliteDatabase>,
pub(crate) blockchain: RpcBlockchain,
}
impl Purse {
pub(crate) fn init(options: &Options) -> Result {
let path = data_dir()
.ok_or_else(|| anyhow!("Failed to retrieve data dir"))?
.join("ord");
if path.exists() {
return Err(anyhow!("Wallet already exists."));
}
fs::create_dir_all(&path)?;
let seed = Mnemonic::generate_in_with(&mut rand::thread_rng(), Language::English, 12)?;
fs::write(path.join("entropy"), seed.to_entropy())?;
let wallet = bdk::wallet::Wallet::new(
Bip84((seed.clone(), None), KeychainKind::External),
None,
options.network,
SqliteDatabase::new(
path
.join("wallet.sqlite")
.to_str()
.ok_or_else(|| anyhow!("Failed to convert path to str"))?
.to_string(),
),
)?;
wallet.sync(
&RpcBlockchain::from_config(&RpcConfig {
url: options.rpc_url(),
auth: Auth::Cookie {
file: options.cookie_file()?,
},
network: options.network,
wallet_name: wallet_name_from_descriptor(
Bip84((seed, None), KeychainKind::External),
None,
options.network,
&Secp256k1::new(),
)?,
skip_blocks: None,
})?,
SyncOptions::default(),
)?;
eprintln!("Wallet initialized.");
Ok(())
}
pub(crate) fn load(options: &Options) -> Result<Self> {
let path = data_dir()
.ok_or_else(|| anyhow!("Failed to retrieve data dir"))?
.join("ord");
if !path.exists() {
return Err(anyhow!("Wallet doesn't exist."));
}
let key = (
Mnemonic::from_entropy(&fs::read(path.join("entropy"))?)?,
None,
);
let wallet = bdk::wallet::Wallet::new(
Bip84(key.clone(), KeychainKind::External),
None,
options.network,
SqliteDatabase::new(
path
.join("wallet.sqlite")
.to_str()
.ok_or_else(|| anyhow!("Failed to convert path to str"))?
.to_string(),
),
)?;
let blockchain = RpcBlockchain::from_config(&RpcConfig {
url: options.rpc_url(),
auth: Auth::Cookie {
file: options.cookie_file()?,
},
network: options.network,
wallet_name: wallet_name_from_descriptor(
Bip84(key, KeychainKind::External),
None,
options.network,
&Secp256k1::new(),
)?,
skip_blocks: None,
})?;
wallet.sync(&blockchain, SyncOptions::default())?;
Ok(Self { wallet, blockchain })
}
pub(crate) fn find(&self, options: &Options, ordinal: Ordinal) -> Result<LocalUtxo> {
let index = Index::index(options)?;
for utxo in self.wallet.list_unspent()? {
if let Some(ranges) = index.list(utxo.outpoint)? {
for (start, end) in ranges {
if ordinal.0 >= start && ordinal.0 < end {
return Ok(utxo);
}
}
}
}
bail!("No utxo contains {}Λ.", ordinal);
}
}