Inscription #64983569#64,983,569svgdmt-mint.thebox#64,190,939tapdmt-mint.thebox#64,190,938tapInscription #59392708#59,392,708svgtoken-transfer3,000,000,000.dmt-nat#54,139,781taptoken-transfer3,291,214,118.dmt-nat#54,134,678tapInscription #54079630#54,079,630htmlInscription #54071730#54,071,730htmltransfer8,000.$bmp#52,201,244brc-20transfer50..com#45,248,025brc-20 ); } #[test] fn change_addresses_must_be_unique() { pretty_assert_eq!( TransactionBuilder::new( satpoint(1, 0), BTreeMap::new(), vec![(outpoint(1), Amount::from_sat(1000))] .into_iter() .collect(), BTreeSet::new(), recipient(), [change(0), change(0)], FeeRate::try_from(0.0).unwrap(), Target::Value(Amount::from_sat(1000)) ) .build_transaction(), Err(Error::DuplicateAddress(change(0))) ); } #[test] fn output_over_value_because_fees_prevent_excess_value_stripping() { pretty_assert_eq!( TransactionBuilder::new( satpoint(1, 0), BTreeMap::new(), vec![(outpoint(1), Amount::from_sat(2000))] .into_iter() .collect(), BTreeSet::new(), recipient(), [change(0), change(1)], FeeRate::try_from(2.0).unwrap(), Target::Value(Amount::from_sat(1500)) ) .build_transaction(), Ok(Transaction { #44,982,873text ), Error::ValueOverflow => write!(f, "arithmetic overflow calculating value"), Error::DuplicateAddress(address) => write!(f, "duplicate input address: {address}"), } } } impl std::error::Error for Error {} #[derive(Debug, PartialEq)] pub struct TransactionBuilder { amounts: BTreeMap<OutPoint, Amount>, change_addresses: BTreeSet<Address>, fee_rate: FeeRate, inputs: Vec<OutPoint>, inscriptions: BTreeMap<SatPoint, InscriptionId>, outgoing: SatPoint, outputs: Vec<(Address, Amount)>, recipient: Address, unused_change_addresses: Vec<Address>, utxos: BTreeSet<OutPoint>, locked_utxos: BTreeSet<OutPoint>, target: Target, } type Result<T> = std::result::Result<T, Error>; impl TransactionBuilder { const ADDITIONAL_INPUT_VBYTES: usize = 58; const ADDITIONAL_OUTPUT_VBYTES: usize = 43; const SCHNORR_SIGNATURE_SIZE: usize = 64; pub(crate) const TARGET_POSTAGE: Amount = Amount::from_sat(10_000); pub(crate) const MAX_POSTAGE: Amount = Amount::from_sat(2 * 10_000); #44,982,872text (outpoint(1), Amount::from_sat(3_003)), // 1. satpoint is selected 1st leaving us needing 7154 more (outpoint(5), Amount::from_sat(3_004)), (outpoint(4), Amount::from_sat(3_001)), // 4. smallest utxo >= 1259 is selected 4th, filling deficit (outpoint(3), Amount::from_sat(3_005)), // 3. next biggest utxo is selected 3rd leaving us needing 1259 more (outpoint(6), Amount::from_sat(3_002)), ]; let tx_builder = TransactionBuilder::new( satpoint(1, 0), BTreeMap::new(), utxos.clone().into_iter().collect(), BTreeSet::new(), recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Value(Amount::from_sat(10_000)), ) .select_outgoing() .unwrap() .add_value() .unwrap(); utxos.remove(4); utxos.remove(3); utxos.remove(1); utxos.remove(0); assert_eq!( tx_builder.utxos, utxos.iter().map(|(outpoint, _ranges)| *outpoint).collect() ); assert_eq!( tx_builder.inputs, #44,982,871text#44,775,230dmt-mint.nat#44,700,469tapdmt-mint.nat#44,700,468tapdmt-mint.nat#44,700,467tapdmt-mint.nat#44,700,466tapdmt-mint.nat#44,700,465tapdmt-mint.nat#44,700,464tapdmt-mint.nat#44,700,463tapdmt-mint.nat#44,700,462tapdmt-mint.nat#44,700,461tapdmt-mint.nat#44,700,460tapmint100,000,000,000.shid#42,896,543brc-20mint100,000,000,000.shid#42,896,542brc-20mint100,000,000,000.shid#42,896,541brc-20mint100,000,000,000.shid#42,896,540brc-20mint100,000,000,000.shid#42,896,539brc-20mint100,000,000,000.shid#42,896,538brc-20mint100,000,000,000.shid#42,896,537brc-20mint100,000,000,000.shid#42,896,536brc-20Inscription #42624567#42,624,567pngInscription #42460827#42,460,827pngInscription #42460821#42,460,821pngInscription #42454409#42,454,409pngmint1,000,000.rats#37,706,262brc-20mint1,000,000.rats#37,706,235brc-20mint1,000,000.rats#37,706,211brc-20mint1,000,000.rats#37,706,205brc-20mint1,000,000.rats#37,706,170brc-20mint1,000,000.rats#37,706,104brc-20mint1,000,000.rats#37,706,103brc-20Inscription #14464905#14,464,905svgInscription #13594179#13,594,179htmlInscription #13066152#13,066,152svgInscription #13021214#13,021,214svgInscription #13021145#13,021,145svgInscription #13021044#13,021,044svgInscription #13020781#13,020,781svgInscription #13020780#13,020,780svg19453.bitmap#12,249,811text1818181.bitmap#12,249,799texttransfer500.btoc#12,249,458brc-20transfer500.btoc#12,244,861brc-20transfer500.btoc#12,230,560brc-20transfer500.btoc#12,228,278brc-20transfer1.btoc#12,210,185brc-20Inscription #12204000#12,204,000svgInscription #12203985#12,203,985svg