diff --git a/README.md b/README.md
index 46fb3528..5c439f9a 100644
--- a/README.md
+++ b/README.md
@@ -73,18 +73,9 @@ To incentivize development and reward contributors, we adopt a simple bounty sys
To bring Haveno to life, we need resources. If you have the possibility, please consider [becoming a sponsor](https://haveno.exchange/sponsors/) or donating to the project:
-### Monero
-
42sjokkT9FmiWPqVzrWPFE5NCJXwt96bkBozHf4vgLR9hXyJDqKHEHKVscAARuD7in5wV1meEcSTJTanCTDzidTe2cFXS1F
If you are using a wallet that supports OpenAlias (like the 'official' CLI and GUI wallets), you can simply put `fund@haveno.exchange` as the "receiver" address.
-
-### Bitcoin
-
-
-
- 1AKq3CE1yBAnxGmHXbNFfNYStcByNDc5gQ
-
diff --git a/build.gradle b/build.gradle
index 617ee2bd..67a6a60f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -610,7 +610,7 @@ configure(project(':desktop')) {
apply plugin: 'com.github.johnrengelman.shadow'
apply from: 'package/package.gradle'
- version = '1.0.16-SNAPSHOT'
+ version = '1.0.17-SNAPSHOT'
jar.manifest.attributes(
"Implementation-Title": project.name,
diff --git a/common/src/main/java/haveno/common/app/Version.java b/common/src/main/java/haveno/common/app/Version.java
index 4bad358e..8f2c2e13 100644
--- a/common/src/main/java/haveno/common/app/Version.java
+++ b/common/src/main/java/haveno/common/app/Version.java
@@ -28,7 +28,7 @@ import static com.google.common.base.Preconditions.checkArgument;
public class Version {
// The application versions
// We use semantic versioning with major, minor and patch
- public static final String VERSION = "1.0.16";
+ public static final String VERSION = "1.0.17";
/**
* Holds a list of the tagged resource files for optimizing the getData requests.
diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java
index 25aebaec..b7cb7255 100644
--- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java
+++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java
@@ -115,7 +115,6 @@ import lombok.Getter;
import monero.common.MoneroRpcConnection;
import monero.daemon.model.MoneroKeyImageSpentStatus;
import monero.daemon.model.MoneroTx;
-import monero.wallet.model.MoneroIncomingTransfer;
import monero.wallet.model.MoneroOutputQuery;
import monero.wallet.model.MoneroOutputWallet;
import monero.wallet.model.MoneroTransferQuery;
@@ -1159,23 +1158,17 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
private void scheduleWithEarliestTxs(List openOffers, OpenOffer openOffer) {
- // check for sufficient balance - scheduled offers amount
- BigInteger offerReserveAmount = openOffer.getOffer().getAmountNeeded();
- if (xmrWalletService.getBalance().subtract(getScheduledAmount(openOffers)).compareTo(offerReserveAmount) < 0) {
- throw new RuntimeException("Not enough money in Haveno wallet");
- }
-
// get earliest available or pending txs with sufficient spendable amount
+ BigInteger offerReserveAmount = openOffer.getOffer().getAmountNeeded();
BigInteger scheduledAmount = BigInteger.ZERO;
Set scheduledTxs = new HashSet();
for (MoneroTxWallet tx : xmrWalletService.getTxs()) {
- // get spendable amount
- BigInteger spendableAmount = getSpendableAmount(tx);
+ // get unscheduled spendable amount
+ BigInteger spendableAmount = getUnscheduledSpendableAmount(tx, openOffers);
- // skip if no spendable amount or already scheduled
+ // skip if no spendable amount
if (spendableAmount.equals(BigInteger.ZERO)) continue;
- if (isTxScheduledByOtherOffer(openOffers, openOffer, tx.getHash())) continue;
// schedule tx
scheduledAmount = scheduledAmount.add(spendableAmount);
@@ -1184,7 +1177,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
// break if sufficient funds
if (scheduledAmount.compareTo(offerReserveAmount) >= 0) break;
}
- if (scheduledAmount.compareTo(offerReserveAmount) < 0) throw new RuntimeException("Not enough funds to schedule offer");
+ if (scheduledAmount.compareTo(offerReserveAmount) < 0) throw new RuntimeException("Not enough funds to create offer");
// schedule txs
openOffer.setScheduledTxHashes(scheduledTxs.stream().map(tx -> tx.getHash()).collect(Collectors.toList()));
@@ -1192,6 +1185,30 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
openOffer.setState(OpenOffer.State.PENDING);
}
+ private BigInteger getUnscheduledSpendableAmount(MoneroTxWallet tx, List openOffers) {
+ if (isScheduledWithUnknownAmount(tx, openOffers)) return BigInteger.ZERO;
+ return getSpendableAmount(tx).subtract(getSplitAmount(tx, openOffers)).max(BigInteger.ZERO);
+ }
+
+ private boolean isScheduledWithUnknownAmount(MoneroTxWallet tx, List openOffers) {
+ for (OpenOffer openOffer : openOffers) {
+ if (openOffer.getScheduledTxHashes() == null) continue;
+ if (openOffer.getScheduledTxHashes().contains(tx.getHash()) && !tx.getHash().equals(openOffer.getSplitOutputTxHash())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private BigInteger getSplitAmount(MoneroTxWallet tx, List openOffers) {
+ for (OpenOffer openOffer : openOffers) {
+ if (openOffer.getSplitOutputTxHash() == null) continue;
+ if (!openOffer.getSplitOutputTxHash().equals(tx.getHash())) continue;
+ return openOffer.getOffer().getAmountNeeded();
+ }
+ return BigInteger.ZERO;
+ }
+
private BigInteger getSpendableAmount(MoneroTxWallet tx) {
// compute spendable amount from outputs if confirmed
@@ -1220,23 +1237,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
return getSpendableAmount(tx).compareTo(BigInteger.ZERO) > 0;
}
- private BigInteger getScheduledAmount(List openOffers) {
- BigInteger scheduledAmount = BigInteger.ZERO;
- for (OpenOffer openOffer : openOffers) {
- if (openOffer.getState() != OpenOffer.State.PENDING) continue;
- if (openOffer.getScheduledTxHashes() == null) continue;
- List fundingTxs = xmrWalletService.getTxs(openOffer.getScheduledTxHashes());
- for (MoneroTxWallet fundingTx : fundingTxs) {
- if (fundingTx.getIncomingTransfers() != null) {
- for (MoneroIncomingTransfer transfer : fundingTx.getIncomingTransfers()) {
- if (transfer.getAccountIndex() == 0) scheduledAmount = scheduledAmount.add(transfer.getAmount());
- }
- }
- }
- }
- return scheduledAmount;
- }
-
private boolean isTxScheduledByOtherOffer(List openOffers, OpenOffer openOffer, String txHash) {
for (OpenOffer otherOffer : openOffers) {
if (otherOffer == openOffer) continue;
diff --git a/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml b/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml
index e4544f48..6e4605f4 100644
--- a/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml
+++ b/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml
@@ -60,6 +60,6 @@
-
+
diff --git a/desktop/package/macosx/Info.plist b/desktop/package/macosx/Info.plist
index 1cd1baf9..88fa1537 100644
--- a/desktop/package/macosx/Info.plist
+++ b/desktop/package/macosx/Info.plist
@@ -5,10 +5,10 @@
CFBundleVersion
- 1.0.16
+ 1.0.17
CFBundleShortVersionString
- 1.0.16
+ 1.0.17
CFBundleExecutable
Haveno
diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.fxml b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.fxml
index 7c5da978..24d8f121 100644
--- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.fxml
+++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.fxml
@@ -38,8 +38,8 @@
+
-
diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.java
index 9544f507..b8827822 100644
--- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.java
+++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.java
@@ -70,7 +70,7 @@ public class TransactionsView extends ActivatableView {
@FXML
TableView tableView;
@FXML
- TableColumn dateColumn, detailsColumn, addressColumn, transactionColumn, amountColumn, txFeeColumn, memoColumn, confidenceColumn, revertTxColumn;
+ TableColumn dateColumn, detailsColumn, addressColumn, transactionColumn, amountColumn, txFeeColumn, confidenceColumn, memoColumn, revertTxColumn;
@FXML
Label numItems;
@FXML
@@ -133,8 +133,8 @@ public class TransactionsView extends ActivatableView {
transactionColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txId", Res.getBaseCurrencyCode())));
amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountWithCur", Res.getBaseCurrencyCode())));
txFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txFee", Res.getBaseCurrencyCode())));
- memoColumn.setGraphic(new AutoTooltipLabel(Res.get("funds.tx.memo")));
confidenceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.confirmations", Res.getBaseCurrencyCode())));
+ memoColumn.setGraphic(new AutoTooltipLabel(Res.get("funds.tx.memo")));
revertTxColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.revert", Res.getBaseCurrencyCode())));
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN);
@@ -146,8 +146,8 @@ public class TransactionsView extends ActivatableView {
setTransactionColumnCellFactory();
setAmountColumnCellFactory();
setTxFeeColumnCellFactory();
- setMemoColumnCellFactory();
setConfidenceColumnCellFactory();
+ setMemoColumnCellFactory();
setRevertTxColumnCellFactory();
dateColumn.setComparator(Comparator.comparing(TransactionsListItem::getDate));
@@ -221,8 +221,8 @@ public class TransactionsView extends ActivatableView {
columns[3] = item.getTxId();
columns[4] = item.getAmountStr();
columns[5] = item.getTxFeeStr();
- columns[6] = item.getMemo() == null ? "" : item.getMemo();
- columns[7] = String.valueOf(item.getNumConfirmations());
+ columns[6] = String.valueOf(item.getNumConfirmations());
+ columns[7] = item.getMemo() == null ? "" : item.getMemo();
return columns;
};
diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java
index 8ededde3..d92a0322 100644
--- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java
+++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java
@@ -56,6 +56,7 @@ import haveno.core.util.coin.CoinUtil;
import haveno.core.util.validation.AmountValidator4Decimals;
import haveno.core.util.validation.AmountValidator8Decimals;
import haveno.core.util.validation.InputValidator;
+import haveno.core.util.validation.InputValidator.ValidationResult;
import haveno.core.util.validation.MonetaryValidator;
import haveno.core.xmr.wallet.Restrictions;
import haveno.desktop.Navigation;
@@ -490,6 +491,8 @@ public abstract class MutableOfferViewModel ext
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()));
if (amount.get() != null) amountValidationResult.set(isXmrInputValid(amount.get()));
updateSecurityDeposit();
+ setSecurityDepositToModel();
+ onFocusOutSecurityDepositTextField(true, false); // refresh security deposit field
applyMakerFee();
dataModel.calculateTotalToPay();
updateButtonDisableState();
@@ -769,7 +772,8 @@ public abstract class MutableOfferViewModel ext
}
}
}
- // We want to trigger a recalculation of the volume
+
+ // trigger recalculation of the volume
UserThread.execute(() -> {
onFocusOutVolumeTextField(true, false);
onFocusOutMinAmountTextField(true, false);
@@ -815,6 +819,11 @@ public abstract class MutableOfferViewModel ext
}
maybeShowMakeOfferToUnsignedAccountWarning();
+
+ // trigger recalculation of the security deposit
+ UserThread.execute(() -> {
+ onFocusOutSecurityDepositTextField(true, false);
+ });
}
}
@@ -944,11 +953,16 @@ public abstract class MutableOfferViewModel ext
if (marketPriceMargin.get() == null && amount.get() != null && volume.get() != null) {
updateMarketPriceToManual();
}
+
+ // trigger recalculation of security deposit
+ UserThread.execute(() -> {
+ onFocusOutSecurityDepositTextField(true, false);
+ });
}
}
void onFocusOutSecurityDepositTextField(boolean oldValue, boolean newValue) {
- if (oldValue && !newValue) {
+ if (oldValue && !newValue && !isMinSecurityDeposit.get()) {
InputValidator.ValidationResult result = securityDepositValidator.validate(securityDeposit.get());
securityDepositValidationResult.set(result);
if (result.isValid) {
@@ -1040,6 +1054,7 @@ public abstract class MutableOfferViewModel ext
public String getSecurityDepositLabel() {
return dataModel.buyerAsTakerWithoutDeposit.get() && dataModel.isSellOffer() ? Res.get("createOffer.myDeposit") :
+ dataModel.isMinSecurityDeposit() ? Res.get("createOffer.minSecurityDepositUsed") :
Preferences.USE_SYMMETRIC_SECURITY_DEPOSIT ? Res.get("createOffer.setDepositForBothTraders") :
dataModel.isBuyOffer() ? Res.get("createOffer.setDepositAsBuyer") : Res.get("createOffer.setDeposit");
}
@@ -1211,7 +1226,7 @@ public abstract class MutableOfferViewModel ext
}
private void setSecurityDepositToModel() {
- if (!(dataModel.buyerAsTakerWithoutDeposit.get() && dataModel.isSellOffer()) && securityDeposit.get() != null && !securityDeposit.get().isEmpty()) {
+ if (securityDeposit.get() != null && !securityDeposit.get().isEmpty() && !isMinSecurityDeposit.get()) {
dataModel.setSecurityDepositPct(ParsingUtils.parsePercentStringToDouble(securityDeposit.get()));
} else {
dataModel.setSecurityDepositPct(Restrictions.getDefaultSecurityDepositAsPercent());
@@ -1282,11 +1297,11 @@ public abstract class MutableOfferViewModel ext
private void updateSecurityDeposit() {
isMinSecurityDeposit.set(dataModel.isMinSecurityDeposit());
+ securityDepositLabel.set(getSecurityDepositLabel());
if (dataModel.isMinSecurityDeposit()) {
- securityDepositLabel.set(Res.get("createOffer.minSecurityDepositUsed"));
securityDeposit.set(HavenoUtils.formatXmr(Restrictions.getMinSecurityDeposit()));
+ securityDepositValidationResult.set(new ValidationResult(true));
} else {
- securityDepositLabel.set(getSecurityDepositLabel());
boolean hasBuyerAsTakerWithoutDeposit = dataModel.buyerAsTakerWithoutDeposit.get() && dataModel.isSellOffer();
securityDeposit.set(FormattingUtils.formatToPercent(hasBuyerAsTakerWithoutDeposit ?
Restrictions.getDefaultSecurityDepositAsPercent() : // use default percent if no deposit from buyer
diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java
index 9b357145..3bcb3cb0 100644
--- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java
+++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java
@@ -185,7 +185,7 @@ abstract public class OfferBookView() {
OfferFilterService.Result canTakeOfferResult = null;
- final ImageView iconView = new ImageView();
- final AutoTooltipButton button = new AutoTooltipButton();
-
- {
- button.setGraphic(iconView);
- button.setGraphicTextGap(10);
- button.setPrefWidth(10000);
- }
-
- final ImageView iconView2 = new ImageView();
- final AutoTooltipButton button2 = new AutoTooltipButton();
-
- {
- button2.setGraphic(iconView2);
- button2.setGraphicTextGap(10);
- button2.setPrefWidth(10000);
- }
-
- final HBox hbox = new HBox();
-
- {
- hbox.setSpacing(8);
- hbox.setAlignment(Pos.CENTER);
- hbox.getChildren().add(button);
- hbox.getChildren().add(button2);
- HBox.setHgrow(button, Priority.ALWAYS);
- HBox.setHgrow(button2, Priority.ALWAYS);
- }
-
@Override
public void updateItem(final OfferBookListItem item, boolean empty) {
super.updateItem(item, empty);
+ final ImageView iconView = new ImageView();
+ final AutoTooltipButton button = new AutoTooltipButton();
+
+ {
+ button.setGraphic(iconView);
+ button.setGraphicTextGap(10);
+ button.setPrefWidth(10000);
+ }
+
+ final ImageView iconView2 = new ImageView();
+ final AutoTooltipButton button2 = new AutoTooltipButton();
+
+ {
+ button2.setGraphic(iconView2);
+ button2.setGraphicTextGap(10);
+ button2.setPrefWidth(10000);
+ }
+
+ final HBox hbox = new HBox();
+
+ {
+ hbox.setSpacing(8);
+ hbox.setAlignment(Pos.CENTER);
+ hbox.getChildren().add(button);
+ hbox.getChildren().add(button2);
+ HBox.setHgrow(button, Priority.ALWAYS);
+ HBox.setHgrow(button2, Priority.ALWAYS);
+ }
+
TableRow tableRow = getTableRow();
if (item != null && !empty) {
Offer offer = item.getOffer();
diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java
index 55fb0946..967e29b6 100644
--- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java
+++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java
@@ -260,7 +260,10 @@ abstract class OfferBookViewModel extends ActivatableViewModel {
showAllTradeCurrenciesProperty.set(showAllEntry);
if (isEditEntry(code))
navigation.navigateTo(MainView.class, SettingsView.class, PreferencesView.class);
- else if (!showAllEntry) {
+ else if (showAllEntry) {
+ this.selectedTradeCurrency = getDefaultTradeCurrency();
+ tradeCurrencyCode.set(selectedTradeCurrency.getCode());
+ } else {
this.selectedTradeCurrency = tradeCurrency;
tradeCurrencyCode.set(code);
}
@@ -579,7 +582,10 @@ abstract class OfferBookViewModel extends ActivatableViewModel {
getCurrencyAndMethodPredicate(direction, selectedTradeCurrency).and(getOffersMatchingMyAccountsPredicate()) :
getCurrencyAndMethodPredicate(direction, selectedTradeCurrency);
- predicate = predicate.and(offerBookListItem -> offerBookListItem.getOffer().isPrivateOffer() == showPrivateOffers);
+ // filter private offers
+ if (direction == OfferDirection.BUY) {
+ predicate = predicate.and(offerBookListItem -> offerBookListItem.getOffer().isPrivateOffer() == showPrivateOffers);
+ }
if (!filterText.isEmpty()) {
diff --git a/desktop/src/main/java/haveno/desktop/theme-dark.css b/desktop/src/main/java/haveno/desktop/theme-dark.css
index 37903692..d045e3b5 100644
--- a/desktop/src/main/java/haveno/desktop/theme-dark.css
+++ b/desktop/src/main/java/haveno/desktop/theme-dark.css
@@ -561,8 +561,10 @@
.toggle-button-no-slider {
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
+ -fx-background-radius: 3;
+ -fx-background-insets: 0, 1;
}
.toggle-button-no-slider:selected {
- -fx-background-color: -bs-color-gray-ddd;
+ -fx-background-color: -bs-color-gray-bbb;
}
diff --git a/docs/create-mainnet.md b/docs/create-mainnet.md
index 38c211d4..4b220e16 100644
--- a/docs/create-mainnet.md
+++ b/docs/create-mainnet.md
@@ -118,6 +118,10 @@ The price node is separated from Haveno and is run as a standalone service. To d
After the price node is built and deployed, add the price node to `DEFAULT_NODES` in [ProvidersRepository.java](https://github.com/haveno-dex/haveno/blob/3cdd88b56915c7f8afd4f1a39e6c1197c2665d63/core/src/main/java/haveno/core/provider/ProvidersRepository.java#L50).
+### Update the download URL
+
+Change every instance of `https://haveno.exchange/downloads` to your download URL. For example, `https://havenoexample.com/downloads`.
+
## Review all local changes
For comparison, placeholders to run on mainnet are marked [here on this branch](https://github.com/haveno-dex/haveno/tree/mainnet_placeholders).
diff --git a/docs/deployment-guide.md b/docs/deployment-guide.md
index 2f7590d0..e4496fcc 100644
--- a/docs/deployment-guide.md
+++ b/docs/deployment-guide.md
@@ -243,6 +243,10 @@ Set `ARBITRATOR_ASSIGNS_TRADE_FEE_ADDRESS` to `true` for the arbitrator to assig
Otherwise set `ARBITRATOR_ASSIGNS_TRADE_FEE_ADDRESS` to `false` and set the XMR address in `getGlobalTradeFeeAddress()` to collect all trade fees to a single address (e.g. a multisig wallet shared among network administrators).
+## Update the download URL
+
+Change every instance of `https://haveno.exchange/downloads` to your download URL. For example, `https://havenoexample.com/downloads`.
+
## Start users for testing
Start user1 on Monero's mainnet using `make user1-desktop-mainnet` or Monero's stagenet using `make user1-desktop-stagenet`.
@@ -266,7 +270,7 @@ Then follow these instructions: https://github.com/haveno-dex/haveno/blob/master
Set the mandatory minimum version for trading (optional)
-If applicable, update the mandatory minimum version for trading, by entering `ctrl + f` to open the Filter window, enter a private key with developer privileges, and enter the minimum version (e.g. 1.0.16) in the field labeled "Min. version required for trading".
+If applicable, update the mandatory minimum version for trading, by entering `ctrl + f` to open the Filter window, enter a private key with developer privileges, and enter the minimum version (e.g. 1.0.17) in the field labeled "Min. version required for trading".
Send update alert
diff --git a/docs/developer-guide.md b/docs/developer-guide.md
index 337d44c6..565ee488 100644
--- a/docs/developer-guide.md
+++ b/docs/developer-guide.md
@@ -31,8 +31,8 @@ Follow [instructions](https://github.com/haveno-dex/haveno-ts#run-tests) to run
For example, the gRPC function to get offers is implemented by [`GrpcServer`](https://github.com/haveno-dex/haveno/blob/master/daemon/src/main/java/haveno/daemon/grpc/GrpcServer.java) > [`GrpcOffersService.getOffers(...)`](https://github.com/haveno-dex/haveno/blob/b761dbfd378faf49d95090c126318b419af7926b/daemon/src/main/java/haveno/daemon/grpc/GrpcOffersService.java#L104) > [`CoreApi.getOffers(...)`](https://github.com/haveno-dex/haveno/blob/b761dbfd378faf49d95090c126318b419af7926b/core/src/main/java/haveno/core/api/CoreApi.java#L128) > [`CoreOffersService.getOffers(...)`](https://github.com/haveno-dex/haveno/blob/b761dbfd378faf49d95090c126318b419af7926b/core/src/main/java/haveno/core/api/CoreOffersService.java#L126) > [`OfferBookService.getOffers()`](https://github.com/haveno-dex/haveno/blob/b761dbfd378faf49d95090c126318b419af7926b/core/src/main/java/haveno/core/offer/OfferBookService.java#L193).
5. Build Haveno: `make`
6. Update the gRPC client in haveno-ts: `npm install`
-7. Add the corresponding typescript method(s) to [haveno.ts](https://github.com/haveno-dex/haveno-ts/blob/master/src/haveno.ts) with clear and concise documentation.
-8. Add clean and comprehensive tests to [haveno.test.ts](https://github.com/haveno-dex/haveno-ts/blob/master/src/haveno.test.ts), following existing patterns.
+7. Add the corresponding typescript method(s) to [HavenoClient.ts](https://github.com/haveno-dex/haveno-ts/blob/master/src/HavenoClient.ts) with clear and concise documentation.
+8. Add clean and comprehensive tests to [HavenoClient.test.ts](https://github.com/haveno-dex/haveno-ts/blob/master/src/HavenoClient.test.ts), following existing patterns.
9. Run the tests with `npm run test -- -t 'my test'` to run tests by name and `npm test` to run all tests together. Ensure all tests pass and there are no exception stacktraces in the terminals of Alice, Bob, or the arbitrator.
10. Open pull requests to the haveno and haveno-ts projects for the backend and frontend implementations.
diff --git a/seednode/src/main/java/haveno/seednode/SeedNodeMain.java b/seednode/src/main/java/haveno/seednode/SeedNodeMain.java
index 75839255..7482cdbc 100644
--- a/seednode/src/main/java/haveno/seednode/SeedNodeMain.java
+++ b/seednode/src/main/java/haveno/seednode/SeedNodeMain.java
@@ -41,7 +41,7 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SeedNodeMain extends ExecutableForAppWithP2p {
private static final long CHECK_CONNECTION_LOSS_SEC = 30;
- private static final String VERSION = "1.0.16";
+ private static final String VERSION = "1.0.17";
private SeedNode seedNode;
private Timer checkConnectionLossTime;