Repository: ordinals/ord (rust)

Issue:
Burn commmand should always burn one sat
Since the burn command is for burning inscriptions, it should default to burning the minimum amount of BTC possible to burn an inscription, i.e., one sat. (I think OP_RETURN outputs are not required to be above the dust limit.)

Also, I think `--postage` option should be removed, since I can't think of a good reason to specify some other amount of postage, especially because we forbid large values for postage, and the only reason to have customizable postage would be to burn large amounts of BTC along with the inscription.

Pull request:
Only burn one sat
Resolves #3977 

Tbh not sure if it's actually that simple. Tested with [this inscription](https://ordinals.com/inscription/fb2de94a4b1c30dbf9c228dec2971ae1bc88ffb3479ae59ecb981f1f65add1eci0). And this was the [burn tx](https://mempool.space/tx/97ad0dae72ab33fa0e64cc573d3b54d19a282c2e1af6bb0ac326f41d6c67c503).

Patch:
diff --git a/src/subcommand/wallet/burn.rs b/src/subcommand/wallet/burn.rs
index fb9c7d73..6f36887b 100644
--- a/src/subcommand/wallet/burn.rs
+++ b/src/subcommand/wallet/burn.rs
@@ -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,
 }
 
@@ -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);
 
@@ -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();
@@ -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,
@@ -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()?;
 
@@ -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,
@@ -149,7 +135,7 @@ impl Burn {
         script_pubkey,
         change,
         fee_rate,
-        postage,
+        Target::ExactPostage(burn_amount),
         wallet.chain().network(),
       )
       .build_transaction()?,


Test patch:
diff --git a/tests/wallet/burn.rs b/tests/wallet/burn.rs
index a3670523..232c04a4 100644
--- a/tests/wallet/burn.rs
+++ b/tests/wallet/burn.rs
@@ -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>
@@ -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, &[], &[]);
@@ -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]
@@ -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();
@@ -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,
@@ -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,