Skip to content

Commit e8084ba

Browse files
authored
Add command to export BIP-329 labels for wallet outputs (ordinals#3120)
Add `ord wallet label`, which exports BIP-320 wallet output labels. Especially useful for labeling outputs in Sparrow wallets.
1 parent 0c63a3b commit e8084ba

File tree

8 files changed

+276
-177
lines changed

8 files changed

+276
-177
lines changed

crates/mockcore/src/server.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ impl Api for Server {
296296
keypool_size: 0,
297297
keypool_size_hd_internal: 0,
298298
pay_tx_fee: Amount::from_sat(0),
299-
private_keys_enabled: false,
299+
private_keys_enabled: true,
300300
scanning: None,
301301
tx_count: 0,
302302
unconfirmed_balance: Amount::from_sat(0),

src/subcommand/wallet.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub mod create;
1212
pub mod dump;
1313
pub mod inscribe;
1414
pub mod inscriptions;
15+
mod label;
1516
pub mod mint;
1617
pub mod outputs;
1718
pub mod receive;
@@ -44,6 +45,8 @@ pub(crate) enum Subcommand {
4445
Balance,
4546
#[command(about = "Create inscriptions and runes")]
4647
Batch(batch_command::Batch),
48+
#[command(about = "List unspent cardinal outputs in wallet")]
49+
Cardinals,
4750
#[command(about = "Create new wallet")]
4851
Create(create::Create),
4952
#[command(about = "Dump wallet descriptors")]
@@ -52,8 +55,12 @@ pub(crate) enum Subcommand {
5255
Inscribe(inscribe::Inscribe),
5356
#[command(about = "List wallet inscriptions")]
5457
Inscriptions,
58+
#[command(about = "Export output labels")]
59+
Label,
5560
#[command(about = "Mint a rune")]
5661
Mint(mint::Mint),
62+
#[command(about = "List all unspent outputs in wallet")]
63+
Outputs,
5764
#[command(about = "Generate receive address")]
5865
Receive(receive::Receive),
5966
#[command(about = "Restore wallet")]
@@ -66,10 +73,6 @@ pub(crate) enum Subcommand {
6673
Send(send::Send),
6774
#[command(about = "See wallet transactions")]
6875
Transactions(transactions::Transactions),
69-
#[command(about = "List all unspent outputs in wallet")]
70-
Outputs,
71-
#[command(about = "List unspent cardinal outputs in wallet")]
72-
Cardinals,
7376
}
7477

7578
impl WalletCommand {
@@ -97,18 +100,19 @@ impl WalletCommand {
97100
match self.subcommand {
98101
Subcommand::Balance => balance::run(wallet),
99102
Subcommand::Batch(batch) => batch.run(wallet),
103+
Subcommand::Cardinals => cardinals::run(wallet),
104+
Subcommand::Create(_) | Subcommand::Restore(_) => unreachable!(),
100105
Subcommand::Dump => dump::run(wallet),
101106
Subcommand::Inscribe(inscribe) => inscribe.run(wallet),
102107
Subcommand::Inscriptions => inscriptions::run(wallet),
108+
Subcommand::Label => label::run(wallet),
103109
Subcommand::Mint(mint) => mint.run(wallet),
110+
Subcommand::Outputs => outputs::run(wallet),
104111
Subcommand::Receive(receive) => receive.run(wallet),
105112
Subcommand::Resume => resume::run(wallet),
106113
Subcommand::Sats(sats) => sats.run(wallet),
107114
Subcommand::Send(send) => send.run(wallet),
108115
Subcommand::Transactions(transactions) => transactions.run(wallet),
109-
Subcommand::Outputs => outputs::run(wallet),
110-
Subcommand::Cardinals => cardinals::run(wallet),
111-
Subcommand::Create(_) | Subcommand::Restore(_) => unreachable!(),
112116
}
113117
}
114118
}

src/subcommand/wallet/label.rs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use super::*;
2+
3+
#[derive(Serialize)]
4+
struct Label {
5+
first_sat: SatLabel,
6+
inscriptions: BTreeMap<u64, BTreeSet<InscriptionId>>,
7+
}
8+
9+
#[derive(Serialize)]
10+
struct SatLabel {
11+
name: String,
12+
number: u64,
13+
rarity: Rarity,
14+
}
15+
16+
#[derive(Serialize)]
17+
struct Line {
18+
label: String,
19+
r#ref: String,
20+
r#type: String,
21+
}
22+
23+
pub(crate) fn run(wallet: Wallet) -> SubcommandResult {
24+
let mut lines: Vec<Line> = Vec::new();
25+
26+
let sat_ranges = wallet.get_output_sat_ranges()?;
27+
28+
let mut inscriptions_by_output: BTreeMap<OutPoint, BTreeMap<u64, Vec<InscriptionId>>> =
29+
BTreeMap::new();
30+
31+
for (satpoint, inscriptions) in wallet.inscriptions() {
32+
inscriptions_by_output
33+
.entry(satpoint.outpoint)
34+
.or_default()
35+
.insert(satpoint.offset, inscriptions.clone());
36+
}
37+
38+
for (output, ranges) in sat_ranges {
39+
let sat = Sat(ranges[0].0);
40+
let mut inscriptions = BTreeMap::<u64, BTreeSet<InscriptionId>>::new();
41+
42+
if let Some(output_inscriptions) = inscriptions_by_output.get(&output) {
43+
for (&offset, offset_inscriptions) in output_inscriptions {
44+
inscriptions
45+
.entry(offset)
46+
.or_default()
47+
.extend(offset_inscriptions);
48+
}
49+
}
50+
51+
lines.push(Line {
52+
label: serde_json::to_string(&Label {
53+
first_sat: SatLabel {
54+
name: sat.name(),
55+
number: sat.n(),
56+
rarity: sat.rarity(),
57+
},
58+
inscriptions,
59+
})?,
60+
r#ref: output.to_string(),
61+
r#type: "output".into(),
62+
});
63+
}
64+
65+
for line in lines {
66+
serde_json::to_writer(io::stdout(), &line)?;
67+
println!();
68+
}
69+
70+
Ok(None)
71+
}

0 commit comments

Comments
 (0)