Skip to content

Promise.all convert result with parameter from nested loop

The following loop to call an async function, here a smart contract interaction using web3. I want to get the balance of an array of token by calling balanceOf() and convert it subsequently with the attached usdrate. For parallel processing I am using Promise.all. Obviously, the function below Promise.all() with access [I % currency.length] does not work, since sorted result is not guaranteed.

My question is, how can I multiply the amounts with the correct usdrates attached to the tokens and still use Promise.all?

currencies = [{
    contract: token1,
    usdrate: 0.5
  },
  {
    contract: token2,
    usdrate: 1.0
  },
  {
    contract: token3,
    usdrate: 1.05
  },
  {
    contract: token4,
    usdrate: 1.10
  },
  {
    contract: token5,
    usdrate: 1.40
  },
  {
    contract: token6,
    usdrate: 1.0
  },
  {
    contract: token7,
    usdrate: 1.0
  }
];
}

async function getUsdWealthAsync(addresses) {
  var totalWealth = 0;
  var amountPromises = [];
  for (var j = 0; j < currencies.length; j++) {
    for (var i = 0; i < addresses.length; i++) {
      amountPromises.push(currencies[j].contract.methods.balanceOf(addresses[i]).call());
    }
  }
  await Promise.all(amountPromises).then(function(amounts) {
    for (var i = 0; i < amounts.length; i++) {
      amounts[i] = Number.parseInt(amounts[i]);
      totalWealth += (amounts[i] / 100) * currencies[i % currencies.length].usdrate;
    }
  })
  return totalWealth;
}

Answer

You have other great answers.

Another way could be that, you can attach the USD rate along with the result from the balanceOf in the promise itself, And then while resolving the promises, you can access the USD rate directly.

Maybe something like this:

async function getUsdWealthAsync(addresses) {
  var totalWealth = 0;
  var amountPromises = [];
  for (var j = 0; j < currencies.length; j++) {
    for (var i = 0; i < addresses.length; i++) {
      const { usdrate, contract } = currencies[j];
      amountPromises.push(
        contract.methods.balanceOf(addresses[i]).call()
          .then((amount) => ({ amount, usdrate }))
      );
    }
  }

  const amounts = await Promise.all(amountPromises);

  for (var i = 0; i < amounts.length; i++) {
    const { amount, usdrate } = amounts[i];
    amount = Number.parseInt(amount);
    totalWealth += (amount / 100) * usdrate;
  }

  return totalWealth;
}