balancedOutputsWithChange method
Result<List<ShelleyTransactionOutput> , String>
balancedOutputsWithChange({
- required ShelleyAddress changeAddress,
- required BlockchainCache cache,
- Coin fee = 0,
Balance transaction by adding/modifying change outputs to match inputs and fee. If no change adjustments are needed, returns input list. All native tokens must have a CurrencyAsset in the cache. To avoid adding multiple change outputs, changeAddress should be the same for a given tx.
Implementation
Result<List<ShelleyTransactionOutput>, String> balancedOutputsWithChange({
required ShelleyAddress changeAddress,
required BlockchainCache cache,
Coin fee = 0,
}) {
//get the differences for each native token:
final sumResult = sumCurrencyIO(cache: cache, fee: fee);
if (sumResult.isErr()) return Err(sumResult.unwrapErr());
final Map<AssetId, Coin> sums = sumResult.unwrap();
final isAllZeros = sums.values.every((sum) => sum == coinZero);
//if balanced - nothing to do - return existing list
if (isAllZeros) return Ok(this.outputs);
final targetAddress = changeAddress.toBech32();
//copy all outputs except for the change output
List<ShelleyTransactionOutput> outputs =
this.outputs.where((o) => o.address != targetAddress).toList();
//find change output if it exists
ShelleyTransactionOutput? changeOutput =
firstWhere(this.outputs, targetAddress);
//break-up assetIds into policyId and name and put in nested maps
final groupByResult = _groupByPolicyIdThenName(sums: sums, cache: cache);
if (groupByResult.isErr()) return Err(groupByResult.unwrapErr());
Map<String, Map<String, Coin>> byPolicyIdThenName = groupByResult.unwrap();
//build new change output
List<ShelleyMultiAsset> multiAssets = [];
Coin lovelace = coinZero;
for (final policyId in byPolicyIdThenName.keys) {
Map<String, Coin> byName = byPolicyIdThenName[policyId]!;
List<ShelleyAsset> assets = [];
for (final name in byName.keys) {
final Coin value = _existingBalance(
changeOutput: changeOutput, policyId: policyId, name: name);
if (policyId == '' && name == lovelaceHex) {
//special handling for lovelace
lovelace = value + (byName[name] ?? coinZero);
} else {
assets.add(ShelleyAsset(
name: name, value: value + (byName[name] ?? coinZero)));
}
}
if (assets.isNotEmpty) {
multiAssets.add(ShelleyMultiAsset(policyId: policyId, assets: assets));
}
}
final value = ShelleyValue(coin: lovelace, multiAssets: multiAssets);
outputs.add(ShelleyTransactionOutput(address: targetAddress, value: value));
return Ok(outputs);
}