static void exchangeCurrencyForNXT(
      Transaction transaction,
      Account account,
      final long currencyId,
      final long rateNQT,
      long units) {
    long extraAmountNQT = 0;
    long remainingUnits = units;

    List<CurrencyBuyOffer> currencyBuyOffers = new ArrayList<>();
    try (DbIterator<CurrencyBuyOffer> offers =
        CurrencyBuyOffer.getOffers(
            new ValidOffersDbClause(currencyId, rateNQT, true),
            0,
            -1,
            " ORDER BY rate DESC, creation_height ASC, transaction_height ASC, transaction_index ASC ")) {
      for (CurrencyBuyOffer offer : offers) {
        currencyBuyOffers.add(offer);
      }
    }

    for (CurrencyBuyOffer offer : currencyBuyOffers) {
      if (remainingUnits == 0) {
        break;
      }
      long curUnits = Math.min(Math.min(remainingUnits, offer.getSupply()), offer.getLimit());
      long curAmountNQT = Math.multiplyExact(curUnits, offer.getRateNQT());

      extraAmountNQT = Math.addExact(extraAmountNQT, curAmountNQT);
      remainingUnits = Math.subtractExact(remainingUnits, curUnits);

      offer.decreaseLimitAndSupply(curUnits);
      long excess = offer.getCounterOffer().increaseSupply(curUnits);

      Account counterAccount = Account.getAccount(offer.getAccountId());
      counterAccount.addToBalanceNQT(-curAmountNQT);
      counterAccount.addToCurrencyUnits(currencyId, curUnits);
      counterAccount.addToUnconfirmedCurrencyUnits(currencyId, excess);
      Exchange.addExchange(
          transaction, currencyId, offer, account.getId(), offer.getAccountId(), curUnits);
    }

    account.addToBalanceAndUnconfirmedBalanceNQT(extraAmountNQT);
    account.addToCurrencyUnits(currencyId, -(units - remainingUnits));
    account.addToUnconfirmedCurrencyUnits(currencyId, remainingUnits);
  }