Skip to content

Commit

Permalink
Only burn one sat (ordinals#4063)
Browse files Browse the repository at this point in the history
  • Loading branch information
onchainguy-btc authored Nov 29, 2024
1 parent ee2c25b commit 5749363
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 60 deletions.
42 changes: 14 additions & 28 deletions src/subcommand/wallet/burn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,6 @@ pub struct Burn {
you understand the implications."
)]
no_limit: bool,
#[arg(
long,
help = "Target <AMOUNT> postage with sent inscriptions. [default: 10000 sat]",
value_name = "AMOUNT"
)]
postage: Option<Amount>,
inscription: InscriptionId,
}

Expand All @@ -47,21 +41,10 @@ impl Burn {

let metadata = WalletCommand::parse_metadata(self.cbor_metadata, self.json_metadata)?;

let Some(value) = inscription_info.value else {
bail!("Cannot burn unbound inscription");
};

let value = Amount::from_sat(value);

ensure! {
value <= TARGET_POSTAGE,
"Cannot burn inscription contained in UTXO exceeding {TARGET_POSTAGE}",
}

ensure! {
self.postage.unwrap_or_default() <= TARGET_POSTAGE,
"Postage may not exceed {TARGET_POSTAGE}",
}
ensure!(
inscription_info.value.is_some(),
"Cannot burn unbound inscription"
);

let mut builder = script::Builder::new().push_opcode(opcodes::all::OP_RETURN);

Expand Down Expand Up @@ -96,12 +79,14 @@ impl Burn {
MAX_STANDARD_OP_RETURN_SIZE,
);

let burn_amount = Amount::from_sat(1);

let unsigned_transaction = Self::create_unsigned_burn_transaction(
&wallet,
inscription_info.satpoint,
self.postage,
self.fee_rate,
script_pubkey,
burn_amount,
)?;

let base_size = unsigned_transaction.base_size();
Expand All @@ -110,8 +95,11 @@ impl Burn {
"transaction base size less than minimum standard tx nonwitness size: {base_size} < 65",
);

let (txid, psbt, fee) =
wallet.sign_and_broadcast_transaction(unsigned_transaction, self.dry_run, Some(value))?;
let (txid, psbt, fee) = wallet.sign_and_broadcast_transaction(
unsigned_transaction,
self.dry_run,
Some(burn_amount),
)?;

Ok(Some(Box::new(send::Output {
txid,
Expand All @@ -124,9 +112,9 @@ impl Burn {
fn create_unsigned_burn_transaction(
wallet: &Wallet,
satpoint: SatPoint,
postage: Option<Amount>,
fee_rate: FeeRate,
script_pubkey: ScriptBuf,
burn_amount: Amount,
) -> Result<Transaction> {
let runic_outputs = wallet.get_runic_outputs()?;

Expand All @@ -137,8 +125,6 @@ impl Burn {

let change = [wallet.get_change_address()?, wallet.get_change_address()?];

let postage = postage.map(Target::ExactPostage).unwrap_or(Target::Postage);

Ok(
TransactionBuilder::new(
satpoint,
Expand All @@ -149,7 +135,7 @@ impl Burn {
script_pubkey,
change,
fee_rate,
postage,
Target::ExactPostage(burn_amount),
wallet.chain().network(),
)
.build_transaction()?,
Expand Down
71 changes: 39 additions & 32 deletions tests/wallet/burn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn inscriptions_can_be_burned() {
<span title=burned>🔥</span>
</dd>
<dt>value</dt>
<dd>9918</dd>
<dd>1</dd>
.*
<dt>content length</dt>
<dd>3 bytes</dd>
Expand Down Expand Up @@ -116,7 +116,7 @@ fn runic_outputs_are_protected() {
}

#[test]
fn cannot_burn_inscriptions_on_large_utxos() {
fn burns_only_one_sat() {
let core = mockcore::spawn();

let ord = TestServer::spawn_with_server_args(&core, &[], &[]);
Expand All @@ -125,14 +125,45 @@ fn cannot_burn_inscriptions_on_large_utxos() {

core.mine_blocks(1);

let (inscription, _) = inscribe_with_postage(&core, &ord, Some(10_001));
assert_eq!(
CommandBuilder::new("wallet balance")
.core(&core)
.ord(&ord)
.run_and_deserialize_output::<Balance>(),
Balance {
cardinal: 50 * COIN_VALUE,
ordinal: 0,
runic: None,
runes: None,
total: 50 * COIN_VALUE,
}
);

let (inscription, _) = inscribe_with_postage(&core, &ord, Some(100_000));

CommandBuilder::new(format!("wallet burn --fee-rate 1 {inscription}",))
.core(&core)
.ord(&ord)
.expected_stderr("error: Cannot burn inscription contained in UTXO exceeding 0.00010000 BTC\n")
.expected_exit_code(1)
.run_and_extract_stdout();
.run_and_deserialize_output::<Send>();

core.mine_blocks(1);

// 4 block rewards - 1 burned sat
let expected_balance = 4 * 50 * COIN_VALUE - 1;

assert_eq!(
CommandBuilder::new("wallet balance")
.core(&core)
.ord(&ord)
.run_and_deserialize_output::<Balance>(),
Balance {
cardinal: expected_balance,
ordinal: 0,
runic: None,
runes: None,
total: expected_balance,
}
);
}

#[test]
Expand Down Expand Up @@ -191,30 +222,6 @@ fn cannot_burn_inscription_sharing_utxo_with_another_inscription() {
.run_and_extract_stdout();
}

#[test]
fn cannot_burn_with_excess_postage() {
let core = mockcore::spawn();

let ord = TestServer::spawn_with_server_args(&core, &[], &[]);

create_wallet(&core, &ord);

core.mine_blocks(1);

let (inscription, _) = inscribe(&core, &ord);

core.mine_blocks(1);

CommandBuilder::new(format!(
"wallet burn --fee-rate 1 {inscription} --postage 10001sat",
))
.core(&core)
.ord(&ord)
.expected_stderr("error: Postage may not exceed 0.00010000 BTC\n")
.expected_exit_code(1)
.run_and_extract_stdout();
}

#[test]
fn json_metadata_can_be_included_when_burning() {
let core = mockcore::spawn();
Expand Down Expand Up @@ -258,7 +265,7 @@ fn json_metadata_can_be_included_when_burning() {
fee: 138,
id: inscription,
output: Some(TxOut {
value: Amount::from_sat(9907),
value: Amount::from_sat(1),
script_pubkey,
}),
height: 3,
Expand Down Expand Up @@ -327,7 +334,7 @@ fn cbor_metadata_can_be_included_when_burning() {
fee: 138,
id: inscription,
output: Some(TxOut {
value: Amount::from_sat(9907),
value: Amount::from_sat(1),
script_pubkey,
}),
height: 3,
Expand Down

0 comments on commit 5749363

Please sign in to comment.