Skip to content

Commit

Permalink
fix: prepare collateral correctly consider min utxo requirements (#198)
Browse files Browse the repository at this point in the history
  • Loading branch information
joacohoyos authored Nov 5, 2024
1 parent 84ba27b commit 97ca0f6
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/fast-dryers-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blaze-cardano/tx": patch
---

correctly consider min utxo requirements when preparing collateral
44 changes: 26 additions & 18 deletions packages/blaze-tx/src/tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1260,12 +1260,7 @@ export class TxBuilder {
// if there are provided collateral UTxOs, use them first
if (providedCollateral.length > 0) {
for (const utxo of providedCollateral) {
const hasMultiAsset = utxo.output().amount().multiasset() != undefined;
const output = utxo.output();
const outputMinAda = this.calculateMinAda(output);
const coinAmount = hasMultiAsset
? output.amount().coin() - outputMinAda
: utxo.output().amount().coin();
const coinAmount = this.getUtxoEffectiveCoin(utxo);
if (
coinAmount >= 5_000_000 &&
utxo.output().address().getProps().paymentPart?.type ==
Expand All @@ -1289,13 +1284,7 @@ export class TxBuilder {

if (utxo) {
// Check if the UTXO amount is sufficient for collateral.
const hasMultiAsset =
utxo.output().amount().multiasset() != undefined;
const output = utxo.output();
const outputMinAda = this.calculateMinAda(output);
const coinAmount = hasMultiAsset
? output.amount().coin() - outputMinAda
: utxo.output().amount().coin();
const coinAmount = this.getUtxoEffectiveCoin(utxo);
if (
coinAmount >= 5_000_000 &&
utxo.output().address().getProps().paymentPart?.type ==
Expand All @@ -1316,8 +1305,9 @@ export class TxBuilder {
// If there is no best fit still, iterate over all UTXOs to find the best candidate.
if (!best) {
for (const utxo of this.utxos.values()) {
const coinAmount = this.getUtxoEffectiveCoin(utxo);
if (
utxo.output().amount().coin() >= 5_000_000n &&
coinAmount >= 5_000_000n &&
utxo.output().address().getProps().paymentPart?.type ==
CredentialType.KeyHash
) {
Expand Down Expand Up @@ -1351,15 +1341,17 @@ export class TxBuilder {
// If we still haven't reached the necessary collateral amount, try to use any available UTxO
if (adaAmount < 5_000_000n) {
// create a sorted list of utxos by ada amount
const adaUtxos = [...this.utxos.values()].sort((a, b) =>
a.output().amount().coin() < b.output().amount().coin() ? -1 : 1,
);
const adaUtxos = [...this.utxos.values()].sort((a, b) => {
const aCoinAmount = this.getUtxoEffectiveCoin(a);
const bCoinAmount = this.getUtxoEffectiveCoin(b);
return aCoinAmount < bCoinAmount ? -1 : 1;
});
for (
let i = 0;
i < Math.min(this.params.maxCollateralInputs, adaUtxos.length);
i++
) {
adaAmount += adaUtxos[i]!.output().amount().coin();
adaAmount += this.getUtxoEffectiveCoin(adaUtxos[i]!);
collateral.push(adaUtxos[i]!);
if (adaAmount >= 5_000_000n) {
break;
Expand Down Expand Up @@ -1398,6 +1390,22 @@ export class TxBuilder {
this.body.setCollateralReturn(ret);
}

/**
* Returns the effective coin value of the utxo substracting the min utxo needed for the multiasset in the utxo
*
* @param {TransactionUnspentOutput} utxo - The utxo to calculate the effective coin value
* @returns {bigint} The effective coin value of the utxo
* */
private getUtxoEffectiveCoin(utxo: TransactionUnspentOutput): bigint {
const output = utxo.output();
const multiasset = output.amount().multiasset();
const hasMultiasset = multiasset && multiasset.size > 0;
const outputMinAda = this.calculateMinAda(output);
return hasMultiasset
? output.amount().coin() - outputMinAda
: output.amount().coin();
}

/**
* Adjusts the balance of the transaction by creating or updating a change output.
* This method takes only the native assets from excess value from the transaction, removes any zero-valued
Expand Down

0 comments on commit 97ca0f6

Please sign in to comment.