Skip to content

Commit

Permalink
Allow sending sat (ordinals#3200)
Browse files Browse the repository at this point in the history
  • Loading branch information
bingryan authored Mar 22, 2024
1 parent d01fe58 commit d895c2e
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 4 deletions.
27 changes: 24 additions & 3 deletions src/outgoing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub enum Outgoing {
Amount(Amount),
InscriptionId(InscriptionId),
SatPoint(SatPoint),
Sat(Sat),
Rune { decimal: Decimal, rune: SpacedRune },
}

Expand All @@ -13,6 +14,7 @@ impl Display for Outgoing {
match self {
Self::Amount(amount) => write!(f, "{}", amount.to_string().to_lowercase()),
Self::InscriptionId(inscription_id) => inscription_id.fmt(f),
Self::Sat(sat) => sat.fmt(f),
Self::SatPoint(satpoint) => satpoint.fmt(f),
Self::Rune { decimal, rune } => write!(f, "{decimal} {rune}"),
}
Expand Down Expand Up @@ -61,7 +63,9 @@ impl FromStr for Outgoing {
.unwrap();
}

Ok(if re::SATPOINT.is_match(s) {
Ok(if s.parse::<Sat>().is_ok() {
Self::Sat(s.parse()?)
} else if re::SATPOINT.is_match(s) {
Self::SatPoint(s.parse()?)
} else if re::INSCRIPTION_ID.is_match(s) {
Self::InscriptionId(s.parse()?)
Expand Down Expand Up @@ -107,6 +111,12 @@ mod tests {
assert_eq!(s.parse::<Outgoing>().unwrap(), outgoing);
}

case("0", Outgoing::Sat("0".parse().unwrap()));
case(
"2099999997689999",
Outgoing::Sat("2099999997689999".parse().unwrap()),
);

case(
"0000000000000000000000000000000000000000000000000000000000000000i0",
Outgoing::InscriptionId(
Expand Down Expand Up @@ -177,8 +187,6 @@ mod tests {
decimal: "1.1".parse().unwrap(),
},
);

assert!("0".parse::<Outgoing>().is_err());
}

#[test]
Expand All @@ -189,6 +197,12 @@ mod tests {
assert_eq!(s, outgoing.to_string());
}

case("0", Outgoing::Sat("0".parse().unwrap()));
case(
"2099999997689999",
Outgoing::Sat("2099999997689999".parse().unwrap()),
);

case(
"0000000000000000000000000000000000000000000000000000000000000000i0",
Outgoing::InscriptionId(
Expand Down Expand Up @@ -236,6 +250,13 @@ mod tests {
assert_eq!(serde_json::from_str::<Outgoing>(j).unwrap(), o);
}

case("0", "\"0\"", Outgoing::Sat("0".parse().unwrap()));
case(
"2099999997689999",
"\"2099999997689999\"",
Outgoing::Sat("2099999997689999".parse().unwrap()),
);

case(
"0000000000000000000000000000000000000000000000000000000000000000i0",
"\"0000000000000000000000000000000000000000000000000000000000000000i0\"",
Expand Down
8 changes: 8 additions & 0 deletions src/subcommand/wallet/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ impl Send {
self.fee_rate,
false,
)?,
Outgoing::Sat(sat) => Self::create_unsigned_send_satpoint_transaction(
&wallet,
address,
wallet.find_sat_in_outputs(sat)?,
self.postage,
self.fee_rate,
true,
)?,
};

let unspent_outputs = wallet.utxos();
Expand Down
13 changes: 13 additions & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ fn receive(
.unwrap()
}

fn sats(
bitcoin_rpc_server: &test_bitcoincore_rpc::Handle,
ord_rpc_server: &TestServer,
) -> Vec<ord::subcommand::wallet::sats::OutputRare> {
CommandBuilder::new(format!(
"--chain {} wallet sats",
bitcoin_rpc_server.network()
))
.bitcoin_rpc_server(bitcoin_rpc_server)
.ord_rpc_server(ord_rpc_server)
.run_and_deserialize_output::<Vec<ord::subcommand::wallet::sats::OutputRare>>()
}

fn inscribe(
bitcoin_rpc_server: &test_bitcoincore_rpc::Handle,
ord_rpc_server: &TestServer,
Expand Down
63 changes: 62 additions & 1 deletion tests/wallet/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fn send_unknown_inscription() {
}

#[test]
fn send_inscribed_sat() {
fn send_inscribed_inscription() {
let bitcoin_rpc_server = test_bitcoincore_rpc::spawn();

let ord_rpc_server = TestServer::spawn_with_server_args(&bitcoin_rpc_server, &[], &[]);
Expand Down Expand Up @@ -100,6 +100,67 @@ fn send_inscribed_sat() {
);
}

#[test]
fn send_uninscribed_sat() {
let bitcoin_rpc_server = test_bitcoincore_rpc::spawn();

let ord_rpc_server =
TestServer::spawn_with_server_args(&bitcoin_rpc_server, &["--index-sats"], &[]);

create_wallet(&bitcoin_rpc_server, &ord_rpc_server);

let sat = 1;

CommandBuilder::new(format!(
"wallet send --fee-rate 1 bc1qcqgs2pps4u4yedfyl5pysdjjncs8et5utseepv {sat}"
))
.bitcoin_rpc_server(&bitcoin_rpc_server)
.ord_rpc_server(&ord_rpc_server)
.expected_stderr(format!(
"error: could not find sat `{sat}` in wallet outputs\n"
))
.expected_exit_code(1)
.run_and_extract_stdout();
}

#[test]
fn send_inscription_by_sat() {
let bitcoin_rpc_server = test_bitcoincore_rpc::spawn();

let ord_rpc_server =
TestServer::spawn_with_server_args(&bitcoin_rpc_server, &["--index-sats"], &[]);

create_wallet(&bitcoin_rpc_server, &ord_rpc_server);

bitcoin_rpc_server.mine_blocks(1);

let (inscription, txid) = inscribe(&bitcoin_rpc_server, &ord_rpc_server);

bitcoin_rpc_server.mine_blocks(1);

let sat_list = sats(&bitcoin_rpc_server, &ord_rpc_server);

let sat = sat_list.iter().find(|s| s.output.txid == txid).unwrap().sat;

let address = "bc1qcqgs2pps4u4yedfyl5pysdjjncs8et5utseepv";

let output = CommandBuilder::new(format!("wallet send --fee-rate 1 {address} {sat}"))
.bitcoin_rpc_server(&bitcoin_rpc_server)
.ord_rpc_server(&ord_rpc_server)
.run_and_deserialize_output::<Send>();

bitcoin_rpc_server.mine_blocks(1);

let send_txid = output.txid;

ord_rpc_server.assert_response_regex(
format!("/inscription/{inscription}"),
format!(
".*<h1>Inscription 0</h1>.*<dt>address</dt>.*<dd class=monospace>{address}</dd>.*<dt>location</dt>.*<dd class=monospace>{send_txid}:0:0</dd>.*",
),
);
}

#[test]
fn send_on_mainnnet_works_with_wallet_named_foo() {
let bitcoin_rpc_server = test_bitcoincore_rpc::spawn();
Expand Down

0 comments on commit d895c2e

Please sign in to comment.