diff --git a/src/subcommand/wallet/inscribe.rs b/src/subcommand/wallet/inscribe.rs index d28b4d3ee5..24cf80a7de 100644 --- a/src/subcommand/wallet/inscribe.rs +++ b/src/subcommand/wallet/inscribe.rs @@ -37,7 +37,7 @@ pub(crate) struct Inscribe { pub(crate) parent: Option, #[arg( long, - help = "Amount of postage to include in the inscription. Default `10000sat`." + help = "Include postage with inscription. [default: 10000sat]" )] pub(crate) postage: Option, #[clap(long, help = "Allow reinscription.")] diff --git a/src/subcommand/wallet/mint.rs b/src/subcommand/wallet/mint.rs index fe2f0ef2ed..1dd70a0efb 100644 --- a/src/subcommand/wallet/mint.rs +++ b/src/subcommand/wallet/mint.rs @@ -6,6 +6,11 @@ pub(crate) struct Mint { fee_rate: FeeRate, #[clap(long, help = "Mint . May contain `.` or `•`as spacers.")] rune: SpacedRune, + #[clap( + long, + help = "Include postage with mint output. [default: 10000sat]" + )] + postage: Option, #[clap(long, help = "Send minted runes to .")] destination: Option>, } @@ -34,6 +39,8 @@ impl Mint { bail!("rune {rune} has not been etched"); }; + let postage = self.postage.unwrap_or(TARGET_POSTAGE); + let amount = rune_entry .mintable(block_height) .map_err(|err| anyhow!("rune {rune} {err}"))?; @@ -45,6 +52,12 @@ impl Mint { None => wallet.get_change_address()?, }; + ensure!( + destination.script_pubkey().dust_value() < postage, + "postage below dust limit of {}sat", + destination.script_pubkey().dust_value().to_sat() + ); + let runestone = Runestone { mint: Some(id), ..default() @@ -69,7 +82,7 @@ impl Mint { }, TxOut { script_pubkey: destination.script_pubkey(), - value: TARGET_POSTAGE.to_sat(), + value: postage.to_sat(), }, ], }; diff --git a/src/subcommand/wallet/send.rs b/src/subcommand/wallet/send.rs index 3a7fd5ae66..7471b13f31 100644 --- a/src/subcommand/wallet/send.rs +++ b/src/subcommand/wallet/send.rs @@ -8,7 +8,7 @@ pub(crate) struct Send { fee_rate: FeeRate, #[arg( long, - help = "Target amount of postage to include with sent inscriptions [default: 10000 sat]" + help = "Target postage with sent inscriptions. [default: 10000 sat]" )] pub(crate) postage: Option, address: Address, diff --git a/tests/wallet/mint.rs b/tests/wallet/mint.rs index 84342a1529..db8da67170 100644 --- a/tests/wallet/mint.rs +++ b/tests/wallet/mint.rs @@ -218,6 +218,8 @@ fn minting_rune_and_then_sending_works() { } ); + assert_eq!(balance.runic.unwrap(), 10000); + let output = CommandBuilder::new(format!( "--chain regtest --index-runes wallet mint --fee-rate 1 --rune {}", Rune(RUNE) @@ -241,6 +243,8 @@ fn minting_rune_and_then_sending_works() { } ); + assert_eq!(balance.runic.unwrap(), 20000); + pretty_assert_eq!( output.pile, Pile { @@ -363,3 +367,125 @@ fn minting_rune_with_destination() { } ); } + +#[test] +fn minting_rune_with_postage() { + let core = mockcore::builder().network(Network::Regtest).build(); + + let ord = TestServer::spawn_with_server_args(&core, &["--index-runes", "--regtest"], &[]); + + core.mine_blocks(1); + + create_wallet(&core, &ord); + + batch( + &core, + &ord, + batch::File { + etching: Some(batch::Etching { + divisibility: 0, + rune: SpacedRune { + rune: Rune(RUNE), + spacers: 0, + }, + premine: "0".parse().unwrap(), + supply: "21".parse().unwrap(), + symbol: '¢', + turbo: false, + terms: Some(batch::Terms { + cap: 1, + offset: Some(batch::Range { + end: Some(10), + start: None, + }), + amount: "21".parse().unwrap(), + height: None, + }), + }), + inscriptions: vec![batch::Entry { + file: Some("inscription.jpeg".into()), + ..default() + }], + ..default() + }, + ); + + let output = CommandBuilder::new(format!( + "--chain regtest --index-runes wallet mint --fee-rate 1 --rune {} --postage 2222sat", + Rune(RUNE) + )) + .core(&core) + .ord(&ord) + .run_and_deserialize_output::(); + + pretty_assert_eq!( + output.pile, + Pile { + amount: 21, + divisibility: 0, + symbol: Some('¢'), + } + ); + + core.mine_blocks(1); + + let balance = CommandBuilder::new("--chain regtest --index-runes wallet balance") + .core(&core) + .ord(&ord) + .run_and_deserialize_output::(); + + assert_eq!(balance.runic.unwrap(), 2222); +} + +#[test] +fn minting_rune_with_postage_dust() { + let core = mockcore::builder().network(Network::Regtest).build(); + + let ord = TestServer::spawn_with_server_args(&core, &["--index-runes", "--regtest"], &[]); + + core.mine_blocks(1); + + create_wallet(&core, &ord); + + batch( + &core, + &ord, + batch::File { + etching: Some(batch::Etching { + divisibility: 0, + rune: SpacedRune { + rune: Rune(RUNE), + spacers: 0, + }, + premine: "0".parse().unwrap(), + supply: "21".parse().unwrap(), + symbol: '¢', + turbo: false, + terms: Some(batch::Terms { + cap: 1, + offset: Some(batch::Range { + end: Some(10), + start: None, + }), + amount: "21".parse().unwrap(), + height: None, + }), + }), + inscriptions: vec![batch::Entry { + file: Some("inscription.jpeg".into()), + ..default() + }], + ..default() + }, + ); + + CommandBuilder::new(format!( + "--chain regtest --index-runes wallet mint --fee-rate 1 --rune {} --postage 300sat", + Rune(RUNE) + )) + .core(&core) + .ord(&ord) + .expected_exit_code(1) + .expected_stderr("error: postage below dust limit of 330sat\n") + .run_and_extract_stdout(); +}