createVTTransaction function
Future
createVTTransaction({
- required List<
ValueTransferOutput> outputs, - required WitPrivateKey privateKey,
- Address? changeAddress,
- required dynamic networkSource,
- required UtxoSelectionStrategy utxoStrategy,
- FeeType? feeType,
- int fee = 0,
- String? metadata,
Implementation
Future<dynamic> createVTTransaction({
required List<ValueTransferOutput> outputs,
required WitPrivateKey privateKey,
Address? changeAddress,
required dynamic networkSource,
required UtxoSelectionStrategy utxoStrategy,
FeeType? feeType,
int fee = 0,
String? metadata,
}) async {
List<ValueTransferOutput> allOutputs = outputs;
if (metadata != null) {
allOutputs.add(createMetadataOutput(metadata));
}
int outputValue = 0;
int totalUtxoValue = 0;
int selectedUtxoValue = 0;
allOutputs.forEach((ValueTransferOutput output) {
outputValue += output.value.toInt();
});
Address signerAddress = Address.fromAddress(privateKey.publicKey.address);
// if the changeAddress param is left blank send the change to the signer
Address _changeAddress = changeAddress ?? signerAddress;
await signerAddress.getUtxoInfo(source: networkSource);
List<Input> inputs = [];
List<Utxo> utxoPool = signerAddress.utxoPool!.sortUtxos(utxoStrategy);
utxoPool.forEach((utxo) {
totalUtxoValue += utxo.value;
});
if (totalUtxoValue < outputValue) {
return TransactionError(-1, 'Insufficient funds.');
}
List<Utxo> selectedUtxos = [];
var _outputValue = outputValue;
while (_outputValue > 0) {
Utxo utxo = utxoPool.first;
utxoPool.removeAt(0);
selectedUtxos.add(utxo);
_outputValue -= utxo.value;
}
selectedUtxos.forEach((Utxo utxo) {
inputs.add(utxo.toInput());
print('${utxo.toInput().outputPointer.jsonMap(asHex: true)} ${utxo.value}');
selectedUtxoValue += utxo.value;
});
print(selectedUtxoValue);
int change = selectedUtxoValue - outputValue;
if (change > 0) {
// receive the change to this address
FeeType absFee = FeeType.Absolute;
// if feeType is null use Absolute fee
switch (feeType ?? absFee) {
case FeeType.Absolute:
if (change > fee) {
allOutputs.add(_changeAddress.receive(change - fee));
} else if (change == fee) {
// do nothing with the change since it is the fee.
} else {
// get additional utxos to cover the fee
while (fee > change) {
Utxo nextUtxo = utxoPool.first;
utxoPool.removeAt(0);
selectedUtxos.add(nextUtxo);
inputs.add(nextUtxo.toInput());
selectedUtxoValue += nextUtxo.value;
change = selectedUtxoValue - outputValue;
}
}
break;
case FeeType.Weighted:
print('Current Change: $change');
var inputCount = inputs.length;
var outputCount = allOutputs.length;
var currentWeight = vttWeight(inputCount, outputCount);
print('Inputs: $inputCount, Outputs: $outputCount');
print('Current Weight -> $currentWeight');
if (change == currentWeight) {
// do nothing with the change since it is the currentWeight
} else if (change > currentWeight) {
// account for the weight of an additional output for the change
int newWeight = vttWeight(inputCount, outputCount + 1);
// is the new weight greater than the change?
if (newWeight > change) {
// need additional utxos to cover the weighted fee
while (newWeight > change) {
Utxo nextUtxo = utxoPool.first;
utxoPool.removeAt(0);
inputs.add(nextUtxo.toInput());
selectedUtxoValue += nextUtxo.value;
change = selectedUtxoValue - outputValue;
newWeight = vttWeight(inputs.length, outputCount + 1);
}
}
allOutputs.add(_changeAddress.receive(change - newWeight));
} else {
// need additional utxos to cover the weighted fee
}
break;
}
}
VTTransactionBody body =
VTTransactionBody(inputs: inputs, outputs: allOutputs);
VTTransaction transaction = VTTransaction(body: body, signatures: []);
KeyedSignature signature =
signerAddress.signHash(transaction.transactionID, privateKey);
for (int i = 0; i < transaction.body.inputs.length; i++) {
transaction.signatures.add(signature);
}
return transaction;
}