input-output-hk/cardano-js-sdk

subtractValueQuantities pass token map as reference

jmagan opened this issue · 1 comments

Summary

Hi!,

The substractTokenMap method pass the asset token map as reference. In the first line of the method, it assings position array 0 to the result constant:

export const subtractTokenMaps = (assets: (TokenMap | undefined)[]): TokenMap | undefined => {
  if (assets.length <= 0 || !isNotNil(assets[0])) return undefined;
  const result: TokenMap = assets[0];
  const rest: TokenMap[] = assets.slice(1).filter(isNotNil);
  for (const assetTotals of rest) {
    for (const [assetId, assetQuantity] of assetTotals.entries()) {
      const total = result.get(assetId) ?? 0n;
      const diff = total - assetQuantity;
      diff === 0n ? result.delete(assetId) : result.set(assetId, diff);
    }
  }
  if (result.size === 0) {
    return undefined;
  }
  return result;
};

That produces changes in the first position of the value array passed to subtractValueQuantities, as I show in the example. I would suggest to create a copy of the object instead of pass it as reference.

Thanks.

Steps to reproduce the bug

  1. This script shows the test case:
import { Cardano } from '@cardano-sdk/core';

const cardanoAsset: Cardano.AssetId = Cardano.AssetId('01234567890123456789012345678901234567890123456789012345678901234567890123456789');

// First value with 10 ADA and 10 tokens
const tokenMap1: Cardano.TokenMap = new Map([[cardanoAsset, 10n]]);
const value1: Cardano.Value = { coins: 10000000n, assets: tokenMap1 };

console.log(`Value 1 before subtraction: ${Number(value1.coins) / (10 ** 6)} ADA and ${value1.assets!.get(cardanoAsset)!.toString()} Token`);

// Second value with 5 ADA and 5 tokens
const tokenMap2: Cardano.TokenMap = new Map([[cardanoAsset, 5n]]);
const value2: Cardano.Value = { coins: 5000000n, assets: tokenMap2 };

// Substract value 2 to value 1
const result = Cardano.util.subtractValueQuantities([value1, value2]);

console.log(`Value 1 after subtraction: ${Number(value1.coins) / (10 ** 6)} ADA and ${value1.assets!.get(cardanoAsset)!.toString()} Token`);
console.log(`Result value: ${Number(result.coins) / (10 ** 6)} ADA and ${result.assets!.get(cardanoAsset)!.toString()} Token`);

Actual Result

The script out put is:

Value 1 before subtraction: 10 ADA and 10 Token
Value 1 after subtraction: 10 ADA and 5 Token
Result value: 5 ADA and 5 Token

Expected Result

My expected result is:

Value 1 before subtraction: 10 ADA and 10 Token
Value 1 after subtraction: 10 ADA and 10 Token
Result value: 5 ADA and 5 Token

SDK version

0.5.0

Environment type

  • Node.js
  • Browser
  • Browser Extension
  • Other

Environment details

v14.20.0

Thanks for raising this issue @jmagan. We're open for contributions, either as a complete fix or just a failing test in this suite, so feel free to submit a PR to be recognised for your work here 🙂