diff --git a/CHANGELOG.MD b/CHANGELOG.MD
index 08f877a..cea4000 100644
--- a/CHANGELOG.MD
+++ b/CHANGELOG.MD
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+### Fixed
+
+- UTXO_BALANCE_INSUFFICIENT while using `setMax` on ADA output
+
## [2.2.0] - 2023-10-06
### Added
diff --git a/docs/badge-coverage.svg b/docs/badge-coverage.svg
index 0a652fa..3db4cbb 100644
--- a/docs/badge-coverage.svg
+++ b/docs/badge-coverage.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/methods/largestFirst.ts b/src/methods/largestFirst.ts
index 935f73f..fbef466 100644
--- a/src/methods/largestFirst.ts
+++ b/src/methods/largestFirst.ts
@@ -123,7 +123,8 @@ export const largestFirst = (
let forceAnotherRound = false;
while (!sufficientUtxos) {
if (maxOutput) {
- // reset previously computed maxOutput in order to correctly calculate a potential change output
+ // Reset previously computed maxOutput in order to correctly calculate a potential change output
+ // when new utxo is added to the set
preparedOutputs[maxOutputIndex] = setMinUtxoValueForOutputs(
txBuilder,
[maxOutput],
@@ -145,6 +146,7 @@ export const largestFirst = (
if (maxOutput) {
// set amount for a max output from a changeOutput calculated above
const { maxOutput: newMaxOutput } = setMaxOutput(
+ txBuilder,
maxOutput,
singleChangeOutput,
);
diff --git a/src/utils/common.ts b/src/utils/common.ts
index c7dd5b4..834037f 100644
--- a/src/utils/common.ts
+++ b/src/utils/common.ts
@@ -633,6 +633,7 @@ export const getInitialUtxoSet = (
};
export const setMaxOutput = (
+ txBuilder: CardanoWasm.TransactionBuilder,
maxOutput: UserOutput,
changeOutput: OutputCost | null,
): {
@@ -648,17 +649,28 @@ export const setMaxOutput = (
if (maxOutputAsset === 'lovelace') {
// set maxOutput for ADA
if (changeOutput) {
+ // Calculate the cost of previous dummy set-max output
+ const previousMaxOutputCost = getOutputCost(
+ txBuilder,
+ maxOutput,
+ maxOutput.address ?? changeOutput.output.address().to_bech32(),
+ );
newMaxAmount = changeOutput.output.amount().coin();
+
if (changeOutputAssets.length === 0) {
- // we don't need the change output anymore
- newMaxAmount = newMaxAmount.checked_add(changeOutput.outputFee);
+ // Add a fee that was previously consumed by the dummy max output.
+ // Cost calculated for the change output will be greater (due to larger coin amount
+ // than in dummy output - which is 0) than the cost of the dummy set-max output.
+ newMaxAmount = newMaxAmount.checked_add(
+ previousMaxOutputCost.outputFee,
+ );
changeOutput = null;
} else {
newMaxAmount = newMaxAmount.clamped_sub(changeOutput.minOutputAmount);
const txOutput = CardanoWasm.TransactionOutput.new(
changeOutput.output.address(),
- CardanoWasm.Value.new(newMaxAmount), // TODO: 0 before
+ CardanoWasm.Value.new(newMaxAmount),
);
const minUtxoVal = CardanoWasm.min_ada_for_output(
txOutput,
diff --git a/tests/fixtures/constants.ts b/tests/fixtures/constants.ts
index ed828e6..8226409 100644
--- a/tests/fixtures/constants.ts
+++ b/tests/fixtures/constants.ts
@@ -130,3 +130,102 @@ export const utxo8 = Object.freeze({
],
}),
});
+
+export const setMaxAdaInputs = [
+ {
+ address:
+ 'addr_test1qzq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsu8d9w5',
+ txHash: 'd6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c',
+ outputIndex: 2,
+ amount: [
+ {
+ quantity: '2611207363',
+ unit: 'lovelace',
+ },
+ ],
+ },
+ {
+ address:
+ 'addr_test1qzq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsu8d9w5',
+ txHash: 'd6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c',
+ outputIndex: 5,
+ amount: [
+ {
+ quantity: '1305603682',
+ unit: 'lovelace',
+ },
+ ],
+ },
+ {
+ address:
+ 'addr_test1qzq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsu8d9w5',
+ txHash: 'd6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c',
+ outputIndex: 8,
+ amount: [
+ {
+ quantity: '652801841',
+ unit: 'lovelace',
+ },
+ ],
+ },
+ {
+ address:
+ 'addr_test1qzq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsu8d9w5',
+ txHash: 'd6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c',
+ outputIndex: 11,
+ amount: [
+ {
+ quantity: '326400920',
+ unit: 'lovelace',
+ },
+ ],
+ },
+ {
+ address:
+ 'addr_test1qzq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsu8d9w5',
+ txHash: 'd6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c',
+ outputIndex: 14,
+ amount: [
+ {
+ quantity: '163200460',
+ unit: 'lovelace',
+ },
+ ],
+ },
+ {
+ address:
+ 'addr_test1qzq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsu8d9w5',
+ txHash: 'd6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c',
+ outputIndex: 17,
+ amount: [
+ {
+ quantity: '81600230',
+ unit: 'lovelace',
+ },
+ ],
+ },
+ {
+ address:
+ 'addr_test1qzq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsu8d9w5',
+ txHash: 'd6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c',
+ outputIndex: 21,
+ amount: [
+ {
+ quantity: '40800115',
+ unit: 'lovelace',
+ },
+ ],
+ },
+ {
+ address:
+ 'addr_test1qzq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsu8d9w5',
+ txHash: 'd6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c',
+ outputIndex: 22,
+ amount: [
+ {
+ quantity: '40800115',
+ unit: 'lovelace',
+ },
+ ],
+ },
+];
diff --git a/tests/methods/fixtures/largestFirst.ts b/tests/methods/fixtures/largestFirst.ts
index e732523..26fa547 100644
--- a/tests/methods/fixtures/largestFirst.ts
+++ b/tests/methods/fixtures/largestFirst.ts
@@ -1,6 +1,7 @@
import { Certificate } from '../../../src/types/types';
import {
changeAddress,
+ setMaxAdaInputs,
utxo1,
utxo2,
utxo3,
@@ -118,6 +119,44 @@ export const nonFinalCompose = [
];
export const coinSelection = [
+ {
+ description: 'send max ada only utxos',
+ utxos: setMaxAdaInputs,
+ outputs: [
+ {
+ address:
+ 'addr_test1qr9tax9jxzt05y65m8xanngng36mh7hpf23jy53xwyd9y5qj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfms0kcepv',
+ amount: undefined,
+ assets: [],
+ setMax: true,
+ },
+ ],
+ changeAddress: changeAddress,
+ certificates: [],
+ withdrawals: [],
+ accountPubKey:
+ 'd507c8f866691bd96e131334c355188b1a1d0b2fa0ab11545075aab332d77d9eb19657ad13ee581b56b0f8d744d66ca356b93d42fe176b3de007d53e9c4c4e7a',
+ ttl: 66578367,
+ options: {},
+ result: {
+ totalSpent: '5222414726',
+ fee: '176721',
+ tx: {
+ body: 'a40088825820d6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c02825820d6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c05825820d6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c08825820d6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c0b825820d6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c0e825820d6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c11825820d6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c15825820d6de3f33c3b421167eb1726c48129990ec16512dd829ad2239751ba49773b30c16018182583900cabe98b23096fa1354d9cdd9cd134475bbfae14aa3225226711a5250122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771b0000000137450735021a0002b251031a03f7e7bf',
+ hash: '74a66a069530d96224b56d955eb1e58dde84774168f3d1fb4b5a972431cc18fa',
+ size: 481,
+ },
+ inputs: setMaxAdaInputs,
+ outputs: [
+ {
+ address:
+ 'addr_test1qr9tax9jxzt05y65m8xanngng36mh7hpf23jy53xwyd9y5qj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfms0kcepv',
+ amount: '5222238005',
+ assets: [],
+ },
+ ],
+ },
+ },
{
description: 'send max sundae',
utxos: [