Skip to content

Commit 8a22e31

Browse files
committed
feat: add prepareOrdinalSend to ordinals interface
w a single input send-all
1 parent dceae42 commit 8a22e31

1 file changed

Lines changed: 75 additions & 0 deletions

File tree

lib/wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import 'package:isar_community/isar.dart';
22

33
import '../../../dto/ordinals/inscription_data.dart';
4+
import '../../../models/input.dart';
5+
import '../../../models/isar/models/blockchain_data/address.dart';
6+
import '../../../models/isar/models/blockchain_data/utxo.dart';
47
import '../../../models/isar/ordinal.dart';
58
import '../../../services/ord_api.dart';
9+
import '../../../utilities/amount/amount.dart';
10+
import '../../../utilities/enums/fee_rate_type_enum.dart';
611
import '../../../utilities/logger.dart';
712
import '../../crypto_currency/interfaces/electrumx_currency_interface.dart';
13+
import '../../models/tx_data.dart';
814
import 'electrumx_interface.dart';
915

1016
mixin OrdinalsInterface<T extends ElectrumXCurrencyInterface>
@@ -86,6 +92,75 @@ mixin OrdinalsInterface<T extends ElectrumXCurrencyInterface>
8692
}
8793
}
8894

95+
/// Build a transaction that sends the ordinal UTXO to [recipientAddress].
96+
///
97+
/// Uses coin-control send-all from the single ordinal UTXO so the ordinal
98+
/// (at input offset 0) lands on the only output (the recipient) via FIFO.
99+
/// If the UTXO value can't cover the fee, an exception is thrown.
100+
Future<TxData> prepareOrdinalSend({
101+
required UTXO ordinalUtxo,
102+
required String recipientAddress,
103+
FeeRateType feeRateType = FeeRateType.average,
104+
}) async {
105+
// Temporarily unblock so coinSelection accepts it.
106+
final wasBlocked = ordinalUtxo.isBlocked;
107+
// utxoForTx is the in-memory object passed to coinSelection; it must have
108+
// isBlocked=false or the spendable-outputs filter will reject it.
109+
UTXO utxoForTx = ordinalUtxo;
110+
if (wasBlocked) {
111+
final unblocked = ordinalUtxo.copyWith(
112+
isBlocked: false,
113+
blockedReason: null,
114+
);
115+
unblocked.id = ordinalUtxo.id;
116+
await mainDB.putUTXO(unblocked);
117+
utxoForTx = unblocked;
118+
}
119+
120+
try {
121+
final utxoValue = Amount(
122+
rawValue: BigInt.from(ordinalUtxo.value),
123+
fractionDigits: cryptoCurrency.fractionDigits,
124+
);
125+
126+
final txData = TxData(
127+
feeRateType: feeRateType,
128+
recipients: [
129+
TxRecipient(
130+
address: recipientAddress,
131+
amount: utxoValue,
132+
isChange: false,
133+
addressType: cryptoCurrency.getAddressType(recipientAddress) ??
134+
AddressType.unknown,
135+
),
136+
],
137+
utxos: {StandardInput(utxoForTx)},
138+
ignoreCachedBalanceChecks: true,
139+
note: "Send ordinal #${(await mainDB.isar.ordinals
140+
.where()
141+
.filter()
142+
.walletIdEqualTo(walletId)
143+
.and()
144+
.utxoTXIDEqualTo(ordinalUtxo.txid)
145+
.and()
146+
.utxoVOUTEqualTo(ordinalUtxo.vout)
147+
.findFirst())?.inscriptionNumber ?? "unknown"}",
148+
);
149+
150+
return await prepareSend(txData: txData);
151+
} finally {
152+
// Re-block regardless of success or failure.
153+
if (wasBlocked) {
154+
final reblocked = ordinalUtxo.copyWith(
155+
isBlocked: true,
156+
blockedReason: "Ordinal",
157+
);
158+
reblocked.id = ordinalUtxo.id;
159+
await mainDB.putUTXO(reblocked);
160+
}
161+
}
162+
}
163+
89164
// =================== Overrides =============================================
90165

91166
@override

0 commit comments

Comments
 (0)