Skip to content

Commit

Permalink
Implement burning
Browse files Browse the repository at this point in the history
  • Loading branch information
onchainguy-btc committed Apr 14, 2024
1 parent f07db71 commit b9400f1
Show file tree
Hide file tree
Showing 8 changed files with 393 additions and 110 deletions.
7 changes: 6 additions & 1 deletion crates/ordinals/src/charm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ pub enum Charm {
Uncommon = 9,
Vindicated = 10,
Mythic = 11,
Burned = 12,
}

impl Charm {
pub const ALL: [Self; 12] = [
pub const ALL: [Self; 13] = [
Self::Coin,
Self::Uncommon,
Self::Rare,
Expand All @@ -30,6 +31,7 @@ impl Charm {
Self::Unbound,
Self::Lost,
Self::Vindicated,
Self::Burned,
];

fn flag(self) -> u16 {
Expand Down Expand Up @@ -62,6 +64,7 @@ impl Charm {
Self::Unbound => "🔓",
Self::Uncommon => "🌱",
Self::Vindicated => "❤️‍🔥",
Self::Burned => "💀🔥",
}
}

Expand Down Expand Up @@ -91,6 +94,7 @@ impl Display for Charm {
Self::Unbound => "unbound",
Self::Uncommon => "uncommon",
Self::Vindicated => "vindicated",
Self::Burned => "burned",
}
)
}
Expand All @@ -113,6 +117,7 @@ impl FromStr for Charm {
"unbound" => Self::Unbound,
"uncommon" => Self::Uncommon,
"vindicated" => Self::Vindicated,
"burned" => Self::Burned,
_ => return Err(format!("invalid charm `{s}`")),
})
}
Expand Down
30 changes: 28 additions & 2 deletions src/index/updater/inscription_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ impl<'a, 'tx> InscriptionUpdater<'a, 'tx> {
let mut range_to_vout = BTreeMap::new();
let mut new_locations = Vec::new();
let mut output_value = 0;
let mut is_burned = false;
for (vout, tx_out) in tx.output.iter().enumerate() {
let end = output_value + tx_out.value;

Expand All @@ -307,6 +308,7 @@ impl<'a, 'tx> InscriptionUpdater<'a, 'tx> {
offset: flotsam.offset - output_value,
};

is_burned = tx_out.script_pubkey.is_op_return();
new_locations.push((new_satpoint, inscriptions.next().unwrap()));
}

Expand Down Expand Up @@ -345,7 +347,7 @@ impl<'a, 'tx> InscriptionUpdater<'a, 'tx> {
_ => new_satpoint,
};

self.update_inscription_location(input_sat_ranges, flotsam, new_satpoint)?;
self.update_inscription_location(input_sat_ranges, flotsam, new_satpoint, is_burned)?;
}

if is_coinbase {
Expand All @@ -354,7 +356,7 @@ impl<'a, 'tx> InscriptionUpdater<'a, 'tx> {
outpoint: OutPoint::null(),
offset: self.lost_sats + flotsam.offset - output_value,
};
self.update_inscription_location(input_sat_ranges, flotsam, new_satpoint)?;
self.update_inscription_location(input_sat_ranges, flotsam, new_satpoint, false)?;
}
self.lost_sats += self.reward - output_value;
Ok(())
Expand Down Expand Up @@ -392,6 +394,7 @@ impl<'a, 'tx> InscriptionUpdater<'a, 'tx> {
input_sat_ranges: Option<&VecDeque<(u64, u64)>>,
flotsam: Flotsam,
new_satpoint: SatPoint,
is_burned: bool,
) -> Result {
let inscription_id = flotsam.inscription_id;
let (unbound, sequence_number) = match flotsam.origin {
Expand All @@ -406,6 +409,29 @@ impl<'a, 'tx> InscriptionUpdater<'a, 'tx> {
.unwrap()
.value();

println!("is_burned {}", is_burned);

if is_burned {
let entry = InscriptionEntry::load(
self.sequence_number_to_entry
.get(&sequence_number)?
.unwrap()
.value(),
);

let mut charms = entry.charms.clone();
Charm::Burned.set(&mut charms);

self.sequence_number_to_entry.insert(
sequence_number,
&InscriptionEntry {
charms,
..entry
}
.store(),
)?;
}

if let Some(sender) = self.event_sender {
sender.blocking_send(Event::InscriptionTransferred {
block_height: self.height,
Expand Down
64 changes: 46 additions & 18 deletions src/subcommand/wallet/send.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
use {super::*, crate::outgoing::Outgoing, base64::Engine, bitcoin::psbt::Psbt};
use {super::*, crate::outgoing::Outgoing, base64::Engine, bitcoin::{opcodes,psbt::Psbt}};

#[derive(Clone, Copy)]
struct AddressParser;

#[derive(Clone, Debug, PartialEq)]
enum ParsedAddress {
Address(Address<NetworkUnchecked>),
ScriptBuf(ScriptBuf),
}

fn parse_address(arg: &str) -> Result<ParsedAddress, bitcoin::address::Error> {
if arg == "burn" {
let builder = script::Builder::new()
.push_opcode(opcodes::all::OP_RETURN);
Ok(ParsedAddress::ScriptBuf(builder.into_script()))
} else {
Ok(ParsedAddress::Address(Address::from_str(arg)?))
}
}

#[derive(Debug, Parser)]
pub(crate) struct Send {
Expand All @@ -11,7 +30,8 @@ pub(crate) struct Send {
help = "Target <AMOUNT> postage with sent inscriptions. [default: 10000 sat]"
)]
pub(crate) postage: Option<Amount>,
address: Address<NetworkUnchecked>,
#[arg(value_parser = parse_address)]
address: ParsedAddress,
outgoing: Outgoing,
}

Expand All @@ -25,25 +45,32 @@ pub struct Output {

impl Send {
pub(crate) fn run(self, wallet: Wallet) -> SubcommandResult {
let address = self
.address
.clone()
.require_network(wallet.chain().network())?;
let recipient = match self.address {
ParsedAddress::Address(address) => {
address
.clone()
.require_network(wallet.chain().network())?
.script_pubkey()
}
ParsedAddress::ScriptBuf(script_buf) => {
script_buf.clone()
}
};

let unsigned_transaction = match self.outgoing {
Outgoing::Amount(amount) => {
Self::create_unsigned_send_amount_transaction(&wallet, address, amount, self.fee_rate)?
Self::create_unsigned_send_amount_transaction(&wallet, recipient, amount, self.fee_rate)?
}
Outgoing::Rune { decimal, rune } => Self::create_unsigned_send_runes_transaction(
&wallet,
address,
recipient,
rune,
decimal,
self.fee_rate,
)?,
Outgoing::InscriptionId(id) => Self::create_unsigned_send_satpoint_transaction(
&wallet,
address,
recipient,
wallet
.inscription_info()
.get(&id)
Expand All @@ -55,15 +82,15 @@ impl Send {
)?,
Outgoing::SatPoint(satpoint) => Self::create_unsigned_send_satpoint_transaction(
&wallet,
address,
recipient,
satpoint,
self.postage,
self.fee_rate,
false,
)?,
Outgoing::Sat(sat) => Self::create_unsigned_send_satpoint_transaction(
&wallet,
address,
recipient,
wallet.find_sat_in_outputs(sat)?,
self.postage,
self.fee_rate,
Expand Down Expand Up @@ -132,7 +159,7 @@ impl Send {

fn create_unsigned_send_amount_transaction(
wallet: &Wallet,
destination: Address,
destination: ScriptBuf,
amount: Amount,
fee_rate: FeeRate,
) -> Result<Transaction> {
Expand All @@ -143,7 +170,7 @@ impl Send {
lock_time: LockTime::ZERO,
input: Vec::new(),
output: vec![TxOut {
script_pubkey: destination.script_pubkey(),
script_pubkey: destination,
value: amount.to_sat(),
}],
};
Expand All @@ -159,7 +186,7 @@ impl Send {

fn create_unsigned_send_satpoint_transaction(
wallet: &Wallet,
destination: Address,
destination: ScriptBuf,
satpoint: SatPoint,
postage: Option<Amount>,
fee_rate: FeeRate,
Expand Down Expand Up @@ -195,18 +222,19 @@ impl Send {
wallet.utxos().clone(),
wallet.locked_utxos().clone().into_keys().collect(),
runic_outputs,
destination.clone(),
destination,
change,
fee_rate,
postage,
wallet.chain().network()
)
.build_transaction()?,
.build_transaction()?,
)
}

fn create_unsigned_send_runes_transaction(
wallet: &Wallet,
destination: Address,
destination: ScriptBuf,
spaced_rune: SpacedRune,
decimal: Decimal,
fee_rate: FeeRate,
Expand Down Expand Up @@ -295,7 +323,7 @@ impl Send {
value: TARGET_POSTAGE.to_sat(),
},
TxOut {
script_pubkey: destination.script_pubkey(),
script_pubkey: destination,
value: TARGET_POSTAGE.to_sat(),
},
],
Expand Down
16 changes: 15 additions & 1 deletion src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(crate) use {
std::iter,
tempfile::TempDir,
unindent::Unindent,
wallet::transaction_builder::OutputType
};

pub(crate) fn txid(n: u64) -> Txid {
Expand Down Expand Up @@ -40,7 +41,16 @@ pub(crate) fn address() -> Address {
.assume_checked()
}

pub(crate) fn recipient() -> Address {
pub(crate) fn recipient() -> ScriptBuf {
recipient_as_address()
.script_pubkey()
}

pub(crate) fn recipient_address_as_output_type() -> OutputType {
OutputType::Address(recipient_as_address())
}

pub(crate) fn recipient_as_address() -> Address {
"tb1q6en7qjxgw4ev8xwx94pzdry6a6ky7wlfeqzunz"
.parse::<Address<NetworkUnchecked>>()
.unwrap()
Expand All @@ -60,6 +70,10 @@ pub(crate) fn change(n: u64) -> Address {
.assume_checked()
}

pub(crate) fn change_as_output_type(n: u64) -> OutputType {
OutputType::Address(change(n))
}

pub(crate) fn tx_in(previous_output: OutPoint) -> TxIn {
TxIn {
previous_output,
Expand Down
3 changes: 2 additions & 1 deletion src/wallet/batch/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,10 +523,11 @@ impl Plan {
utxos.clone(),
locked_utxos.clone(),
runic_utxos,
commit_tx_address.clone(),
commit_tx_address.script_pubkey(),
commit_change,
self.commit_fee_rate,
Target::Value(target_value),
chain.network()
)
.build_transaction()?;

Expand Down
56 changes: 56 additions & 0 deletions src/wallet/recipient.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use rustls_acme::acme::AuthStatus::Invalid;
use super::*;

#[derive(Debug, PartialEq)]
pub(crate) enum RecipientError {
InvalidRecipient
}

impl Display for RecipientError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
RecipientError::InvalidRecipient => {
write!(f, "Invalid recipient")
}
}
}
}

impl std::error::Error for RecipientError {}

#[derive(Clone, Debug, PartialEq)]
pub(crate) enum Recipient {
Address(Address),
ScriptBuf(ScriptBuf),
}

trait ScriptPubkey {
fn script_pubkey(&self) -> ScriptBuf;
}

impl ScriptPubkey for Address {
fn script_pubkey(&self) -> ScriptBuf {
self.script_pubkey()
}
}

impl ScriptPubkey for ScriptBuf {
fn script_pubkey(&self) -> ScriptBuf {
self.clone()
}
}

impl Recipient {
pub fn to_address(&self) -> Result<Address> {
match self {
Recipient::Address(address) => Ok(address.clone()),
_ => Err(anyhow!(RecipientError::InvalidRecipient)),
}
}
pub fn script_pubkey(&self) -> ScriptBuf {
match self {
Recipient::Address(address) => address.script_pubkey(),
Recipient::ScriptBuf(script_buf) => script_buf.script_pubkey(),
}
}
}
Loading

0 comments on commit b9400f1

Please sign in to comment.