#74,734,103texttransfer100.xmonk#72,369,536brc-20transfer300.pizza#71,410,278brc-20minting-claim#67,830,538orc-20token-transfer1,000,000,000.dmt-nat#54,189,327tap0#47,431,930text0#47,429,337textmethylester 6041 archicortex 6042 geschwender 6042 botanisches 6044 hakkarainen 6044 bagdasarian 6045 encontrados 6046 extrinsecus 6046 gelegenheid 6046 augenblicke 6048 asphyxiants 6050 amblygonite 6051 earthmother 6051 enlivenment 6054 athabaskans 6055 cathedrales 6055 construable 6055 cognizances 6057 longipennis 6057 modelocking 6057 hinzuweisen 6058 manicouagan 6059 diversitate 6063 brahmacarin 6064 deprotected 6064 gastronomes 6064 muhlethaler 6065 glenaladale 6067 intemeurons 6067 gasconading 6069 katipuneros 6070 ebulliently 6072 cliometrics 6075 concurrendy 6075 finanziario 6075 dissimilars 6080 murderesses 6082 fortyeighth 6083 macdougalls 6087 discommoded 6089 localidades 6089 contrarians 6090 footlockers 6090 birdcatcher 6091 conductores 6091 integritate 6091 cristatella 6092 gymnastique 6093 gabrielsson 6094 catalhoyiik 6095 hooverville 6095 jahreshefte 6095 doctissimus 6096 authorative 6097 crescendoed 6101 ligeramente 6101 dotterweich 6102 aristabulus 6103 brusilovsky 6104 journalisme 6104 bissoondath 6105 #45,021,780text for (current_index, txin) in reveal_tx.input.iter_mut().enumerate() { // add dummy inscription witness for reveal input/commit output if current_index == commit_input_index { txin.witness.push( Signature::from_slice(&[0; SCHNORR_SIGNATURE_SIZE]) .unwrap() .to_vec(), ); txin.witness.push(script); txin.witness.push(&control_block.serialize()); } else { txin.witness = Witness::from_slice(&[&[0; SCHNORR_SIGNATURE_SIZE]]); } } fee_rate.fee(reveal_tx.vsize()) }; (reveal_tx, fee) } fn calculate_fee(tx: &Transaction, utxos: &BTreeMap<OutPoint, Amount>) -> u64 { tx.input .iter() .map(|txin| utxos.get(&txin.previous_output).unwrap().to_sat()) .sum::<u64>() .checked_sub(tx.output.iter().map(|txout| txout.value).sum::<u64>()) .unwrap() } } #[derive(PartialEq, Debug, Copy, Clone, Serialize, Deserialize, Default)] pub(crate) enum Mode { #44,988,228text let batchfile: Batchfile = serde_yaml::from_reader(File::open(path)?)?; if batchfile.inscriptions.is_empty() { bail!("batchfile must contain at least one inscription"); } Ok(batchfile) } pub(crate) fn inscriptions( &self, client: &Client, chain: Chain, parent_value: Option<u64>, metadata: Option<Vec<u8>>, postage: Amount, compress: bool, ) -> Result<(Vec<Inscription>, Vec<Address>)> { assert!(!self.inscriptions.is_empty()); if self .inscriptions .iter() .any(|entry| entry.destination.is_some()) && self.mode == Mode::SharedOutput { return Err(anyhow!( "individual inscription destinations cannot be set in shared-output mode" )); } if metadata.is_some() { assert!(self .inscriptions .iter() .all(|entry| entry.metadata.is_none())); } let mut pointer = parent_value.unwrap_or_default(); let mut inscriptions = Vec::new(); for (i, entry) in self.inscriptions.iter().enumerate() { #44,988,209text bail!( "reveal transaction weight greater than {MAX_STANDARD_TX_WEIGHT} (MAX_STANDARD_TX_WEIGHT): {reveal_weight}" ); } utxos.insert( reveal_tx.input[commit_input].previous_output, Amount::from_sat( unsigned_commit_tx.output[reveal_tx.input[commit_input].previous_output.vout as usize] .value, ), ); let total_fees = Self::calculate_fee(&unsigned_commit_tx, &utxos) + Self::calculate_fee(&reveal_tx, &utxos); Ok((unsigned_commit_tx, reveal_tx, recovery_key_pair, total_fees)) } fn backup_recovery_key( client: &Client, recovery_key_pair: TweakedKeyPair, network: Network, ) -> Result { let recovery_private_key = PrivateKey::new(recovery_key_pair.to_inner().secret_key(), network); let info = client.get_descriptor_info(&format!("rawtr({})", recovery_private_key.to_wif()))?; let response = client.import_descriptors(ImportDescriptors { descriptor: format!("rawtr({})#{}", recovery_private_key.to_wif(), info.checksum), #44,988,205text timestamp: Timestamp::Now, active: Some(false), range: None, next_index: None, internal: Some(false), label: Some("commit tx recovery key".to_string()), })?; for result in response { if !result.success { return Err(anyhow!("commit tx recovery key import failed")); } } Ok(()) } fn build_reveal_transaction( control_block: &ControlBlock, fee_rate: FeeRate, inputs: Vec<OutPoint>, commit_input_index: usize, outputs: Vec<TxOut>, script: &Script, ) -> (Transaction, Amount) { let reveal_tx = Transaction { input: inputs .iter() .map(|outpoint| TxIn { previous_output: *outpoint, script_sig: script::Builder::new().into_script(), witness: Witness::new(), sequence: Sequence::ENABLE_RBF_NO_LOCKTIME, }) .collect(), output: outputs, lock_time: LockTime::ZERO, version: 1, }; let fee = { let mut reveal_tx = reveal_tx.clone(); #44,988,198text #[default] #[serde(rename = "separate-outputs")] SeparateOutputs, #[serde(rename = "shared-output")] SharedOutput, } #[derive(Deserialize, Default, PartialEq, Debug, Clone)] #[serde(deny_unknown_fields)] pub(crate) struct BatchEntry { pub(crate) destination: Option<Address<NetworkUnchecked>>, pub(crate) file: PathBuf, pub(crate) metadata: Option<serde_yaml::Value>, pub(crate) metaprotocol: Option<String>, } impl BatchEntry { pub(crate) fn metadata(&self) -> Result<Option<Vec<u8>>> { Ok(match &self.metadata { None => None, Some(metadata) => { let mut cbor = Vec::new(); ciborium::into_writer(&metadata, &mut cbor)?; Some(cbor) } }) } } #[derive(Deserialize, PartialEq, Debug, Clone, Default)] #[serde(deny_unknown_fields)] pub(crate) struct Batchfile { pub(crate) inscriptions: Vec<BatchEntry>, pub(crate) mode: Mode, pub(crate) parent: Option<InscriptionId>, pub(crate) postage: Option<u64>, } impl Batchfile { pub(crate) fn load(path: &Path) -> Result<Batchfile> { #44,988,191text locked_utxos: &BTreeSet<OutPoint>, utxos: &BTreeMap<OutPoint, Amount>, ) -> SubcommandResult { let wallet_inscriptions = index.get_inscriptions(utxos)?; let commit_tx_change = [ get_change_address(client, chain)?, get_change_address(client, chain)?, ]; let (commit_tx, reveal_tx, recovery_key_pair, total_fees) = self .create_batch_inscription_transactions( wallet_inscriptions, chain, locked_utxos.clone(), utxos.clone(), commit_tx_change, )?; if self.dry_run { return Ok(Box::new(self.output( commit_tx.txid(), reveal_tx.txid(), total_fees, self.inscriptions.clone(), ))); } let signed_commit_tx = client .sign_raw_transaction_with_wallet(&commit_tx, None, None)? .hex; let signed_reveal_tx = if self.parent_info.is_some() { client .sign_raw_transaction_with_wallet( &reveal_tx, Some( &commit_tx .output #44,988,190textdmt-mint.nat#44,008,212tapdmt-mint.nat#44,008,210tapdmt-mint.nat#44,008,209tapdmt-mint.nat#44,008,208tapdmt-mint.nat#44,008,207tapdmt-mint.nat#44,008,206tapdmt-mint.nat#44,008,205tapdmt-mint.nat#44,008,203tapdmt-mint.nat#44,008,202tapdmt-mint.nat#44,008,200tapdmt-mint.nat#44,008,199tapdmt-mint.nat#44,008,198tapdmt-mint.nat#44,008,197tapdmt-mint.nat#44,008,196tapdmt-mint.nat#44,008,195tapdmt-mint.nat#44,008,194tapdmt-mint.nat#44,008,192tapdmt-mint.nat#44,008,190tapdmt-mint.nat#44,008,189tapdmt-mint.nat#44,008,188tapdmt-mint.nat#44,008,187tapdmt-mint.nat#44,008,186tapdmt-mint.nat#44,008,185tapdmt-mint.nat#44,008,184tapdmt-mint.nat#44,008,183tapdmt-mint.nat#44,008,182tapdmt-mint.nat#44,008,178tapdmt-mint.nat#44,008,176tapdmt-mint.nat#44,008,175tapdmt-mint.nat#44,008,174tapdmt-mint.nat#44,008,173tapdmt-mint.nat#44,008,172tapdmt-mint.nat#44,008,171tapdmt-mint.nat#44,008,170tapdmt-mint.nat#44,008,169tapdmt-mint.nat#44,008,168tapdmt-mint.nat#44,008,165tapdmt-mint.nat#44,008,164tapdmt-mint.nat#44,008,163tapdmt-mint.nat#44,008,160tapdmt-mint.nat#44,008,159tapdmt-mint.nat#44,008,157tapdmt-mint.nat#44,008,156tapdmt-mint.nat#44,008,154tapdmt-mint.nat#44,008,153tapdmt-mint.nat#44,008,151tap