Merge branch 'master' of github.com:bisq-network/bisq into release/v1.1.6

# Conflicts:
#	core/src/main/java/bisq/core/offer/OfferUtil.java
#	core/src/main/resources/i18n/displayStrings.properties
#	desktop/src/main/java/bisq/desktop/main/MainView.java
#	desktop/src/main/java/bisq/desktop/main/MainViewModel.java
#	desktop/src/main/java/bisq/desktop/main/market/trades/TradesChartsViewModel.java
#	desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java
#	desktop/src/main/java/bisq/desktop/main/overlays/windows/DisputeSummaryWindow.java
#	desktop/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java
#	desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersViewModel.java
#	desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesView.java
#	desktop/src/main/java/bisq/desktop/main/support/dispute/DisputeView.java
#	desktop/src/main/java/bisq/desktop/main/support/dispute/agent/DisputeAgentView.java
This commit is contained in:
Christoph Atteneder 2019-09-17 15:52:51 +02:00
commit cc3128d4e0
No known key found for this signature in database
GPG Key ID: CD5DC1C529CDFD3B
128 changed files with 3692 additions and 1276 deletions

View File

@ -179,6 +179,7 @@
</Properties>
<codeStyleSettings language="JAVA">
<option name="RIGHT_MARGIN" value="120" />
<option name="KEEP_LINE_BREAKS" value="false" />
<option name="BLANK_LINES_BEFORE_PACKAGE" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="WRAP_ON_TYPING" value="0" />

View File

@ -19,6 +19,7 @@ All Bisq contributors submit changes via pull requests. The workflow is as follo
- Fork the repository
- Create a topic branch from the `master` branch
- Commit patches
- Squash redundant or unnecessary commits
- Submit a pull request from your topic branch back to the `master` branch of the main repository
Pull requests should be focused on a single change. Do not mix, for example, refactorings with a bug fix or implementation of a new feature. This practice makes it easier for fellow contributors to review each pull request on its merits and and to give a clear ACK/NACK (see below).
@ -73,6 +74,10 @@ https://help.github.com/articles/signing-commits-with-gpg/ for instructions.
The [.editorconfig](.editorconfig) settings in this repository ensure consistent management of whitespace, line endings and more. Most modern editors support it natively or with plugin. See http://editorconfig.org for details. See also [bisq-network/style#10](https://github.com/bisq-network/style/issues/10).
### Keep the git history clean
It's very important to keep the git history clear, light and easily browsable. This means contributors must make sure their pull requests include only meaningful commits (if they are redundant or were added after a review, they should be removed) and _no merge commits_.
### Additional style guidelines
See the issues in the [bisq-network/style](https://github.com/bisq-network/style/issues) repository.

View File

@ -1,66 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.asset.coins;
import bisq.asset.AddressValidationResult;
import bisq.asset.AddressValidator;
import bisq.asset.Coin;
import java.util.Arrays;
import org.bitcoinj.core.Base58;
import org.bitcoinj.core.AddressFormatException;
import org.bouncycastle.crypto.digests.Blake2bDigest;
public class Ergo extends Coin {
public Ergo() {
super("Ergo", "ERG", new ErgoAddressValidator());
}
public static class ErgoAddressValidator implements AddressValidator {
@Override
public AddressValidationResult validate(String address) {
try {
byte[] decoded = Base58.decode(address);
if (decoded.length < 4) {
return AddressValidationResult.invalidAddress("Input too short: " + decoded.length);
}
if (decoded[0] != 1 && decoded[0] != 2 && decoded[0] != 3) {
return AddressValidationResult.invalidAddress("Invalid prefix");
}
byte[] data = Arrays.copyOfRange(decoded, 0, decoded.length - 4);
byte[] checksum = Arrays.copyOfRange(decoded, decoded.length - 4, decoded.length);
byte[] hashed = new byte[32];
{
Blake2bDigest digest = new Blake2bDigest(256);
digest.update(data, 0, data.length);
digest.doFinal(hashed, 0);
}
byte[] actualChecksum = Arrays.copyOfRange(hashed, 0, 4);
if (!Arrays.equals(checksum, actualChecksum)) {
return AddressValidationResult.invalidAddress("Invalid checksum");
}
} catch (AddressFormatException e) {
return AddressValidationResult.invalidAddress(e);
}
return AddressValidationResult.validAddress();
}
}
}

View File

@ -40,7 +40,6 @@ bisq.asset.coins.Donu
bisq.asset.coins.Dragonglass
bisq.asset.coins.DSTRA
bisq.asset.coins.Emercoin
bisq.asset.coins.Ergo
bisq.asset.coins.Ether
bisq.asset.coins.EtherClassic
bisq.asset.coins.FourtyTwo

View File

@ -1,48 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.asset.coins;
import bisq.asset.AbstractAssetTest;
import org.junit.Test;
public class ErgoTest extends AbstractAssetTest {
public ErgoTest() {
super(new Ergo());
}
@Test
public void testValidAddresses() {
assertValidAddress("9fRAWhdxEsTcdb8PhGNrZfwqa65zfkuYHAMmkQLcic1gdLSV5vA");
assertValidAddress("25qGdVWg2yyYho8uC1pLtc7KxFn4nEEAwD");
assertValidAddress("23NL9a8ngN28ovtLiKLgHexcdTKBbUMLhH");
assertValidAddress("7bwdkU5V8");
assertValidAddress("BxKBaHkvrTvLZrDcZjcsxsF7aSsrN73ijeFZXtbj4CXZHHcvBtqSxQ");
}
@Test
public void testInvalidAddresses() {
assertInvalidAddress("9fRAWhdxEsTcdb8PhGNrZfwqa65zfkuYHAMmkQLcic1gdLSV5vAaa");
assertInvalidAddress("afRAWhdxEsTcdb8PhGNrZfwqa65zfkuYHAMmkQLcic1gdLSV5vA");
assertInvalidAddress("25qGdVWg2yyYho8uC1pLtc7KxFn4nEEAwDaa");
assertInvalidAddress("23NL9a8ngN28ovtLiKLgHexcdTKBbUMLhHaa");
assertInvalidAddress("7bwdkU5V8aa");
assertInvalidAddress("BxKBaHkvrTvLZrDcZjcsxsF7aSsrN73ijeFZXtbj4CXZHHcvBtqSxQ#");
}
}

View File

@ -60,7 +60,7 @@ configure(subprojects) {
logbackVersion = '1.1.10'
lombokVersion = '1.18.2'
mockitoVersion = '3.0.0'
netlayerVersion = '0.6.5.1'
netlayerVersion = '0.6.5.2'
protobufVersion = '3.9.1'
pushyVersion = '0.13.2'
qrgenVersion = '1.3'
@ -158,7 +158,6 @@ configure(project(':assets')) {
compile "com.google.guava:guava:$guavaVersion"
compile "org.slf4j:slf4j-api:$slf4jVersion"
compile "org.apache.commons:commons-lang3:$langVersion"
compile "org.bouncycastle:bcpg-jdk15on:$bcVersion"
}
}
@ -180,9 +179,6 @@ configure(project(':common')) {
compile "org.openjfx:javafx-graphics:11:$os"
compile "com.google.protobuf:protobuf-java:$protobufVersion"
compile 'com.google.code.gson:gson:2.7'
compile("com.googlecode.json-simple:json-simple:$jsonsimpleVersion") {
exclude(module: 'junit')
}
compile "org.springframework:spring-core:$springVersion"
compile "org.slf4j:slf4j-api:$slf4jVersion"
compile "ch.qos.logback:logback-core:$logbackVersion"
@ -199,7 +195,6 @@ configure(project(':common')) {
exclude(module: 'protobuf-java')
}
compile "org.jetbrains:annotations:$jetbrainsAnnotationsVersion"
runtime "org.bouncycastle:bcprov-jdk15on:$bcVersion"
compile "org.bouncycastle:bcpg-jdk15on:$bcVersion"
compile "commons-io:commons-io:$ioVersion"
compile "org.apache.commons:commons-lang3:$langVersion"
@ -396,7 +391,6 @@ configure(project(':seednode')) {
dependencies {
compile project(':core')
runtime "org.bouncycastle:bcprov-jdk15on:$bcVersion"
compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
testCompile "org.springframework:spring-test:$springVersion"

View File

@ -54,8 +54,7 @@ public class FrameRateTimer implements Timer, Runnable {
stop();
}
} catch (Throwable t) {
log.error(t.getMessage());
t.printStackTrace();
log.error("exception in FrameRateTimer", t);
stop();
throw t;
}

View File

@ -93,8 +93,7 @@ public class UserThread {
return timerClass.getDeclaredConstructor().newInstance();
} catch (InstantiationException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
String message = "Could not instantiate timer bsTimerClass=" + timerClass;
log.error(message);
e.printStackTrace();
log.error(message, e);
throw new RuntimeException(message);
}
}

View File

@ -38,4 +38,3 @@ public class CryptoUtils {
return bytes;
}
}

View File

@ -18,8 +18,7 @@
package bisq.common.crypto;
import bisq.common.util.Utilities;
import org.bouncycastle.util.encoders.Hex;
import bisq.common.util.Hex;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
@ -70,8 +69,7 @@ public class Encryption {
log.trace("Generate msgEncryptionKeyPair needed {} ms", System.currentTimeMillis() - ts);
return keyPair;
} catch (Throwable e) {
log.error(e.toString());
e.printStackTrace();
log.error("Could not create key.", e);
throw new RuntimeException("Could not create key.");
}
}
@ -87,7 +85,7 @@ public class Encryption {
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(payload);
} catch (Throwable e) {
e.printStackTrace();
log.error("error in encrypt", e);
throw new CryptoException(e);
}
}
@ -128,8 +126,7 @@ public class Encryption {
outputStream.flush();
payloadWithHmac = outputStream.toByteArray().clone();
} catch (IOException | NoSuchProviderException e) {
log.error(e.toString());
e.printStackTrace();
log.error("Could not create hmac", e);
throw new RuntimeException("Could not create hmac");
} finally {
if (outputStream != null) {
@ -140,8 +137,7 @@ public class Encryption {
}
}
} catch (Throwable e) {
log.error(e.toString());
e.printStackTrace();
log.error("Could not create hmac", e);
throw new RuntimeException("Could not create hmac");
}
return payloadWithHmac;
@ -153,8 +149,7 @@ public class Encryption {
byte[] hmacTest = getHmac(message, secretKey);
return Arrays.equals(hmacTest, hmac);
} catch (Throwable e) {
log.error(e.toString());
e.printStackTrace();
log.error("Could not create cipher", e);
throw new RuntimeException("Could not create cipher");
}
}
@ -177,7 +172,7 @@ public class Encryption {
public static byte[] decryptPayloadWithHmac(byte[] encryptedPayloadWithHmac, SecretKey secretKey) throws CryptoException {
byte[] payloadWithHmac = decrypt(encryptedPayloadWithHmac, secretKey);
String payloadWithHmacAsHex = Hex.toHexString(payloadWithHmac);
String payloadWithHmacAsHex = Hex.encode(payloadWithHmac);
// first part is raw message
int length = payloadWithHmacAsHex.length();
int sep = length - 64;
@ -204,7 +199,7 @@ public class Encryption {
cipher.init(Cipher.WRAP_MODE, publicKey, oaepParameterSpec);
return cipher.wrap(secretKey);
} catch (Throwable e) {
e.printStackTrace();
log.error("Couldn't encrypt payload", e);
throw new CryptoException("Couldn't encrypt payload");
}
}
@ -233,8 +228,7 @@ public class Encryption {
keyPairGenerator.init(bits);
return keyPairGenerator.generateKey();
} catch (Throwable e) {
e.printStackTrace();
log.error(e.getMessage());
log.error("Couldn't generate key", e);
throw new RuntimeException("Couldn't generate key");
}
}
@ -252,7 +246,6 @@ public class Encryption {
return KeyFactory.getInstance(Encryption.ASYM_KEY_ALGO).generatePublic(new X509EncodedKeySpec(encryptionPubKeyBytes));
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
log.error("Error creating sigPublicKey from bytes. sigPublicKeyBytes as hex={}, error={}", Utilities.bytesAsHexString(encryptionPubKeyBytes), e);
e.printStackTrace();
throw new KeyConversionException(e);
}
}

View File

@ -43,8 +43,7 @@ public class Hash {
digest.update(data, 0, data.length);
return digest.digest();
} catch (NoSuchAlgorithmException e) {
log.error("Could not create MessageDigest for hash. " + e.toString());
e.printStackTrace();
log.error("Could not create MessageDigest for hash. ", e);
throw new RuntimeException(e);
}
}

View File

@ -20,18 +20,12 @@ package bisq.common.crypto;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPublicKey;
import java.security.KeyPair;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
@Getter
@EqualsAndHashCode
@Slf4j
@ -41,33 +35,18 @@ public final class KeyRing {
private final KeyPair encryptionKeyPair;
private final PubKeyRing pubKeyRing;
// We generate by default a PGP keypair but the user can set his own if he prefers.
// Not impl. yet but prepared in data structure
@Nullable
@Setter
// TODO remove Nullable once impl.
private PGPKeyPair pgpKeyPair;
@Inject
public KeyRing(KeyStorage keyStorage) {
if (keyStorage.allKeyFilesExist()) {
signatureKeyPair = keyStorage.loadKeyPair(KeyStorage.KeyEntry.MSG_SIGNATURE);
encryptionKeyPair = keyStorage.loadKeyPair(KeyStorage.KeyEntry.MSG_ENCRYPTION);
// TODO not impl
pgpKeyPair = keyStorage.loadPgpKeyPair(KeyStorage.KeyEntry.PGP);
} else {
// First time we create key pairs
signatureKeyPair = Sig.generateKeyPair();
encryptionKeyPair = Encryption.generateKeyPair();
// TODO not impl
pgpKeyPair = PGP.generateKeyPair();
keyStorage.saveKeyRing(this);
}
// TODO remove Nullable once impl.
final PGPPublicKey pgpPublicKey = pgpKeyPair != null ? pgpKeyPair.getPublicKey() : null;
pubKeyRing = new PubKeyRing(signatureKeyPair.getPublic(), encryptionKeyPair.getPublic(), pgpPublicKey);
pubKeyRing = new PubKeyRing(signatureKeyPair.getPublic(), encryptionKeyPair.getPublic());
}
// Don't print keys for security reasons

View File

@ -24,8 +24,6 @@ import com.google.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.bouncycastle.openpgp.PGPKeyPair;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
@ -54,8 +52,6 @@ import org.slf4j.LoggerFactory;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
// TODO: use a password protection for key storage
@Singleton
public class KeyStorage {
@ -65,9 +61,7 @@ public class KeyStorage {
public enum KeyEntry {
MSG_SIGNATURE("sig", Sig.KEY_ALGO),
MSG_ENCRYPTION("enc", Encryption.ASYM_KEY_ALGO),
// TODO not impl
PGP("pgp", null);
MSG_ENCRYPTION("enc", Encryption.ASYM_KEY_ALGO);
private final String fileName;
private final String algorithm;
@ -111,14 +105,6 @@ public class KeyStorage {
return new File(storageDir + "/" + keyEntry.getFileName() + ".key").exists();
}
// TODO not impl
@SuppressWarnings({"SameParameterValue", "SameReturnValue", "UnusedParameters"})
@Nullable
public PGPKeyPair loadPgpKeyPair(KeyEntry keyEntry) {
return null;
}
public KeyPair loadKeyPair(KeyEntry keyEntry) {
FileUtil.rollingBackup(storageDir, keyEntry.getFileName() + ".key", 20);
// long now = System.currentTimeMillis();
@ -136,8 +122,7 @@ public class KeyStorage {
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
privateKey = keyFactory.generatePrivate(privateKeySpec);
} catch (InvalidKeySpecException | IOException e) {
log.error(e.getMessage());
e.printStackTrace();
log.error("Could not load key " + keyEntry.toString(), e.getMessage());
throw new RuntimeException("Could not load key " + keyEntry.toString(), e);
}
@ -161,8 +146,7 @@ public class KeyStorage {
log.debug("load completed in {} msec", System.currentTimeMillis() - new Date().getTime());
return new KeyPair(publicKey, privateKey);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
log.error(e.getMessage());
log.error("Could not load key " + keyEntry.toString(), e);
throw new RuntimeException("Could not load key " + keyEntry.toString(), e);
}
}
@ -181,8 +165,7 @@ public class KeyStorage {
try (FileOutputStream fos = new FileOutputStream(storageDir + "/" + name + ".key")) {
fos.write(pkcs8EncodedKeySpec.getEncoded());
} catch (IOException e) {
log.error(e.toString());
e.printStackTrace();
log.error("Could not save key " + name, e);
throw new RuntimeException("Could not save key " + name, e);
}
}

View File

@ -1,133 +0,0 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.common.crypto;
import com.google.common.base.Charsets;
import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRingCollection;
import org.bouncycastle.util.encoders.Hex;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
@SuppressWarnings("UnusedAssignment")
@Slf4j
public class PGP {
// TODO not tested yet, remove Nullable once impl.
// PEM encoding
@Nullable
public static PGPPublicKey getPubKeyFromPem(@Nullable String pem) {
if (pem != null) {
InputStream inputStream = new ByteArrayInputStream(pem.getBytes(Charsets.UTF_8));
try {
inputStream = PGPUtil.getDecoderStream(inputStream);
try {
JcaPGPPublicKeyRingCollection ringCollection = new JcaPGPPublicKeyRingCollection(inputStream);
Iterator<PGPPublicKeyRing> keyRingsIterator = ringCollection.getKeyRings();
while (keyRingsIterator.hasNext()) {
PGPPublicKeyRing pgpPublicKeyRing = keyRingsIterator.next();
Iterator<PGPPublicKey> pubKeysIterator = pgpPublicKeyRing.getPublicKeys();
while (pubKeysIterator.hasNext()) {
final PGPPublicKey pgpPublicKey = pubKeysIterator.next();
if ((pgpPublicKey).isEncryptionKey()) {
log.debug(pgpPublicKey.getClass().getName()
+ " KeyID: " + Long.toHexString(pgpPublicKey.getKeyID())
+ " type: " + pgpPublicKey.getAlgorithm()
+ " fingerprint: " + new String(Hex.encode(pgpPublicKey.getFingerprint())));
BCPGKey bcKey = pgpPublicKey.getPublicKeyPacket().getKey();
log.debug(bcKey.getClass().getName());
if (bcKey instanceof RSAPublicBCPGKey) {
RSAPublicBCPGKey bcRSA = (RSAPublicBCPGKey) bcKey;
RSAPublicKeySpec specRSA = new RSAPublicKeySpec(bcRSA.getModulus(), bcRSA.getPublicExponent());
PublicKey jceKey = KeyFactory.getInstance("RSA").generatePublic(specRSA);
// if you want to use the key in JCE, use jceKey
// if you want to write "X.509" (SPKI) DER format to a file:
//Files.write(new File(pubKeyAsString).toPath(), jceKey.getEncoded());
// if you want to write in PEM, bouncycastle can do that
// or you can just do base64 and add BEGIN/END lines
// return pubKeyAsString; // assume only one key; if need to handle multiple keys
// or select other than the first, specify more clearly
}
return pgpPublicKey;
}
}
}
return null;
} catch (PGPException | InvalidKeySpecException | NoSuchAlgorithmException e) {
log.error("Error creating publicKey from pem. pem={}, error={}", pem, e);
e.printStackTrace();
throw new KeyConversionException(e);
}
} catch (IOException e) {
log.error("Error creating publicKey from pem. pem={}, error={}", pem, e);
e.printStackTrace();
throw new KeyConversionException(e);
} finally {
try {
inputStream.close();
} catch (IOException ignore) {
}
}
} else {
log.warn("Error creating publicKey from pem. pem=null");
return null;
}
}
// TODO not impl, remove Nullable once impl.
// PEM encoding
@SuppressWarnings({"SameReturnValue", "UnusedParameters"})
@NotNull
public static String getPEMFromPubKey(@Nullable PGPPublicKey pgpPubKey) {
// We use empty string as we must not have null in proto file
return "";
}
// TODO not impl, remove Nullable once impl.
@SuppressWarnings("SameReturnValue")
@Nullable
public static PGPKeyPair generateKeyPair() {
return null;
}
}

View File

@ -25,16 +25,12 @@ import com.google.protobuf.ByteString;
import com.google.common.annotations.VisibleForTesting;
import org.bouncycastle.openpgp.PGPPublicKey;
import java.security.PublicKey;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
/**
* Same as KeyRing but with public keys only.
* Used to send public keys over the wire to other peer.
@ -45,22 +41,15 @@ import javax.annotation.Nullable;
public final class PubKeyRing implements NetworkPayload, UsedForTradeContractJson {
private final byte[] signaturePubKeyBytes;
private final byte[] encryptionPubKeyBytes;
@Nullable
private final String pgpPubKeyAsPem;
private transient PublicKey signaturePubKey;
private transient PublicKey encryptionPubKey;
@Nullable
private transient PGPPublicKey pgpPubKey;
public PubKeyRing(PublicKey signaturePubKey, PublicKey encryptionPubKey, @Nullable PGPPublicKey pgpPubKey) {
public PubKeyRing(PublicKey signaturePubKey, PublicKey encryptionPubKey) {
this.signaturePubKeyBytes = Sig.getPublicKeyBytes(signaturePubKey);
this.encryptionPubKeyBytes = Encryption.getPublicKeyBytes(encryptionPubKey);
this.pgpPubKeyAsPem = PGP.getPEMFromPubKey(pgpPubKey);
this.signaturePubKey = signaturePubKey;
this.encryptionPubKey = encryptionPubKey;
this.pgpPubKey = pgpPubKey;
}
@ -69,15 +58,11 @@ public final class PubKeyRing implements NetworkPayload, UsedForTradeContractJso
///////////////////////////////////////////////////////////////////////////////////////////
@VisibleForTesting
public PubKeyRing(byte[] signaturePubKeyBytes, byte[] encryptionPubKeyBytes, @Nullable String pgpPubKeyAsPem) {
public PubKeyRing(byte[] signaturePubKeyBytes, byte[] encryptionPubKeyBytes) {
this.signaturePubKeyBytes = signaturePubKeyBytes;
this.encryptionPubKeyBytes = encryptionPubKeyBytes;
this.pgpPubKeyAsPem = pgpPubKeyAsPem;
signaturePubKey = Sig.getPublicKeyFromBytes(signaturePubKeyBytes);
encryptionPubKey = Encryption.getPublicKeyFromBytes(encryptionPubKeyBytes);
if (pgpPubKeyAsPem != null)
pgpPubKey = PGP.getPubKeyFromPem(pgpPubKeyAsPem);
}
@Override
@ -85,14 +70,13 @@ public final class PubKeyRing implements NetworkPayload, UsedForTradeContractJso
return protobuf.PubKeyRing.newBuilder()
.setSignaturePubKeyBytes(ByteString.copyFrom(signaturePubKeyBytes))
.setEncryptionPubKeyBytes(ByteString.copyFrom(encryptionPubKeyBytes))
.setPgpPubKeyAsPem(pgpPubKeyAsPem)
.build();
}
public static PubKeyRing fromProto(protobuf.PubKeyRing proto) {
return new PubKeyRing(proto.getSignaturePubKeyBytes().toByteArray(),
proto.getEncryptionPubKeyBytes().toByteArray(),
proto.getPgpPubKeyAsPem());
return new PubKeyRing(
proto.getSignaturePubKeyBytes().toByteArray(),
proto.getEncryptionPubKeyBytes().toByteArray());
}
@Override
@ -100,7 +84,6 @@ public final class PubKeyRing implements NetworkPayload, UsedForTradeContractJso
return "PubKeyRing{" +
"signaturePubKeyHex=" + Utilities.bytesAsHexString(signaturePubKeyBytes) +
", encryptionPubKeyHex=" + Utilities.bytesAsHexString(encryptionPubKeyBytes) +
", pgpPubKeyAsString=" + pgpPubKeyAsPem +
'}';
"}";
}
}

View File

@ -18,11 +18,10 @@
package bisq.common.crypto;
import bisq.common.util.Utilities;
import bisq.common.util.Base64;
import com.google.common.base.Charsets;
import org.bouncycastle.util.encoders.Base64;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
@ -65,8 +64,7 @@ public class Sig {
log.trace("Generate msgSignatureKeyPair needed {} ms", System.currentTimeMillis() - ts);
return keyPair;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
log.error(e.toString());
log.error("Could not create key.", e);
throw new RuntimeException("Could not create key.");
}
}
@ -95,7 +93,7 @@ public class Sig {
*/
public static String sign(PrivateKey privateKey, String message) throws CryptoException {
byte[] sigAsBytes = sign(privateKey, message.getBytes(Charsets.UTF_8));
return Base64.toBase64String(sigAsBytes);
return Base64.encode(sigAsBytes);
}
/**
@ -143,4 +141,3 @@ public class Sig {
return new X509EncodedKeySpec(sigPublicKey.getEncoded()).getEncoded();
}
}

View File

@ -20,14 +20,9 @@ package bisq.common.storage;
import bisq.common.UserThread;
import bisq.common.util.Utilities;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.nio.file.Paths;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.ThreadPoolExecutor;
@ -102,15 +97,4 @@ public class JsonFileManager {
}
});
}
public Object readJsonFromDisc(String fileName) {
final File jsonFile = new File(Paths.get(dir.getAbsolutePath(), fileName + ".json").toString());
JSONParser parser = new JSONParser();
try {
return parser.parse(new FileReader(jsonFile));
} catch (ParseException | IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,33 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.common.util;
/**
* We use Java 8 builtin Base64 because it is much faster than Guava and Apache versions:
* http://java-performance.info/base64-encoding-and-decoding-performance/
*/
public class Base64 {
public static byte[] decode(String base64) {
return java.util.Base64.getDecoder().decode(base64);
}
public static String encode(byte[] bytes) {
return java.util.Base64.getEncoder().encodeToString(bytes);
}
}

View File

@ -0,0 +1,31 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.common.util;
import com.google.common.io.BaseEncoding;
public class Hex {
public static byte[] decode(String hex) {
return BaseEncoding.base16().lowerCase().decode(hex.toLowerCase());
}
public static String encode(byte[] bytes) {
return BaseEncoding.base16().lowerCase().encode(bytes);
}
}

View File

@ -431,7 +431,7 @@ message Peer {
message PubKeyRing {
bytes signature_pub_key_bytes = 1;
bytes encryption_pub_key_bytes = 2;
string pgp_pub_key_as_pem = 3;
reserved 3; // WAS: string pgp_pub_key_as_pem = 3;
}
message SealedAndSigned {

View File

@ -70,9 +70,7 @@ public class AvoidStandbyModeService {
private void start() {
isStopped = false;
log.info("AvoidStandbyModeService started");
Thread thread = new Thread(this::play);
thread.setName("AvoidStandbyModeService-thread");
thread.start();
new Thread(this::play, "AvoidStandbyModeService-thread").start();
}

View File

@ -446,11 +446,8 @@ public class BisqSetup {
bisqEnvironment.getIgnoreLocalBtcNode()) {
step3();
} else {
Thread checkIfLocalHostNodeIsRunningThread = new Thread(() -> {
Thread.currentThread().setName("checkIfLocalHostNodeIsRunningThread");
Socket socket = null;
try {
socket = new Socket();
new Thread(() -> {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(InetAddresses.forString("127.0.0.1"),
BisqEnvironment.getBaseCurrencyNetwork().getParameters().getPort()), 5000);
log.info("Localhost Bitcoin node detected.");
@ -460,16 +457,8 @@ public class BisqSetup {
});
} catch (Throwable e) {
UserThread.execute(BisqSetup.this::step3);
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException ignore) {
}
}
}
});
checkIfLocalHostNodeIsRunningThread.start();
}, "checkIfLocalHostNodeIsRunningThread").start();
}
}
@ -486,9 +475,8 @@ public class BisqSetup {
// If users compile themselves they might miss that step and then would get an exception in the trade.
// To avoid that we add here at startup a sample encryption and signing to see if it don't causes an exception.
// See: https://github.com/bisq-network/exchange/blob/master/doc/build.md#7-enable-unlimited-strength-for-cryptographic-keys
Thread checkCryptoThread = new Thread(() -> {
new Thread(() -> {
try {
Thread.currentThread().setName("checkCryptoThread");
// just use any simple dummy msg
Ping payload = new Ping(1, 1);
SealedAndSigned sealedAndSigned = EncryptionService.encryptHybridWithSignature(payload,
@ -508,8 +496,7 @@ public class BisqSetup {
if (cryptoSetupFailedHandler != null)
cryptoSetupFailedHandler.accept(msg);
}
});
checkCryptoThread.start();
}, "checkCryptoThread").start();
}
private void startP2pNetworkAndWallet() {

View File

@ -49,11 +49,8 @@ public class SetupUtils {
// If users compile themselves they might miss that step and then would get an exception in the trade.
// To avoid that we add here at startup a sample encryption and signing to see if it don't causes an exception.
// See: https://github.com/bisq-network/exchange/blob/master/doc/build.md#7-enable-unlimited-strength-for-cryptographic-keys
Thread checkCryptoThread = new Thread() {
@Override
public void run() {
Thread checkCryptoThread = new Thread(() -> {
try {
Thread.currentThread().setName("checkCryptoThread");
// just use any simple dummy msg
Ping payload = new Ping(1, 1);
SealedAndSigned sealedAndSigned = EncryptionService.encryptHybridWithSignature(payload,
@ -74,15 +71,13 @@ public class SetupUtils {
e.printStackTrace();
errorHandler.accept(e);
}
}
};
}, "checkCryptoThread");
checkCryptoThread.start();
}
public static BooleanProperty readFromResources(P2PDataStorage p2PDataStorage) {
BooleanProperty result = new SimpleBooleanProperty();
Thread thread = new Thread(() -> {
Thread.currentThread().setName("readFromResourcesThread");
new Thread(() -> {
// Used to load different files per base currency (EntryMap_BTC_MAINNET, EntryMap_LTC,...)
final BaseCurrencyNetwork baseCurrencyNetwork = BisqEnvironment.getBaseCurrencyNetwork();
final String postFix = "_" + baseCurrencyNetwork.name();
@ -90,8 +85,7 @@ public class SetupUtils {
p2PDataStorage.readFromResources(postFix);
log.info("readFromResources took {} ms", (new Date().getTime() - ts));
UserThread.execute(() -> result.set(true));
});
thread.start();
}, "readFromResourcesThread").start();
return result;
}
}

View File

@ -120,7 +120,7 @@ public class WalletAppSetup {
result = Res.get("mainView.footer.btcInfo",
peers,
Res.get("mainView.footer.btcInfo.synchronizingWith"),
getBtcNetworkAsString() + ": " + formatter.formatToPercentWithSymbol(percentage));
getBtcNetworkAsString() + ": " + BSFormatter.formatToPercentWithSymbol(percentage));
} else {
result = Res.get("mainView.footer.btcInfo",
peers,

View File

@ -561,13 +561,12 @@ public class WalletConfig extends AbstractIdleService {
private void installShutdownHook() {
if (autoStop) Runtime.getRuntime().addShutdownHook(new Thread(() -> {
Thread.currentThread().setName("ShutdownHook");
try {
WalletConfig.this.stopAsync();
WalletConfig.this.awaitTerminated();
} catch (Throwable ignore) {
}
}));
}, "WalletConfig ShutdownHook"));
}
@Override

View File

@ -180,9 +180,9 @@ public class TradeWalletService {
boolean doBroadcast,
@Nullable TxBroadcaster.Callback callback)
throws InsufficientMoneyException, AddressFormatException {
log.debug("fundingAddress {}", fundingAddress.toString());
log.debug("reservedForTradeAddress {}", reservedForTradeAddress.toString());
log.debug("changeAddress {}", changeAddress.toString());
log.debug("fundingAddress {}", fundingAddress);
log.debug("reservedForTradeAddress {}", reservedForTradeAddress);
log.debug("changeAddress {}", changeAddress);
log.info("reservedFundsForOffer {}", reservedFundsForOffer.toPlainString());
log.debug("useSavingsWallet {}", useSavingsWallet);
log.info("tradingFee {}", tradingFee.toPlainString());
@ -245,9 +245,9 @@ public class TradeWalletService {
TransactionVerificationException, WalletException,
InsufficientMoneyException, AddressFormatException {
log.debug("preparedBsqTx {}", preparedBsqTx.toString());
log.debug("fundingAddress {}", fundingAddress.toString());
log.debug("changeAddress {}", changeAddress.toString());
log.debug("preparedBsqTx {}", preparedBsqTx);
log.debug("fundingAddress {}", fundingAddress);
log.debug("changeAddress {}", changeAddress);
log.debug("reservedFundsForOffer {}", reservedFundsForOffer.toPlainString());
log.debug("useSavingsWallet {}", useSavingsWallet);
log.debug("txFee {}", txFee.toPlainString());
@ -346,10 +346,12 @@ public class TradeWalletService {
Coin txFee,
Address takersAddress) throws
TransactionVerificationException {
if (log.isDebugEnabled()) {
log.debug("takerCreatesDepositsTxInputs called");
log.debug("inputAmount {}", inputAmount.toFriendlyString());
log.debug("txFee {}", txFee.toFriendlyString());
log.debug("takersAddress {}", takersAddress.toString());
}
// We add the mining fee 2 times to the deposit tx:
// 1. Will be spent when publishing the deposit tx (paid by buyer)
@ -448,9 +450,9 @@ public class TradeWalletService {
log.debug("takerChangeAddressString {}", takerChangeAddressString);
log.debug("makerAddress {}", makerAddress);
log.debug("makerChangeAddress {}", makerChangeAddress);
log.debug("buyerPubKey {}", ECKey.fromPublicOnly(buyerPubKey).toString());
log.debug("sellerPubKey {}", ECKey.fromPublicOnly(sellerPubKey).toString());
log.debug("arbitratorPubKey {}", ECKey.fromPublicOnly(arbitratorPubKey).toString());
log.debug("buyerPubKey {}", ECKey.fromPublicOnly(buyerPubKey));
log.debug("sellerPubKey {}", ECKey.fromPublicOnly(sellerPubKey));
log.debug("arbitratorPubKey {}", ECKey.fromPublicOnly(arbitratorPubKey));
checkArgument(!takerRawTransactionInputs.isEmpty());

View File

@ -40,8 +40,8 @@ public class DaoUtil {
long now = new Date().getTime();
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM", Locale.getDefault());
SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm", Locale.getDefault());
String startDateTime = formatter.formatDateTime(new Date(now + (start - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
String endDateTime = formatter.formatDateTime(new Date(now + (end - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
String startDateTime = BSFormatter.formatDateTime(new Date(now + (start - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
String endDateTime = BSFormatter.formatDateTime(new Date(now + (end - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
return Res.get("dao.cycle.phaseDurationWithoutBlocks", start, end, startDateTime, endDateTime);
}
@ -53,9 +53,9 @@ public class DaoUtil {
long now = new Date().getTime();
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM", Locale.getDefault());
SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm", Locale.getDefault());
String startDateTime = formatter.formatDateTime(new Date(now + (start - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
String endDateTime = formatter.formatDateTime(new Date(now + (end - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
String durationTime = formatter.formatDurationAsWords(duration * 10 * 60 * 1000, false, false);
String startDateTime = BSFormatter.formatDateTime(new Date(now + (start - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
String endDateTime = BSFormatter.formatDateTime(new Date(now + (end - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
String durationTime = BSFormatter.formatDurationAsWords(duration * 10 * 60 * 1000, false, false);
return Res.get("dao.cycle.phaseDuration", duration, durationTime, start, end, startDateTime, endDateTime);
}
}

View File

@ -36,6 +36,7 @@ import bisq.core.dao.state.model.governance.Issuance;
import bisq.core.dao.state.model.governance.IssuanceType;
import bisq.core.dao.state.model.governance.ParamChange;
import bisq.core.util.BsqFormatter;
import bisq.core.util.ParsingUtils;
import org.bitcoinj.core.Coin;
@ -923,7 +924,7 @@ public class DaoStateService implements DaoSetupService {
}
public double getParamValueAsPercentDouble(String paramValue) {
return bsqFormatter.parsePercentStringToDouble(paramValue);
return ParsingUtils.parsePercentStringToDouble(paramValue);
}
public int getParamValueAsBlock(String paramValue) {

View File

@ -34,6 +34,7 @@ public class LanguageUtil {
"el", // Greek
"es", // Spanish
"pt", // Portuguese
"pt_BR", // Brazilian Portuguese
"zh", // Chinese
"ru", // Russian
"fr", // French
@ -118,6 +119,8 @@ public class LanguageUtil {
// Serbia
// shows it in russian by default
return "Srpski";
} else if (locale.getLanguage().equals("pt_br")) {
return "português (Brasil)";
} else {
return locale.getDisplayName(locale);
}

View File

@ -17,7 +17,7 @@
package bisq.core.monetary;
import bisq.core.util.BSFormatter;
import bisq.core.util.ParsingUtils;
import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.MonetaryFormat;
@ -89,7 +89,7 @@ public final class Altcoin implements Monetary, Comparable<Altcoin> {
* @throws IllegalArgumentException if you try to specify fractional satoshis, or a value out of range.
*/
public static Altcoin parseAltcoin(final String currencyCode, String input) {
String cleaned = BSFormatter.convertCharsForNumber(input);
String cleaned = ParsingUtils.convertCharsForNumber(input);
try {
long val = new BigDecimal(cleaned).movePointRight(SMALLEST_UNIT_EXPONENT)
.toBigIntegerExact().longValue();

View File

@ -18,7 +18,7 @@
package bisq.core.monetary;
import bisq.core.locale.CurrencyUtil;
import bisq.core.util.BSFormatter;
import bisq.core.util.ParsingUtils;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Monetary;
@ -58,7 +58,7 @@ public class Price extends MonetaryWrapper implements Comparable<Price> {
* @return The parsed Price.
*/
public static Price parse(String currencyCode, String input) {
String cleaned = BSFormatter.convertCharsForNumber(input);
String cleaned = ParsingUtils.convertCharsForNumber(input);
if (CurrencyUtil.isFiatCurrency(currencyCode))
return new Price(Fiat.parseFiat(currencyCode, cleaned));
else

View File

@ -18,7 +18,7 @@
package bisq.core.monetary;
import bisq.core.locale.CurrencyUtil;
import bisq.core.util.BSFormatter;
import bisq.core.util.ParsingUtils;
import org.bitcoinj.core.Monetary;
import org.bitcoinj.utils.Fiat;
@ -36,7 +36,7 @@ public class Volume extends MonetaryWrapper implements Comparable<Volume> {
}
public static Volume parse(String input, String currencyCode) {
String cleaned = BSFormatter.convertCharsForNumber(input);
String cleaned = ParsingUtils.convertCharsForNumber(input);
if (CurrencyUtil.isFiatCurrency(currencyCode))
return new Volume(Fiat.parseFiat(currencyCode, cleaned));
else

View File

@ -180,9 +180,9 @@ public class MarketAlerts {
ratio = Math.abs(ratio);
String msg = Res.get("account.notifications.marketAlert.message.msg",
direction,
formatter.getCurrencyPair(currencyCode),
formatter.formatPrice(offerPrice),
formatter.formatToPercentWithSymbol(ratio / 10000d),
BSFormatter.getCurrencyPair(currencyCode),
BSFormatter.formatPrice(offerPrice),
BSFormatter.formatToPercentWithSymbol(ratio / 10000d),
marketDir,
Res.get(offer.getPaymentMethod().getId()),
shortOfferId);

View File

@ -70,8 +70,8 @@ public class PriceAlert {
if (priceAsLong > filter.getHigh() || priceAsLong < filter.getLow()) {
String msg = Res.get("account.notifications.priceAlert.message.msg",
currencyName,
formatter.formatMarketPrice(priceAsDouble, currencyCode),
formatter.getCurrencyPair(currencyCode));
BSFormatter.formatMarketPrice(priceAsDouble, currencyCode),
BSFormatter.getCurrencyPair(currencyCode));
MobileMessage message = new MobileMessage(Res.get("account.notifications.priceAlert.message.title", currencyName),
msg,
MobileMessageType.PRICE);

View File

@ -322,19 +322,6 @@ public class OfferUtil {
}
}
public static String getFeeWithFiatAmount(Coin makerFeeAsCoin,
Optional<Volume> optionalFeeInFiat,
BSFormatter formatter) {
String fee = makerFeeAsCoin != null ? formatter.formatCoinWithCode(makerFeeAsCoin) : Res.get("shared.na");
String feeInFiatAsString;
if (optionalFeeInFiat != null && optionalFeeInFiat.isPresent()) {
feeInFiatAsString = formatter.formatVolumeWithCode(optionalFeeInFiat.get());
} else {
feeInFiatAsString = Res.get("shared.na");
}
return Res.get("feeOptionWindow.fee", fee, feeInFiatAsString);
}
public static Map<String, String> getExtraDataMap(AccountAgeWitnessService accountAgeWitnessService,
ReferralIdService referralIdService,

View File

@ -48,7 +48,7 @@ public class ApplyFilter extends TradeTask {
FilterManager filterManager = processModel.getFilterManager();
if (nodeAddress != null && filterManager.isNodeAddressBanned(nodeAddress)) {
failed("Other trader is banned by his node address.\n" +
failed("Other trader is banned by their node address.\n" +
"tradingPeerNodeAddress=" + nodeAddress);
} else if (filterManager.isOfferIdBanned(trade.getId())) {
failed("Offer ID is banned.\n" +
@ -60,7 +60,7 @@ public class ApplyFilter extends TradeTask {
failed("Payment method is banned.\n" +
"Payment method=" + trade.getOffer().getPaymentMethod().getId());
} else if (filterManager.isPeersPaymentAccountDataAreBanned(paymentAccountPayload, appliedPaymentAccountFilter)) {
failed("Other trader is banned by his trading account data.\n" +
failed("Other trader is banned by their trading account data.\n" +
"paymentAccountPayload=" + paymentAccountPayload.getPaymentDetails() + "\n" +
"banFilter=" + appliedPaymentAccountFilter[0].toString());
} else if (filterManager.requireUpdateToNewVersionForTrading()) {

View File

@ -39,11 +39,13 @@ public class SellerVerifiesPeersAccountAge extends TradeTask {
try {
runInterceptHook();
boolean isTradeRisky = OfferRestrictions.isTradeRisky(trade);
boolean isTradePeersAccountAgeImmature = AccountAgeRestrictions.isTradePeersAccountAgeImmature(
processModel.getAccountAgeWitnessService(), trade);
log.debug("SellerVerifiesPeersAccountAge isOfferRisky={} isTradePeersAccountAgeImmature={}",
OfferRestrictions.isTradeRisky(trade), AccountAgeRestrictions.isTradePeersAccountAgeImmature(
processModel.getAccountAgeWitnessService(), trade));
if (OfferRestrictions.isTradeRisky(trade) &&
AccountAgeRestrictions.isTradePeersAccountAgeImmature(processModel.getAccountAgeWitnessService(), trade)) {
isTradeRisky, isTradePeersAccountAgeImmature);
if (isTradeRisky &&
isTradePeersAccountAgeImmature) {
failed("Violation of security restrictions:\n" +
" - The peer's account was created after March 1st 2019\n" +
" - The trade amount is above 0.01 BTC\n" +

View File

@ -20,12 +20,9 @@ package bisq.core.util;
import bisq.core.app.BisqEnvironment;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.GlobalSettings;
import bisq.core.locale.LanguageUtil;
import bisq.core.locale.Res;
import bisq.core.monetary.Altcoin;
import bisq.core.monetary.Price;
import bisq.core.monetary.Volume;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
import bisq.network.p2p.NodeAddress;
@ -55,6 +52,7 @@ import java.util.Locale;
import java.util.TimeZone;
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
@ -64,27 +62,24 @@ import org.jetbrains.annotations.NotNull;
public class BSFormatter {
public final static String RANGE_SEPARATOR = " - ";
protected boolean useMilliBit;
protected int scale = 3;
// We don't support localized formatting. Format is always using "." as decimal mark and no grouping separator.
// Input of "," as decimal mark (like in german locale) will be replaced with ".".
// Input of a group separator (1,123,45) lead to an validation error.
// Note: BtcFormat was intended to be used, but it lead to many problems (automatic format to mBit,
// no way to remove grouping separator). It seems to be not optimal for user input formatting.
protected MonetaryFormat coinFormat;
@Getter
protected MonetaryFormat monetaryFormat;
// protected String currencyCode = CurrencyUtil.getDefaultFiatCurrencyAsCode();
protected final MonetaryFormat fiatPriceFormat = new MonetaryFormat().shift(0).minDecimals(4).repeatOptionalDecimals(0, 0);
protected final MonetaryFormat fiatVolumeFormat = new MonetaryFormat().shift(0).minDecimals(2).repeatOptionalDecimals(0, 0);
protected final MonetaryFormat altcoinFormat = new MonetaryFormat().shift(0).minDecimals(8).repeatOptionalDecimals(0, 0);
protected final DecimalFormat decimalFormat = new DecimalFormat("#.#");
public static final MonetaryFormat fiatPriceFormat = new MonetaryFormat().shift(0).minDecimals(4).repeatOptionalDecimals(0, 0);
protected static final MonetaryFormat altcoinFormat = new MonetaryFormat().shift(0).minDecimals(8).repeatOptionalDecimals(0, 0);
protected static final DecimalFormat decimalFormat = new DecimalFormat("#.#");
@Inject
public BSFormatter() {
coinFormat = BisqEnvironment.getParameters().getMonetaryFormat();
monetaryFormat = BisqEnvironment.getParameters().getMonetaryFormat();
}
@ -106,10 +101,14 @@ public class BSFormatter {
}
public String formatCoin(Coin coin, int decimalPlaces, boolean decimalAligned, int maxNumberOfDigits) {
return formatCoin(coin, decimalPlaces, decimalAligned, maxNumberOfDigits, coinFormat);
return formatCoin(coin, decimalPlaces, decimalAligned, maxNumberOfDigits, monetaryFormat);
}
public String formatCoin(Coin coin, int decimalPlaces, boolean decimalAligned, int maxNumberOfDigits, MonetaryFormat coinFormat) {
public static String formatCoin(Coin coin,
int decimalPlaces,
boolean decimalAligned,
int maxNumberOfDigits,
MonetaryFormat coinFormat) {
String formattedCoin = "";
if (coin != null) {
@ -132,18 +131,18 @@ public class BSFormatter {
}
public String formatCoinWithCode(Coin coin) {
return formatCoinWithCode(coin, coinFormat);
return formatCoinWithCode(coin, monetaryFormat);
}
public String formatCoinWithCode(long value) {
return formatCoinWithCode(Coin.valueOf(value), monetaryFormat);
}
public static String formatCoinWithCode(long value, MonetaryFormat coinFormat) {
return formatCoinWithCode(Coin.valueOf(value), coinFormat);
}
public String formatCoinWithCode(long value, MonetaryFormat coinFormat) {
return formatCoinWithCode(Coin.valueOf(value), coinFormat);
}
public String formatCoinWithCode(Coin coin, MonetaryFormat coinFormat) {
public static String formatCoinWithCode(Coin coin, MonetaryFormat coinFormat) {
if (coin != null) {
try {
// we don't use the code feature from coinFormat as it does automatic switching between mBTC and BTC and
@ -158,62 +157,11 @@ public class BSFormatter {
}
}
public Coin parseToCoin(String input) {
return parseToCoin(input, coinFormat);
}
public Coin parseToCoin(String input, MonetaryFormat coinFormat) {
if (input != null && input.length() > 0) {
try {
return coinFormat.parse(cleanDoubleInput(input));
} catch (Throwable t) {
log.warn("Exception at parseToBtc: " + t.toString());
return Coin.ZERO;
}
} else {
return Coin.ZERO;
}
}
/**
* Converts to a coin with max. 4 decimal places. Last place gets rounded.
* 0.01234 -> 0.0123
* 0.01235 -> 0.0124
*
* @param input
* @return
*/
public Coin parseToCoinWith4Decimals(String input) {
try {
return Coin.valueOf(new BigDecimal(parseToCoin(cleanDoubleInput(input)).value).setScale(-scale - 1,
BigDecimal.ROUND_HALF_UP).setScale(scale + 1, BigDecimal.ROUND_HALF_UP).toBigInteger().longValue());
} catch (Throwable t) {
if (input != null && input.length() > 0)
log.warn("Exception at parseToCoinWith4Decimals: " + t.toString());
return Coin.ZERO;
}
}
public boolean hasBtcValidDecimals(String input) {
return parseToCoin(input).equals(parseToCoinWith4Decimals(input));
}
/**
* Transform a coin with the properties defined in the format (used to reduce decimal places)
*
* @param coin The coin which should be transformed
* @return The transformed coin
*/
public Coin reduceTo4Decimals(Coin coin) {
return parseToCoin(formatCoin(coin));
}
///////////////////////////////////////////////////////////////////////////////////////////
// FIAT
///////////////////////////////////////////////////////////////////////////////////////////
public String formatFiat(Fiat fiat, MonetaryFormat format, boolean appendCurrencyCode) {
public static String formatFiat(Fiat fiat, MonetaryFormat format, boolean appendCurrencyCode) {
if (fiat != null) {
try {
final String res = format.noCode().format(fiat).toString();
@ -230,10 +178,10 @@ public class BSFormatter {
}
}
protected Fiat parseToFiat(String input, String currencyCode) {
private static Fiat parseToFiat(String input, String currencyCode) {
if (input != null && input.length() > 0) {
try {
return Fiat.parseFiat(currencyCode, cleanDoubleInput(input));
return Fiat.parseFiat(currencyCode, ParsingUtils.cleanDoubleInput(input));
} catch (Exception e) {
log.warn("Exception at parseToFiat: " + e.toString());
return Fiat.valueOf(currencyCode, 0);
@ -253,10 +201,10 @@ public class BSFormatter {
* @return
*/
public Fiat parseToFiatWithPrecision(String input, String currencyCode) {
public static Fiat parseToFiatWithPrecision(String input, String currencyCode) {
if (input != null && input.length() > 0) {
try {
return parseToFiat(new BigDecimal(cleanDoubleInput(input)).setScale(2, BigDecimal.ROUND_HALF_UP).toString(),
return parseToFiat(new BigDecimal(ParsingUtils.cleanDoubleInput(input)).setScale(2, BigDecimal.ROUND_HALF_UP).toString(),
currencyCode);
} catch (Throwable t) {
log.warn("Exception at parseToFiatWithPrecision: " + t.toString());
@ -267,24 +215,12 @@ public class BSFormatter {
return Fiat.valueOf(currencyCode, 0);
}
public boolean isFiatAlteredWhenPrecisionApplied(String input, String currencyCode) {
return parseToFiat(input, currencyCode).equals(parseToFiatWithPrecision(input, currencyCode));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Altcoin
///////////////////////////////////////////////////////////////////////////////////////////
public String formatAltcoin(Altcoin altcoin) {
return formatAltcoin(altcoin, false);
}
public String formatAltcoinWithCode(Altcoin altcoin) {
return formatAltcoin(altcoin, true);
}
public String formatAltcoin(Altcoin altcoin, boolean appendCurrencyCode) {
private static String formatAltcoin(Altcoin altcoin, boolean appendCurrencyCode) {
if (altcoin != null) {
try {
String res = altcoinFormat.noCode().format(altcoin).toString();
@ -306,21 +242,8 @@ public class BSFormatter {
// Volume
///////////////////////////////////////////////////////////////////////////////////////////
public String formatVolume(Offer offer, Boolean decimalAligned, int maxNumberOfDigits) {
return formatVolume(offer, decimalAligned, maxNumberOfDigits, true);
}
public String formatVolume(Offer offer, Boolean decimalAligned, int maxNumberOfDigits, boolean showRange) {
String formattedVolume = offer.isRange() && showRange ? formatVolume(offer.getMinVolume()) + RANGE_SEPARATOR + formatVolume(offer.getVolume()) : formatVolume(offer.getVolume());
if (decimalAligned) {
formattedVolume = fillUpPlacesWithEmptyStrings(formattedVolume, maxNumberOfDigits);
}
return formattedVolume;
}
@NotNull
public String fillUpPlacesWithEmptyStrings(String formattedNumber, int maxNumberOfDigits) {
public static String fillUpPlacesWithEmptyStrings(String formattedNumber, int maxNumberOfDigits) {
//FIXME: temporary deactivate adding spaces in front of numbers as we don't use a monospace font right now.
/*int numberOfPlacesToFill = maxNumberOfDigits - formattedNumber.length();
for (int i = 0; i < numberOfPlacesToFill; i++) {
@ -329,27 +252,7 @@ public class BSFormatter {
return formattedNumber;
}
public String formatVolume(Volume volume) {
return formatVolume(volume, fiatVolumeFormat, false);
}
public String formatVolumeWithCode(Volume volume) {
return formatVolume(volume, fiatVolumeFormat, true);
}
public String formatVolume(Volume volume, MonetaryFormat fiatVolumeFormat, boolean appendCurrencyCode) {
if (volume != null) {
Monetary monetary = volume.getMonetary();
if (monetary instanceof Fiat)
return formatFiat((Fiat) monetary, fiatVolumeFormat, appendCurrencyCode);
else
return formatAltcoinVolume((Altcoin) monetary, appendCurrencyCode);
} else {
return "";
}
}
public String formatAltcoinVolume(Altcoin altcoin, boolean appendCurrencyCode) {
public static String formatAltcoinVolume(Altcoin altcoin, boolean appendCurrencyCode) {
if (altcoin != null) {
try {
// TODO quick hack...
@ -371,47 +274,13 @@ public class BSFormatter {
}
}
public String formatVolumeLabel(String currencyCode) {
return formatVolumeLabel(currencyCode, "");
}
public String formatVolumeLabel(String currencyCode, String postFix) {
return Res.get("formatter.formatVolumeLabel",
currencyCode, postFix);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Amount
///////////////////////////////////////////////////////////////////////////////////////////
public String formatAmount(Offer offer) {
return formatAmount(offer, false);
}
public String formatAmount(Offer offer, boolean decimalAligned) {
String formattedAmount = offer.isRange() ? formatCoin(offer.getMinAmount()) + RANGE_SEPARATOR + formatCoin(offer.getAmount()) : formatCoin(offer.getAmount());
if (decimalAligned) {
formattedAmount = fillUpPlacesWithEmptyStrings(formattedAmount, 15);
}
return formattedAmount;
}
public String formatAmount(Offer offer, int decimalPlaces, boolean decimalAligned, int maxPlaces) {
String formattedAmount = offer.isRange() ? formatCoin(offer.getMinAmount(), decimalPlaces) + RANGE_SEPARATOR + formatCoin(offer.getAmount(), decimalPlaces) : formatCoin(offer.getAmount(), decimalPlaces);
if (decimalAligned) {
formattedAmount = fillUpPlacesWithEmptyStrings(formattedAmount, maxPlaces);
}
return formattedAmount;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Price
///////////////////////////////////////////////////////////////////////////////////////////
public String formatPrice(Price price, MonetaryFormat fiatPriceFormat, boolean appendCurrencyCode) {
public static String formatPrice(Price price, MonetaryFormat fiatPriceFormat, boolean appendCurrencyCode) {
if (price != null) {
Monetary monetary = price.getMonetary();
if (monetary instanceof Fiat)
@ -423,35 +292,26 @@ public class BSFormatter {
}
}
public String formatPrice(Price price, boolean appendCurrencyCode) {
public static String formatPrice(Price price, boolean appendCurrencyCode) {
return formatPrice(price, fiatPriceFormat, true);
}
public String formatPrice(Price price) {
public static String formatPrice(Price price) {
return formatPrice(price, fiatPriceFormat, false);
}
public String formatPrice(Price price, Boolean decimalAligned, int maxPlaces) {
String formattedPrice = formatPrice(price);
if (decimalAligned) {
formattedPrice = fillUpPlacesWithEmptyStrings(formattedPrice, maxPlaces);
}
return formattedPrice;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Market price
///////////////////////////////////////////////////////////////////////////////////////////
public String formatMarketPrice(double price, String currencyCode) {
public static String formatMarketPrice(double price, String currencyCode) {
if (CurrencyUtil.isFiatCurrency(currencyCode))
return formatMarketPrice(price, 2);
else
return formatMarketPrice(price, 8);
}
public String formatMarketPrice(double price, int precision) {
public static String formatMarketPrice(double price, int precision) {
return formatRoundedDoubleWithPrecision(price, precision);
}
@ -460,40 +320,25 @@ public class BSFormatter {
// Other
///////////////////////////////////////////////////////////////////////////////////////////
public String formatRoundedDoubleWithPrecision(double value, int precision) {
public static String formatRoundedDoubleWithPrecision(double value, int precision) {
decimalFormat.setMinimumFractionDigits(precision);
decimalFormat.setMaximumFractionDigits(precision);
return decimalFormat.format(MathUtils.roundDouble(value, precision)).replace(",", ".");
}
public String getDirectionWithCode(OfferPayload.Direction direction, String currencyCode) {
if (CurrencyUtil.isFiatCurrency(currencyCode))
return (direction == OfferPayload.Direction.BUY) ? Res.get("shared.buyCurrency", Res.getBaseCurrencyCode()) : Res.get("shared.sellCurrency", Res.getBaseCurrencyCode());
else
return (direction == OfferPayload.Direction.SELL) ? Res.get("shared.buyCurrency", currencyCode) : Res.get("shared.sellCurrency", currencyCode);
}
public String getDirectionWithCodeDetailed(OfferPayload.Direction direction, String currencyCode) {
public static String getDirectionWithCodeDetailed(OfferPayload.Direction direction, String currencyCode) {
if (CurrencyUtil.isFiatCurrency(currencyCode))
return (direction == OfferPayload.Direction.BUY) ? Res.get("shared.buyingBTCWith", currencyCode) : Res.get("shared.sellingBTCFor", currencyCode);
else
return (direction == OfferPayload.Direction.SELL) ? Res.get("shared.buyingCurrency", currencyCode) : Res.get("shared.sellingCurrency", currencyCode);
}
public String arbitratorAddressesToString(List<NodeAddress> nodeAddresses) {
public static String arbitratorAddressesToString(List<NodeAddress> nodeAddresses) {
return nodeAddresses.stream().map(NodeAddress::getFullAddress).collect(Collectors.joining(", "));
}
public String languageCodesToString(List<String> languageLocales) {
return languageLocales.stream().map(LanguageUtil::getDisplayName).collect(Collectors.joining(", "));
}
public String formatDateTime(Date date) {
return formatDateTime(date, true);
}
public String formatDateTime(Date date, boolean useLocaleAndLocalTimezone) {
Locale locale = useLocaleAndLocalTimezone ? getLocale() : Locale.US;
public static String formatDateTime(Date date, boolean useLocaleAndLocalTimezone) {
Locale locale = useLocaleAndLocalTimezone ? GlobalSettings.getLocale() : Locale.US;
DateFormat dateInstance = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
DateFormat timeInstance = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
if (!useLocaleAndLocalTimezone) {
@ -503,7 +348,7 @@ public class BSFormatter {
return formatDateTime(date, dateInstance, timeInstance);
}
public String formatDateTime(Date date, DateFormat dateFormatter, DateFormat timeFormatter) {
public static String formatDateTime(Date date, DateFormat dateFormatter, DateFormat timeFormatter) {
if (date != null) {
return dateFormatter.format(date) + " " + timeFormatter.format(date);
} else {
@ -511,113 +356,26 @@ public class BSFormatter {
}
}
public String formatDateTimeSpan(Date dateFrom, Date dateTo) {
if (dateFrom != null && dateTo != null) {
DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale());
DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale());
return dateFormatter.format(dateFrom) + " " + timeFormatter.format(dateFrom) + RANGE_SEPARATOR + timeFormatter.format(dateTo);
} else {
return "";
}
}
public String formatTime(Date date) {
if (date != null) {
DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale());
return timeFormatter.format(date);
} else {
return "";
}
}
public String formatDate(Date date) {
if (date != null) {
DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale());
return dateFormatter.format(date);
} else {
return "";
}
}
public String formatToPercentWithSymbol(double value) {
public static String formatToPercentWithSymbol(double value) {
return formatToPercent(value) + "%";
}
public String formatPercentagePrice(double value) {
public static String formatPercentagePrice(double value) {
return formatToPercentWithSymbol(value);
}
public String formatToPercent(double value) {
public static String formatToPercent(double value) {
DecimalFormat decimalFormat = new DecimalFormat("#.##");
decimalFormat.setMinimumFractionDigits(2);
decimalFormat.setMaximumFractionDigits(2);
return decimalFormat.format(MathUtils.roundDouble(value * 100.0, 2)).replace(",", ".");
}
public double parseNumberStringToDouble(String input) throws NumberFormatException {
return Double.parseDouble(cleanDoubleInput(input));
}
public double parsePercentStringToDouble(String percentString) throws NumberFormatException {
String input = percentString.replace("%", "");
input = cleanDoubleInput(input);
double value = Double.parseDouble(input);
return MathUtils.roundDouble(value / 100d, 4);
}
public long parsePriceStringToLong(String currencyCode, String amount, int precision) {
if (amount == null || amount.isEmpty())
return 0;
long value = 0;
try {
double amountValue = Double.parseDouble(amount);
amount = formatRoundedDoubleWithPrecision(amountValue, precision);
value = Price.parse(currencyCode, amount).getValue();
} catch (NumberFormatException ignore) {
// expected NumberFormatException if input is not a number
} catch (Throwable t) {
log.error("parsePriceStringToLong: " + t.toString());
}
return value;
}
public static String convertCharsForNumber(String input) {
// Some languages like finnish use the long dash for the minus
input = input.replace("", "-");
input = StringUtils.deleteWhitespace(input);
return input.replace(",", ".");
}
protected String cleanDoubleInput(String input) {
input = convertCharsForNumber(input);
if (input.equals("."))
input = input.replace(".", "0.");
if (input.equals("-."))
input = input.replace("-.", "-0.");
// don't use String.valueOf(Double.parseDouble(input)) as return value as it gives scientific
// notation (1.0E-6) which screw up coinFormat.parse
//noinspection ResultOfMethodCallIgnored
// Just called to check if we have a valid double, throws exception otherwise
//noinspection ResultOfMethodCallIgnored
Double.parseDouble(input);
return input;
}
public String formatAccountAge(long durationMillis) {
durationMillis = Math.max(0, durationMillis);
String day = Res.get("time.day").toLowerCase();
String days = Res.get("time.days");
String format = "d\' " + days + "\'";
return StringUtils.replaceOnce(DurationFormatUtils.formatDuration(durationMillis, format), "1 " + days, "1 " + day);
}
public String formatDurationAsWords(long durationMillis) {
public static String formatDurationAsWords(long durationMillis) {
return formatDurationAsWords(durationMillis, false, true);
}
public String formatDurationAsWords(long durationMillis, boolean showSeconds, boolean showZeroValues) {
public static String formatDurationAsWords(long durationMillis, boolean showSeconds, boolean showZeroValues) {
String format = "";
String second = Res.get("time.second");
String minute = Res.get("time.minute");
@ -657,77 +415,7 @@ public class BSFormatter {
return duration.trim();
}
public String booleanToYesNo(boolean value) {
return value ? Res.get("shared.yes") : Res.get("shared.no");
}
public String getDirectionBothSides(OfferPayload.Direction direction, String currencyCode) {
if (CurrencyUtil.isFiatCurrency(currencyCode)) {
currencyCode = Res.getBaseCurrencyCode();
return direction == OfferPayload.Direction.BUY ?
Res.get("formatter.makerTaker", currencyCode, Res.get("shared.buyer"), currencyCode, Res.get("shared.seller")) :
Res.get("formatter.makerTaker", currencyCode, Res.get("shared.seller"), currencyCode, Res.get("shared.buyer"));
} else {
return direction == OfferPayload.Direction.SELL ?
Res.get("formatter.makerTaker", currencyCode, Res.get("shared.buyer"), currencyCode, Res.get("shared.seller")) :
Res.get("formatter.makerTaker", currencyCode, Res.get("shared.seller"), currencyCode, Res.get("shared.buyer"));
}
}
public String getDirectionForBuyer(boolean isMyOffer, String currencyCode) {
if (CurrencyUtil.isFiatCurrency(currencyCode)) {
String code = Res.getBaseCurrencyCode();
return isMyOffer ?
Res.get("formatter.youAreAsMaker", Res.get("shared.buying"), code, Res.get("shared.selling"), code) :
Res.get("formatter.youAreAsTaker", Res.get("shared.buying"), code, Res.get("shared.selling"), code);
} else {
return isMyOffer ?
Res.get("formatter.youAreAsMaker", Res.get("shared.selling"), currencyCode, Res.get("shared.buying"), currencyCode) :
Res.get("formatter.youAreAsTaker", Res.get("shared.selling"), currencyCode, Res.get("shared.buying"), currencyCode);
}
}
public String getDirectionForSeller(boolean isMyOffer, String currencyCode) {
if (CurrencyUtil.isFiatCurrency(currencyCode)) {
String code = Res.getBaseCurrencyCode();
return isMyOffer ?
Res.get("formatter.youAreAsMaker", Res.get("shared.selling"), code, Res.get("shared.buying"), code) :
Res.get("formatter.youAreAsTaker", Res.get("shared.selling"), code, Res.get("shared.buying"), code);
} else {
return isMyOffer ?
Res.get("formatter.youAreAsMaker", Res.get("shared.buying"), currencyCode, Res.get("shared.selling"), currencyCode) :
Res.get("formatter.youAreAsTaker", Res.get("shared.buying"), currencyCode, Res.get("shared.selling"), currencyCode);
}
}
public String getDirectionForTakeOffer(OfferPayload.Direction direction, String currencyCode) {
String baseCurrencyCode = Res.getBaseCurrencyCode();
if (CurrencyUtil.isFiatCurrency(currencyCode)) {
return direction == OfferPayload.Direction.BUY ?
Res.get("formatter.youAre", Res.get("shared.selling"), baseCurrencyCode, Res.get("shared.buying"), currencyCode) :
Res.get("formatter.youAre", Res.get("shared.buying"), baseCurrencyCode, Res.get("shared.selling"), currencyCode);
} else {
return direction == OfferPayload.Direction.SELL ?
Res.get("formatter.youAre", Res.get("shared.selling"), currencyCode, Res.get("shared.buying"), baseCurrencyCode) :
Res.get("formatter.youAre", Res.get("shared.buying"), currencyCode, Res.get("shared.selling"), baseCurrencyCode);
}
}
public String getOfferDirectionForCreateOffer(OfferPayload.Direction direction, String currencyCode) {
String baseCurrencyCode = Res.getBaseCurrencyCode();
if (CurrencyUtil.isFiatCurrency(currencyCode)) {
return direction == OfferPayload.Direction.BUY ?
Res.get("formatter.youAreCreatingAnOffer.fiat", Res.get("shared.buy"), baseCurrencyCode) :
Res.get("formatter.youAreCreatingAnOffer.fiat", Res.get("shared.sell"), baseCurrencyCode);
} else {
return direction == OfferPayload.Direction.SELL ?
Res.get("formatter.youAreCreatingAnOffer.altcoin", Res.get("shared.buy"), currencyCode, Res.get("shared.selling"), baseCurrencyCode) :
Res.get("formatter.youAreCreatingAnOffer.altcoin", Res.get("shared.sell"), currencyCode, Res.get("shared.buying"), baseCurrencyCode);
}
}
public String getRole(boolean isBuyerMakerAndSellerTaker, boolean isMaker, String currencyCode) {
public static String getRole(boolean isBuyerMakerAndSellerTaker, boolean isMaker, String currencyCode) {
if (CurrencyUtil.isFiatCurrency(currencyCode)) {
String baseCurrencyCode = Res.getBaseCurrencyCode();
if (isBuyerMakerAndSellerTaker)
@ -751,7 +439,7 @@ public class BSFormatter {
}
public String formatBytes(long bytes) {
public static String formatBytes(long bytes) {
double kb = 1024;
double mb = kb * kb;
DecimalFormat decimalFormat = new DecimalFormat("#.##");
@ -763,47 +451,28 @@ public class BSFormatter {
return decimalFormat.format(bytes / mb) + " MB";
}
public String getCurrencyPair(String currencyCode) {
public static String getCurrencyPair(String currencyCode) {
if (CurrencyUtil.isFiatCurrency(currencyCode))
return Res.getBaseCurrencyCode() + "/" + currencyCode;
else
return currencyCode + "/" + Res.getBaseCurrencyCode();
}
public String getCounterCurrency(String currencyCode) {
public static String getCounterCurrency(String currencyCode) {
if (CurrencyUtil.isFiatCurrency(currencyCode))
return currencyCode;
else
return Res.getBaseCurrencyCode();
}
public String getBaseCurrency(String currencyCode) {
if (CurrencyUtil.isCryptoCurrency(currencyCode))
return currencyCode;
else
return Res.getBaseCurrencyCode();
}
public String getCounterCurrencyAndCurrencyPair(String currencyCode) {
return getCounterCurrency(currencyCode) + " (" + getCurrencyPair(currencyCode) + ")";
}
public String getCurrencyNameAndCurrencyPair(String currencyCode) {
return CurrencyUtil.getNameByCode(currencyCode) + " (" + getCurrencyPair(currencyCode) + ")";
}
public String getPriceWithCurrencyCode(String currencyCode) {
public static String getPriceWithCurrencyCode(String currencyCode) {
return getPriceWithCurrencyCode(currencyCode, "shared.priceInCurForCur");
}
public String getPriceWithCurrencyCode(String currencyCode, String translationKey) {
public static String getPriceWithCurrencyCode(String currencyCode, String translationKey) {
if (CurrencyUtil.isCryptoCurrency(currencyCode))
return Res.get(translationKey, Res.getBaseCurrencyCode(), currencyCode);
else
return Res.get(translationKey, currencyCode, Res.getBaseCurrencyCode());
}
public Locale getLocale() {
return GlobalSettings.getLocale();
}
}

View File

@ -61,12 +61,12 @@ public class BsqFormatter extends BSFormatter {
GlobalSettings.localeProperty().addListener((observable, oldValue, newValue) -> setFormatter(newValue));
setFormatter(GlobalSettings.getLocale());
btcCoinFormat = super.coinFormat;
btcCoinFormat = super.monetaryFormat;
final String baseCurrencyCode = BisqEnvironment.getBaseCurrencyNetwork().getCurrencyCode();
switch (baseCurrencyCode) {
case "BTC":
coinFormat = new MonetaryFormat().shift(6).code(6, "BSQ").minDecimals(2);
monetaryFormat = new MonetaryFormat().shift(6).code(6, "BSQ").minDecimals(2);
break;
default:
throw new RuntimeException("baseCurrencyCode not defined. baseCurrencyCode=" + baseCurrencyCode);
@ -123,11 +123,11 @@ public class BsqFormatter extends BSFormatter {
}
public String formatBSQSatoshis(long satoshi) {
return super.formatCoin(satoshi, coinFormat);
return super.formatCoin(satoshi, monetaryFormat);
}
public String formatBSQSatoshisWithCode(long satoshi) {
return super.formatCoinWithCode(satoshi, coinFormat);
return super.formatCoinWithCode(satoshi, monetaryFormat);
}
public String formatBTCSatoshis(long satoshi) {
@ -147,7 +147,7 @@ public class BsqFormatter extends BSFormatter {
}
public Coin parseToBTC(String input) {
return super.parseToCoin(input, btcCoinFormat);
return ParsingUtils.parseToCoin(input, btcCoinFormat);
}
public void validateBtcInput(String input) throws ProposalValidationException {
@ -155,12 +155,12 @@ public class BsqFormatter extends BSFormatter {
}
public void validateBsqInput(String input) throws ProposalValidationException {
validateCoinInput(input, this.coinFormat);
validateCoinInput(input, this.monetaryFormat);
}
private void validateCoinInput(String input, MonetaryFormat coinFormat) throws ProposalValidationException {
try {
coinFormat.parse(cleanDoubleInput(input));
coinFormat.parse(ParsingUtils.cleanDoubleInput(input));
} catch (Throwable t) {
throw new ProposalValidationException("Invalid format for a " + coinFormat.code() + " value");
}
@ -172,11 +172,11 @@ public class BsqFormatter extends BSFormatter {
// In case we add a new param old clients will not know that enum and fall back to UNDEFINED.
return Res.get("shared.na");
case BSQ:
return formatCoinWithCode(parseToCoin(value));
return formatCoinWithCode(ParsingUtils.parseToCoin(value, this));
case BTC:
return formatBTCWithCode(parseToBTC(value));
case PERCENT:
return formatToPercentWithSymbol(parsePercentStringToDouble(value));
return formatToPercentWithSymbol(ParsingUtils.parsePercentStringToDouble(value));
case BLOCK:
return Res.get("dao.param.blocks", Integer.parseInt(value));
case ADDRESS:
@ -190,7 +190,7 @@ public class BsqFormatter extends BSFormatter {
public Coin parseParamValueToCoin(Param param, String inputValue) {
switch (param.getParamType()) {
case BSQ:
return parseToCoin(inputValue);
return ParsingUtils.parseToCoin(inputValue, this);
case BTC:
return parseToBTC(inputValue);
default:
@ -216,7 +216,7 @@ public class BsqFormatter extends BSFormatter {
case BTC:
return formatBTC(parseParamValueToCoin(param, inputValue));
case PERCENT:
return formatToPercent(parsePercentStringToDouble(inputValue));
return formatToPercent(ParsingUtils.parsePercentStringToDouble(inputValue));
case BLOCK:
return Integer.toString(parseParamValueToBlocks(param, inputValue));
case ADDRESS:

View File

@ -0,0 +1,83 @@
package bisq.core.util;
import bisq.core.monetary.Price;
import bisq.common.util.MathUtils;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.MonetaryFormat;
import org.apache.commons.lang3.StringUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ParsingUtils {
public static Coin parseToCoin(String input, BSFormatter bsFormatter) {
return parseToCoin(input, bsFormatter.getMonetaryFormat());
}
public static Coin parseToCoin(String input, MonetaryFormat coinFormat) {
if (input != null && input.length() > 0) {
try {
return coinFormat.parse(cleanDoubleInput(input));
} catch (Throwable t) {
log.warn("Exception at parseToBtc: " + t.toString());
return Coin.ZERO;
}
} else {
return Coin.ZERO;
}
}
public static double parseNumberStringToDouble(String input) throws NumberFormatException {
return Double.parseDouble(cleanDoubleInput(input));
}
public static double parsePercentStringToDouble(String percentString) throws NumberFormatException {
String input = percentString.replace("%", "");
input = cleanDoubleInput(input);
double value = Double.parseDouble(input);
return MathUtils.roundDouble(value / 100d, 4);
}
public static long parsePriceStringToLong(String currencyCode, String amount, int precision) {
if (amount == null || amount.isEmpty())
return 0;
long value = 0;
try {
double amountValue = Double.parseDouble(amount);
amount = BSFormatter.formatRoundedDoubleWithPrecision(amountValue, precision);
value = Price.parse(currencyCode, amount).getValue();
} catch (NumberFormatException ignore) {
// expected NumberFormatException if input is not a number
} catch (Throwable t) {
log.error("parsePriceStringToLong: " + t.toString());
}
return value;
}
public static String convertCharsForNumber(String input) {
// Some languages like finnish use the long dash for the minus
input = input.replace("", "-");
input = StringUtils.deleteWhitespace(input);
return input.replace(",", ".");
}
public static String cleanDoubleInput(String input) {
input = convertCharsForNumber(input);
if (input.equals("."))
input = input.replace(".", "0.");
if (input.equals("-."))
input = input.replace("-.", "-0.");
// don't use String.valueOf(Double.parseDouble(input)) as return value as it gives scientific
// notation (1.0E-6) which screw up coinFormat.parse
//noinspection ResultOfMethodCallIgnored
// Just called to check if we have a valid double, throws exception otherwise
//noinspection ResultOfMethodCallIgnored
Double.parseDouble(input);
return input;
}
}

View File

@ -506,7 +506,7 @@ takeOffer.failed.offerTaken=You cannot take that offer because the offer was alr
takeOffer.failed.offerRemoved=You cannot take that offer because the offer has been removed in the meantime.
takeOffer.failed.offererNotOnline=Take offer request failed because maker is not online anymore.
takeOffer.failed.offererOffline=You cannot take that offer because the maker is offline.
takeOffer.warning.connectionToPeerLost=You lost connection to the maker.\nHe might have gone offline or has closed the connection to you because of too many open connections.\n\nIf you can still see his offer in the offerbook you can try to take the offer again.
takeOffer.warning.connectionToPeerLost=You lost connection to the maker.\nThey might have gone offline or has closed the connection to you because of too many open connections.\n\nIf you can still see their offer in the offerbook you can try to take the offer again.
takeOffer.error.noFundsLost=\n\nNo funds have left your wallet yet.\nPlease try to restart your application and check your network connection to see if you can resolve the issue.
takeOffer.error.feePaid=\n\nPlease try to restart your application and check your network connection to see if you can resolve the issue.
@ -613,7 +613,7 @@ portfolio.pending.step2_buyer.confirmStart.yes=Yes, I have started the payment
portfolio.pending.step2_seller.waitPayment.headline=Wait for payment
portfolio.pending.step2_seller.f2fInfo.headline=Buyer's contact information
portfolio.pending.step2_seller.waitPayment.msg=The deposit transaction has at least one blockchain confirmation.\nYou need to wait until the BTC buyer starts the {0} payment.
portfolio.pending.step2_seller.warn=The BTC buyer still has not done the {0} payment.\nYou need to wait until they have started the payment.\nThe trade has to be completed by {1}.
portfolio.pending.step2_seller.warn=The BTC buyer still has not done the {0} payment.\nYou need to wait until they have started the payment.\nIf the trade has not been completed on {1} the arbitrator will investigate.
portfolio.pending.step2_seller.openForDispute=The BTC buyer has not started their payment!\nThe max. allowed period for the trade has elapsed.\nYou can wait longer and give the trading peer more time or contact the mediator for assistance.
tradeChat.chatWindowTitle=Chat window for trade with ID ''{0}''
@ -779,7 +779,7 @@ portfolio.pending.mediationRequested=Mediation requested
portfolio.pending.openSupport=Open support ticket
portfolio.pending.supportTicketOpened=Support ticket opened
portfolio.pending.requestSupport=Request support
portfolio.pending.error.requestSupport=Please report the problem to your mediator or arbitrator.\n\nHe will forward the \
portfolio.pending.error.requestSupport=Please report the problem to your mediator or arbitrator.\n\nThey will forward the \
information to the developers to investigate the problem.\nAfter the problem has been analyzed you will \
get back all locked funds.
portfolio.pending.communicateWithArbitrator=Please communicate in the \"Support\" screen with the arbitrator.
@ -910,7 +910,7 @@ support.filter=Filter list
support.filter.prompt=Enter trade ID, date, onion address or account data
support.noTickets=There are no open tickets
support.sendingMessage=Sending Message...
support.receiverNotOnline=Receiver is not online. Message is saved to his mailbox.
support.receiverNotOnline=Receiver is not online. Message is saved to their mailbox.
support.sendMessageError=Sending message failed. Error: {0}
support.wrongVersion=The offer in that dispute has been created with an older version of Bisq.\n\
You cannot close that dispute with your version of the application.\n\n\

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,7 @@ public class ArbitratorTest {
return new Arbitrator(new NodeAddress("host", 1000),
getBytes(100),
"btcaddress",
new PubKeyRing(getBytes(100), getBytes(100), "key"),
new PubKeyRing(getBytes(100), getBytes(100)),
Lists.newArrayList(),
new Date().getTime(),
getBytes(100),
@ -58,4 +58,3 @@ public class ArbitratorTest {
return RandomUtils.nextBytes(count);
}
}

View File

@ -44,7 +44,7 @@ public class MediatorTest {
public static Mediator getMediatorMock() {
return new Mediator(new NodeAddress("host", 1000),
new PubKeyRing(getBytes(100), getBytes(100), "key"),
new PubKeyRing(getBytes(100), getBytes(100)),
Lists.newArrayList(),
new Date().getTime(),
getBytes(100),
@ -53,6 +53,4 @@ public class MediatorTest {
"info",
null);
}
}

View File

@ -22,11 +22,8 @@ import bisq.common.crypto.KeyRing;
import bisq.common.crypto.KeyStorage;
import bisq.common.storage.FileUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.cert.CertificateException;
import java.io.File;
@ -62,5 +59,3 @@ public class EncryptionTest {
}

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
cd $(dirname $0)
tx pull -l de,el_GR,es,ja,pt,ru,zh_CN,vi,th_TH,fa,fr
tx pull -l de,el_GR,es,ja,pt,ru,zh_CN,vi,th_TH,fa,fr,pt_BR
translations="translations/bisq-desktop.displaystringsproperties"
i18n="src/main/resources/i18n"
@ -17,5 +17,6 @@ mv "$translations/vi.properties" "$i18n/displayStrings_vi.properties"
mv "$translations/th_TH.properties" "$i18n/displayStrings_th.properties"
mv "$translations/fa.properties" "$i18n/displayStrings_fa.properties"
mv "$translations/fr.properties" "$i18n/displayStrings_fr.properties"
mv "$translations/pt_BR.properties" "$i18n/displayStrings_pt_BR.properties"
rm -rf $translations

View File

@ -0,0 +1,43 @@
#!/bin/bash
cd $(dirname $0)/../../
mkdir -p deploy
set -e
version="1.1.5-SNAPSHOT"
commithash="ec633f0c3771893b47956b8d05b17c6f3f1919c1"
cd ..
./gradlew :desktop:build -x test shadowJar
cd desktop
EXE_JAR=build/libs/desktop-$version-all.jar
JAR_WITH_HASH_NAME=desktop-$version-$commithash-all.jar
EXE_JAR_WITH_HASH=build/libs/$JAR_WITH_HASH_NAME
DEPLOY_JAR=deploy/$JAR_WITH_HASH_NAME
# we need to strip out Java 9 module configuration used in the fontawesomefx library as it causes the javapackager to stop,
# because of this existing module information, although it is not used as a module.
echo Unzipping jar to delete module config
tmp=build/libs/tmp
unzip -o -q $EXE_JAR -d $tmp
# Sometimes $tmp/module-info.class is not available. TODO check why and if still needed
rm -f $tmp/module-info.class
rm $EXE_JAR
echo Zipping jar again without module config
cd $tmp; zip -r -q -X "../$JAR_WITH_HASH_NAME" *
cd ../../../; rm -rf $tmp
cp $EXE_JAR_WITH_HASH $DEPLOY_JAR
echo Create signature
gpg --digest-algo SHA256 --local-user $BISQ_GPG_USER --output $DEPLOY_JAR.asc --detach-sig --armor $DEPLOY_JAR
echo Verify signatures
gpg --digest-algo SHA256 --verify $DEPLOY_JAR{.asc*,}
open deploy

View File

@ -0,0 +1,43 @@
#!/bin/bash
cd $(dirname $0)/../../
set -e
version="1.1.5-SNAPSHOT"
commithash="ec633f0c3771893b47956b8d05b17c6f3f1919c1"
cd ..
./gradlew :seednode:build -x test shadowJar
cd seednode
mkdir -p deploy
EXE_JAR=build/libs/seednode-all.jar
JAR_WITH_HASH_NAME=seednode-$version-$commithash-all.jar
EXE_JAR_WITH_HASH=build/libs/$JAR_WITH_HASH_NAME
DEPLOY_JAR=deploy/$JAR_WITH_HASH_NAME
# we need to strip out Java 9 module configuration used in the fontawesomefx library as it causes the javapackager to stop,
# because of this existing module information, although it is not used as a module.
echo Unzipping jar to delete module config
tmp=build/libs/tmp
unzip -o -q $EXE_JAR -d $tmp
# Sometimes $tmp/module-info.class is not available. TODO check why and if still needed
rm -f $tmp/module-info.class
rm $EXE_JAR
echo Zipping jar again without module config
cd $tmp; zip -r -q -X "../$JAR_WITH_HASH_NAME" *
cd ../../../; rm -rf $tmp
cp $EXE_JAR_WITH_HASH $DEPLOY_JAR
echo Create signature
gpg --digest-algo SHA256 --local-user $BISQ_GPG_USER --output $DEPLOY_JAR.asc --detach-sig --armor $DEPLOY_JAR
echo Verify signatures
gpg --digest-algo SHA256 --verify $DEPLOY_JAR{.asc*,}
open deploy

View File

@ -18,6 +18,7 @@
package bisq.desktop.components;
import bisq.desktop.main.overlays.editor.PeerInfoWithTagEditor;
import bisq.desktop.util.DisplayUtils;
import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.alert.PrivateNotificationManager;
@ -141,7 +142,7 @@ public class PeerInfoIcon extends Group {
boolean isFiatCurrency = CurrencyUtil.isFiatCurrency(offer.getCurrencyCode());
String accountAge = isFiatCurrency ?
peersAccountAge > -1 ? Res.get("peerInfoIcon.tooltip.age", formatter.formatAccountAge(peersAccountAge)) :
peersAccountAge > -1 ? Res.get("peerInfoIcon.tooltip.age", DisplayUtils.formatAccountAge(peersAccountAge)) :
Res.get("peerInfoIcon.tooltip.unknownAge") :
"";
tooltipText = hasTraded ?
@ -268,7 +269,7 @@ public class PeerInfoIcon extends Group {
long makersAccountAge) {
final String accountAgeTagEditor = isFiatCurrency ?
makersAccountAge > -1 ?
formatter.formatAccountAge(makersAccountAge) :
DisplayUtils.formatAccountAge(makersAccountAge) :
Res.get("peerInfo.unknownAge") :
null;
setOnMouseClicked(e -> new PeerInfoWithTagEditor(privateNotificationManager, offer, preferences, useDevPrivilegeKeys)

View File

@ -21,6 +21,7 @@ import bisq.desktop.components.AutoTooltipCheckBox;
import bisq.desktop.components.InfoTextField;
import bisq.desktop.components.InputTextField;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
@ -182,7 +183,7 @@ public abstract class PaymentMethodForm {
Res.get("payment.maxPeriodAndLimit",
getTimeText(hours),
formatter.formatCoinWithCode(Coin.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrency.getCode()))),
formatter.formatAccountAge(accountAge));
DisplayUtils.formatAccountAge(accountAge));
if (isDisplayForm)
addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.limitations"), limitationsText);

View File

@ -38,6 +38,7 @@ import bisq.desktop.main.portfolio.PortfolioView;
import bisq.desktop.main.settings.SettingsView;
import bisq.desktop.main.shared.PriceFeedComboBoxItem;
import bisq.desktop.main.support.SupportView;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.Transitions;
import bisq.core.dao.monitoring.DaoStateMonitoringService;
@ -523,14 +524,14 @@ public class MainView extends InitializableView<StackPane, MainViewModel>
res = Res.get("mainView.marketPrice.tooltip",
"https://bitcoinaverage.com",
"",
formatter.formatTime(model.getPriceFeedService().getLastRequestTimeStampBtcAverage()),
DisplayUtils.formatTime(model.getPriceFeedService().getLastRequestTimeStampBtcAverage()),
model.getPriceFeedService().getProviderNodeAddress());
} else {
String altcoinExtra = "\n" + Res.get("mainView.marketPrice.tooltip.altcoinExtra");
res = Res.get("mainView.marketPrice.tooltip",
"https://poloniex.com",
altcoinExtra,
formatter.formatTime(model.getPriceFeedService().getLastRequestTimeStampPoloniex()),
DisplayUtils.formatTime(model.getPriceFeedService().getLastRequestTimeStampPoloniex()),
model.getPriceFeedService().getProviderNodeAddress());
}
return res;

View File

@ -33,6 +33,7 @@ import bisq.desktop.main.overlays.windows.downloadupdate.DisplayUpdateDownloadWi
import bisq.desktop.main.presentation.DaoPresentation;
import bisq.desktop.main.presentation.MarketPricePresentation;
import bisq.desktop.main.shared.PriceFeedComboBoxItem;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.account.witness.AccountAgeWitnessService;
@ -218,7 +219,7 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupCompleteList
DontShowAgainLookup.dontShowAgain(key, true);
new Popup<>().warning(Res.get("popup.warning.tradePeriod.halfReached",
trade.getShortId(),
formatter.formatDateTime(maxTradePeriodDate)))
DisplayUtils.formatDateTime(maxTradePeriodDate)))
.show();
}
break;
@ -228,7 +229,7 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupCompleteList
DontShowAgainLookup.dontShowAgain(key, true);
new Popup<>().warning(Res.get("popup.warning.tradePeriod.ended",
trade.getShortId(),
formatter.formatDateTime(maxTradePeriodDate)))
DisplayUtils.formatDateTime(maxTradePeriodDate)))
.show();
}
break;

View File

@ -140,7 +140,7 @@ public class ManageMarketAlertsWindow extends Overlay<ManageMarketAlertsWindow>
public void updateItem(final MarketAlertFilter item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setText(formatter.formatPercentagePrice(item.getTriggerValue() / 10000d));
setText(BSFormatter.formatPercentagePrice(item.getTriggerValue() / 10000d));
} else {
setText("");
}

View File

@ -48,6 +48,7 @@ import bisq.core.provider.price.PriceFeedService;
import bisq.core.user.Preferences;
import bisq.core.user.User;
import bisq.core.util.BSFormatter;
import bisq.core.util.ParsingUtils;
import bisq.core.util.validation.InputValidator;
import bisq.common.UserThread;
@ -347,7 +348,7 @@ public class MobileNotificationsView extends ActivatableView<GridPane, Void> {
private void onAddMarketAlert() {
PaymentAccount paymentAccount = paymentAccountsComboBox.getSelectionModel().getSelectedItem();
double percentAsDouble = formatter.parsePercentStringToDouble(marketAlertTriggerInputTextField.getText());
double percentAsDouble = ParsingUtils.parsePercentStringToDouble(marketAlertTriggerInputTextField.getText());
int triggerValue = (int) Math.round(percentAsDouble * 10000);
boolean isBuyOffer = offerTypeRadioButtonsToggleGroup.getSelectedToggle() == buyOffersRadioButton;
MarketAlertFilter marketAlertFilter = new MarketAlertFilter(paymentAccount, triggerValue, isBuyOffer);
@ -510,8 +511,8 @@ public class MobileNotificationsView extends ActivatableView<GridPane, Void> {
marketAlertTriggerFocusListener = (observable, oldValue, newValue) -> {
if (oldValue && !newValue) {
try {
double percentAsDouble = formatter.parsePercentStringToDouble(marketAlertTriggerInputTextField.getText()) * 100;
marketAlertTriggerInputTextField.setText(formatter.formatRoundedDoubleWithPrecision(percentAsDouble, 2) + "%");
double percentAsDouble = ParsingUtils.parsePercentStringToDouble(marketAlertTriggerInputTextField.getText()) * 100;
marketAlertTriggerInputTextField.setText(BSFormatter.formatRoundedDoubleWithPrecision(percentAsDouble, 2) + "%");
} catch (Throwable ignore) {
}
@ -695,8 +696,8 @@ public class MobileNotificationsView extends ActivatableView<GridPane, Void> {
currencyComboBox.getSelectionModel().select(optionalTradeCurrency.get());
onSelectedTradeCurrency();
priceAlertHighInputTextField.setText(formatter.formatMarketPrice(priceAlertFilter.getHigh() / 10000d, currencyCode));
priceAlertLowInputTextField.setText(formatter.formatMarketPrice(priceAlertFilter.getLow() / 10000d, currencyCode));
priceAlertHighInputTextField.setText(BSFormatter.formatMarketPrice(priceAlertFilter.getHigh() / 10000d, currencyCode));
priceAlertLowInputTextField.setText(BSFormatter.formatMarketPrice(priceAlertFilter.getLow() / 10000d, currencyCode));
} else {
currencyComboBox.getSelectionModel().clearSelection();
}
@ -747,15 +748,15 @@ public class MobileNotificationsView extends ActivatableView<GridPane, Void> {
try {
String inputValue = inputTextField.getText();
if (inputValue != null && !inputValue.isEmpty() && selectedPriceAlertTradeCurrency != null) {
double priceAsDouble = formatter.parseNumberStringToDouble(inputValue);
double priceAsDouble = ParsingUtils.parseNumberStringToDouble(inputValue);
String currencyCode = selectedPriceAlertTradeCurrency;
int precision = CurrencyUtil.isCryptoCurrency(currencyCode) ?
Altcoin.SMALLEST_UNIT_EXPONENT : 2;
// We want to use the converted value not the inout value as we apply the converted value at focus out.
// E.g. if input is 5555.5555 it will be rounded to 5555.55 and we use that as the value for comparing
// low and high price...
String stringValue = formatter.formatRoundedDoubleWithPrecision(priceAsDouble, precision);
return formatter.parsePriceStringToLong(currencyCode, stringValue, precision);
String stringValue = BSFormatter.formatRoundedDoubleWithPrecision(priceAsDouble, precision);
return ParsingUtils.parsePriceStringToLong(currencyCode, stringValue, precision);
} else {
return 0;
}
@ -768,11 +769,11 @@ public class MobileNotificationsView extends ActivatableView<GridPane, Void> {
try {
String inputValue = inputTextField.getText();
if (inputValue != null && !inputValue.isEmpty() && selectedPriceAlertTradeCurrency != null) {
double priceAsDouble = formatter.parseNumberStringToDouble(inputValue);
double priceAsDouble = ParsingUtils.parseNumberStringToDouble(inputValue);
String currencyCode = selectedPriceAlertTradeCurrency;
int precision = CurrencyUtil.isCryptoCurrency(currencyCode) ?
Altcoin.SMALLEST_UNIT_EXPONENT : 2;
String stringValue = formatter.formatRoundedDoubleWithPrecision(priceAsDouble, precision);
String stringValue = BSFormatter.formatRoundedDoubleWithPrecision(priceAsDouble, precision);
inputTextField.setText(stringValue);
}
} catch (Throwable ignore) {

View File

@ -113,7 +113,7 @@ public class BondingViewUtils {
Coin miningFee = miningFeeAndTxSize.first;
int txSize = miningFeeAndTxSize.second;
BSFormatter formatter = new BSFormatter();
String duration = formatter.formatDurationAsWords(lockupTime * 10 * 60 * 1000L, false, false);
String duration = BSFormatter.formatDurationAsWords(lockupTime * 10 * 60 * 1000L, false, false);
new Popup<>().headLine(Res.get("dao.bond.reputation.lockup.headline"))
.confirmation(Res.get("dao.bond.reputation.lockup.details",
bsqFormatter.formatCoinWithCode(lockupAmount),
@ -172,7 +172,7 @@ public class BondingViewUtils {
Coin miningFee = miningFeeAndTxSize.first;
int txSize = miningFeeAndTxSize.second;
BSFormatter formatter = new BSFormatter();
String duration = formatter.formatDurationAsWords(lockTime * 10 * 60 * 1000L, false, false);
String duration = BSFormatter.formatDurationAsWords(lockTime * 10 * 60 * 1000L, false, false);
new Popup<>().headLine(Res.get("dao.bond.reputation.unlock.headline"))
.confirmation(Res.get("dao.bond.reputation.unlock.details",
bsqFormatter.formatCoinWithCode(unlockAmount),

View File

@ -17,6 +17,8 @@
package bisq.desktop.main.dao.bonding.bonds;
import bisq.desktop.util.DisplayUtils;
import bisq.core.dao.governance.bond.Bond;
import bisq.core.dao.governance.bond.BondState;
import bisq.core.dao.governance.bond.role.BondedRole;
@ -58,7 +60,7 @@ class BondListItem {
bondDetails = Utilities.bytesAsHexString(bond.getBondedAsset().getHash());
}
lockupTxId = bond.getLockupTxId();
lockupDateString = bond.getLockupDate() > 0 ? bsqFormatter.formatDateTime(new Date(bond.getLockupDate())) : "-";
lockupDateString = bond.getLockupDate() > 0 ? DisplayUtils.formatDateTime(new Date(bond.getLockupDate())) : "-";
bondState = bond.getBondState();
bondStateString = Res.get("dao.bond.bondState." + bond.getBondState().name());
}

View File

@ -17,6 +17,8 @@
package bisq.desktop.main.dao.bonding.reputation;
import bisq.desktop.util.DisplayUtils;
import bisq.core.dao.governance.bond.BondState;
import bisq.core.dao.governance.bond.reputation.MyBondedReputation;
import bisq.core.dao.governance.bond.reputation.MyReputation;
@ -57,7 +59,7 @@ class MyReputationListItem {
txId = myBondedReputation.getLockupTxId();
amount = bsqFormatter.formatCoin(Coin.valueOf(myBondedReputation.getAmount()));
lockupDate = new Date(myBondedReputation.getLockupDate());
lockupDateString = bsqFormatter.formatDateTime(lockupDate);
lockupDateString = DisplayUtils.formatDateTime(lockupDate);
lockTime = Integer.toString(myBondedReputation.getLockTime());
lockupTxId = myBondedReputation.getLockupTxId();
bondState = myBondedReputation.getBondState();

View File

@ -38,6 +38,7 @@ import bisq.core.dao.governance.bond.reputation.MyBondedReputation;
import bisq.core.locale.Res;
import bisq.core.user.Preferences;
import bisq.core.util.BsqFormatter;
import bisq.core.util.ParsingUtils;
import bisq.core.util.validation.HexStringValidator;
import bisq.core.util.validation.IntegerValidator;
@ -170,7 +171,7 @@ public class MyReputationView extends ActivatableView<GridPane, Void> implements
bsqWalletService.addBsqBalanceListener(this);
lockupButton.setOnAction((event) -> {
Coin lockupAmount = bsqFormatter.parseToCoin(amountInputTextField.getText());
Coin lockupAmount = ParsingUtils.parseToCoin(amountInputTextField.getText(), bsqFormatter);
int lockupTime = Integer.parseInt(timeInputTextField.getText());
byte[] salt = Utilities.decodeFromHex(saltInputTextField.getText());
bondingViewUtils.lockupBondForReputation(lockupAmount,

View File

@ -18,6 +18,7 @@
package bisq.desktop.main.dao.bonding.roles;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.FormBuilder;
import bisq.core.dao.DaoFacade;
@ -97,6 +98,6 @@ class RoleDetailsWindow extends Overlay<RoleDetailsWindow> {
bondedRoleType.getLink(), bondedRoleType.getLink(), 0);
FormBuilder.addTopLabelTextField(gridPane, ++rowIndex, Res.get("dao.bond.details.isSingleton"),
bsqFormatter.booleanToYesNo(bondedRoleType.isAllowMultipleHolders()));
DisplayUtils.booleanToYesNo(bondedRoleType.isAllowMultipleHolders()));
}
}

View File

@ -36,6 +36,7 @@ import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.util.BSFormatter;
import bisq.core.util.BsqFormatter;
import bisq.core.util.ParsingUtils;
import bisq.common.app.DevEnv;
@ -273,7 +274,7 @@ public class AssetFeeView extends ActivatableView<GridPane, Void> implements Bsq
}
private Coin getListingFee() {
return bsqFormatter.parseToCoin(feeAmountInputTextField.getText());
return ParsingUtils.parseToCoin(feeAmountInputTextField.getText(), bsqFormatter);
}
private void doPublishFeeTx(Transaction transaction) {

View File

@ -17,6 +17,8 @@
package bisq.desktop.main.dao.burnbsq.proofofburn;
import bisq.desktop.util.DisplayUtils;
import bisq.core.dao.governance.proofofburn.MyProofOfBurn;
import bisq.core.dao.governance.proofofburn.ProofOfBurnService;
import bisq.core.dao.state.model.blockchain.Tx;
@ -52,7 +54,7 @@ class MyProofOfBurnListItem {
if (optionalTx.isPresent()) {
Tx tx = optionalTx.get();
date = new Date(tx.getTime());
dateAsString = bsqFormatter.formatDateTime(date);
dateAsString = DisplayUtils.formatDateTime(date);
amount = proofOfBurnService.getAmount(tx);
amountAsString = bsqFormatter.formatCoinWithCode(Coin.valueOf(amount));
txId = tx.getId();

View File

@ -17,6 +17,8 @@
package bisq.desktop.main.dao.burnbsq.proofofburn;
import bisq.desktop.util.DisplayUtils;
import bisq.core.dao.governance.proofofburn.ProofOfBurnService;
import bisq.core.dao.state.model.blockchain.Tx;
import bisq.core.util.BsqFormatter;
@ -46,6 +48,6 @@ class ProofOfBurnListItem {
hashAsHex = Utilities.bytesAsHexString(proofOfBurnService.getHashFromOpReturnData(tx));
pubKey = Utilities.bytesAsHexString(proofOfBurnService.getPubKey(txId));
date = new Date(tx.getTime());
dateAsString = bsqFormatter.formatDateTime(date);
dateAsString = DisplayUtils.formatDateTime(date);
}
}

View File

@ -38,6 +38,7 @@ import bisq.core.locale.Res;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;
import bisq.core.util.BsqFormatter;
import bisq.core.util.ParsingUtils;
import bisq.core.util.validation.InputValidator;
import bisq.common.app.DevEnv;
@ -273,7 +274,7 @@ public class ProofOfBurnView extends ActivatableView<GridPane, Void> implements
}
private Coin getAmountFee() {
return bsqFormatter.parseToCoin(amountInputTextField.getText());
return ParsingUtils.parseToCoin(amountInputTextField.getText(), bsqFormatter);
}
private void doPublishFeeTx(Transaction transaction, String preImageAsString) {

View File

@ -34,6 +34,7 @@ import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.statistics.TradeStatistics2;
import bisq.core.trade.statistics.TradeStatisticsManager;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;
import bisq.core.util.BsqFormatter;
import bisq.common.util.MathUtils;
@ -321,7 +322,7 @@ public class BsqDashboardView extends ActivatableView<GridPane, Void> implements
Optional<Price> optionalBsqPrice = priceFeedService.getBsqPrice();
if (optionalBsqPrice.isPresent()) {
Price bsqPrice = optionalBsqPrice.get();
marketPriceLabel.setText(bsqFormatter.formatPrice(bsqPrice) + " BSQ/BTC");
marketPriceLabel.setText(BSFormatter.formatPrice(bsqPrice) + " BSQ/BTC");
marketCapTextField.setText(bsqFormatter.formatMarketCap(priceFeedService.getMarketPrice("BSQ"),
priceFeedService.getMarketPrice(preferences.getPreferredTradeCurrency().getCode()),

View File

@ -52,6 +52,7 @@ import bisq.core.dao.state.model.governance.Role;
import bisq.core.locale.Res;
import bisq.core.util.BSFormatter;
import bisq.core.util.BsqFormatter;
import bisq.core.util.ParsingUtils;
import bisq.asset.Asset;
@ -395,13 +396,13 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
"proposalDisplay.requestedBsqTextField must not be null");
return daoFacade.getCompensationProposalWithTransaction(name,
link,
bsqFormatter.parseToCoin(proposalDisplay.requestedBsqTextField.getText()));
ParsingUtils.parseToCoin(proposalDisplay.requestedBsqTextField.getText(), bsqFormatter));
case REIMBURSEMENT_REQUEST:
checkNotNull(proposalDisplay.requestedBsqTextField,
"proposalDisplay.requestedBsqTextField must not be null");
return daoFacade.getReimbursementProposalWithTransaction(name,
link,
bsqFormatter.parseToCoin(proposalDisplay.requestedBsqTextField.getText()));
ParsingUtils.parseToCoin(proposalDisplay.requestedBsqTextField.getText(), bsqFormatter));
case CHANGE_PARAM:
checkNotNull(proposalDisplay.paramComboBox,
"proposalDisplay.paramComboBox must not be null");

View File

@ -30,6 +30,7 @@ import bisq.desktop.components.TxIdTextField;
import bisq.desktop.main.dao.governance.PhasesView;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.main.overlays.windows.SelectProposalWindow;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.BsqValidator;
@ -54,6 +55,7 @@ import bisq.core.locale.Res;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;
import bisq.core.util.BsqFormatter;
import bisq.core.util.ParsingUtils;
import bisq.common.UserThread;
import bisq.common.app.DevEnv;
@ -462,7 +464,7 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
}
private void onVote() {
Coin stake = bsqFormatter.parseToCoin(stakeInputTextField.getText());
Coin stake = ParsingUtils.parseToCoin(stakeInputTextField.getText(), bsqFormatter);
try {
// We create a dummy tx to get the miningFee for displaying it at the confirmation popup
Tuple2<Coin, Integer> miningFeeAndTxSize = daoFacade.getBlindVoteMiningFeeAndTxSize(stake);
@ -718,7 +720,7 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
public void updateItem(final ProposalsListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(bsqFormatter.formatDateTime(item.getProposal().getCreationDateAsDate()));
setText(DisplayUtils.formatDateTime(item.getProposal().getCreationDateAsDate()));
else
setText("");
}

View File

@ -26,6 +26,7 @@ import bisq.desktop.components.TableGroupHeadline;
import bisq.desktop.main.dao.governance.PhasesView;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.main.overlays.windows.ProposalResultsWindow;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
@ -637,7 +638,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
public void updateItem(final ProposalListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(bsqFormatter.formatDateTime(item.getProposal().getCreationDateAsDate()));
setText(DisplayUtils.formatDateTime(item.getProposal().getCreationDateAsDate()));
else
setText("");
}

View File

@ -47,6 +47,7 @@ import bisq.core.locale.Res;
import bisq.core.util.BSFormatter;
import bisq.core.util.BsqFormatter;
import bisq.core.util.CoinUtil;
import bisq.core.util.ParsingUtils;
import bisq.core.util.validation.BtcAddressValidator;
import bisq.network.p2p.P2PService;
@ -234,7 +235,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
// TODO break up in methods
if (GUIUtil.isReadyForTxBroadcastOrShowPopup(p2PService, walletsSetup)) {
String receiversAddressString = bsqFormatter.getAddressFromBsqAddress(receiversAddressInputTextField.getText()).toString();
Coin receiverAmount = bsqFormatter.parseToCoin(amountInputTextField.getText());
Coin receiverAmount = ParsingUtils.parseToCoin(amountInputTextField.getText(), bsqFormatter);
try {
Transaction preparedSendTx = bsqWalletService.getPreparedSendBsqTx(receiversAddressString, receiverAmount);
Transaction txWithBtcFee = btcWalletService.completePreparedSendBsqTx(preparedSendTx, true);

View File

@ -24,6 +24,7 @@ import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.AutoTooltipTableColumn;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.main.dao.wallet.BsqBalanceUtil;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.GUIUtil;
@ -367,7 +368,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
super.updateItem(item, empty);
if (item != null && !empty) {
setText(bsqFormatter.formatDateTime(item.getDate()));
setText(DisplayUtils.formatDateTime(item.getDate()));
} else {
setText("");
}
@ -630,7 +631,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
style = "dao-tx-type-issuance-icon";
int issuanceBlockHeight = daoFacade.getIssuanceBlockHeight(txId);
long blockTime = daoFacade.getBlockTime(issuanceBlockHeight);
String formattedDate = bsqFormatter.formatDateTime(new Date(blockTime));
String formattedDate = DisplayUtils.formatDateTime(new Date(blockTime));
toolTipText = Res.get("dao.tx.issuanceFromCompReq.tooltip", formattedDate);
} else {
awesomeIcon = AwesomeIcon.FILE_TEXT;
@ -644,7 +645,7 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
style = "dao-tx-type-issuance-icon";
int issuanceBlockHeight = daoFacade.getIssuanceBlockHeight(txId);
long blockTime = daoFacade.getBlockTime(issuanceBlockHeight);
String formattedDate = bsqFormatter.formatDateTime(new Date(blockTime));
String formattedDate = DisplayUtils.formatDateTime(new Date(blockTime));
toolTipText = Res.get("dao.tx.issuanceFromReimbursement.tooltip", formattedDate);
} else {
awesomeIcon = AwesomeIcon.FILE_TEXT;

View File

@ -36,6 +36,7 @@ import bisq.core.locale.Res;
import bisq.core.provider.fee.FeeService;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;
import bisq.core.util.ParsingUtils;
import bisq.common.UserThread;
import bisq.common.app.DevEnv;
@ -232,7 +233,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
walletService.addBalanceListener(balanceListener);
amountTextFieldSubscription = EasyBind.subscribe(amountTextField.textProperty(), t -> {
addressTextField.setAmountAsCoin(formatter.parseToCoin(t));
addressTextField.setAmountAsCoin(ParsingUtils.parseToCoin(t, formatter));
updateQRCode();
});
@ -301,7 +302,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
}
private Coin getAmountAsCoin() {
return formatter.parseToCoin(amountTextField.getText());
return ParsingUtils.parseToCoin(amountTextField.getText(), formatter);
}
@NotNull

View File

@ -23,6 +23,7 @@ import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.btc.listeners.BalanceListener;
@ -228,7 +229,7 @@ public class LockedView extends ActivatableView<VBox, Void> {
super.updateItem(item, empty);
if (item != null && !empty) {
if (getTradable(item).isPresent())
setGraphic(new AutoTooltipLabel(formatter.formatDateTime(getTradable(item).get().getDate())));
setGraphic(new AutoTooltipLabel(DisplayUtils.formatDateTime(getTradable(item).get().getDate())));
else
setGraphic(new AutoTooltipLabel(Res.get("shared.noDateAvailable")));
} else {

View File

@ -23,6 +23,7 @@ import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.btc.listeners.BalanceListener;
@ -228,7 +229,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
super.updateItem(item, empty);
if (item != null && !empty) {
if (getTradable(item).isPresent())
setGraphic(new AutoTooltipLabel(formatter.formatDateTime(getTradable(item).get().getDate())));
setGraphic(new AutoTooltipLabel(DisplayUtils.formatDateTime(getTradable(item).get().getDate())));
else
setGraphic(new AutoTooltipLabel(Res.get("shared.noDateAvailable")));
} else {

View File

@ -18,6 +18,7 @@
package bisq.desktop.main.funds.transactions;
import bisq.desktop.components.indicator.TxConfidenceIndicator;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.btc.listeners.TxConfidenceListener;
@ -239,7 +240,7 @@ class TransactionsListItem {
}
// Use tx.getIncludedInBestChainAt() when available, otherwise use tx.getUpdateTime()
date = transaction.getIncludedInBestChainAt() != null ? transaction.getIncludedInBestChainAt() : transaction.getUpdateTime();
dateString = formatter.formatDateTime(date);
dateString = DisplayUtils.formatDateTime(date);
isDustAttackTx = received && valueSentToMe.value < ignoreDustThreshold;
if (isDustAttackTx) {

View File

@ -41,6 +41,7 @@ import bisq.core.trade.TradeManager;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;
import bisq.core.util.CoinUtil;
import bisq.core.util.ParsingUtils;
import bisq.core.util.validation.BtcAddressValidator;
import bisq.network.p2p.P2PService;
@ -246,7 +247,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
amountListener = (observable, oldValue, newValue) -> {
if (amountTextField.focusedProperty().get()) {
try {
amountAsCoin = formatter.parseToCoin(amountTextField.getText());
amountAsCoin = ParsingUtils.parseToCoin(amountTextField.getText(), formatter);
} catch (Throwable t) {
log.error("Error at amountTextField input. " + t.toString());
}

View File

@ -31,6 +31,7 @@ import bisq.desktop.main.market.trades.TradesChartsView;
import bisq.desktop.main.offer.offerbook.OfferBook;
import bisq.desktop.main.offer.offerbook.OfferBookListItem;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.DisplayUtils;
import bisq.core.locale.Res;
import bisq.core.offer.OfferPayload;
@ -183,11 +184,11 @@ public class MarketView extends ActivatableViewAndModel<TabPane, Activatable> {
.map(trade -> {
StringBuilder sb = new StringBuilder();
sb.append("Trade ID: ").append(trade.getOfferId()).append("\n")
.append("Date: ").append(formatter.formatDateTime(trade.getTradeDate())).append("\n")
.append("Market: ").append(formatter.getCurrencyPair(trade.getCurrencyCode())).append("\n")
.append("Price: ").append(formatter.formatPrice(trade.getTradePrice())).append("\n")
.append("Date: ").append(DisplayUtils.formatDateTime(trade.getTradeDate())).append("\n")
.append("Market: ").append(BSFormatter.getCurrencyPair(trade.getCurrencyCode())).append("\n")
.append("Price: ").append(BSFormatter.formatPrice(trade.getTradePrice())).append("\n")
.append("Amount: ").append(formatter.formatCoin(trade.getTradeAmount())).append("\n")
.append("Volume: ").append(formatter.formatVolume(trade.getTradeVolume())).append("\n")
.append("Volume: ").append(DisplayUtils.formatVolume(trade.getTradeVolume())).append("\n")
.append("Payment method: ").append(Res.get(trade.getOfferPaymentMethod())).append("\n")
.append("ReferralID: ").append(trade.getExtraDataMap().get(OfferPayload.REFERRAL_ID));
return sb.toString();
@ -205,9 +206,9 @@ public class MarketView extends ActivatableViewAndModel<TabPane, Activatable> {
StringBuilder sb = new StringBuilder();
sb.append("Offer ID: ").append(offer.getId()).append("\n")
.append("Type: ").append(offer.getDirection().name()).append("\n")
.append("Market: ").append(formatter.getCurrencyPair(offer.getCurrencyCode())).append("\n")
.append("Price: ").append(formatter.formatPrice(offer.getPrice())).append("\n")
.append("Amount: ").append(formatter.formatAmount(offer)).append(" BTC\n")
.append("Market: ").append(BSFormatter.getCurrencyPair(offer.getCurrencyCode())).append("\n")
.append("Price: ").append(BSFormatter.formatPrice(offer.getPrice())).append("\n")
.append("Amount: ").append(DisplayUtils.formatAmount(offer, formatter)).append(" BTC\n")
.append("Payment method: ").append(Res.get(offer.getPaymentMethod().getId())).append("\n")
.append("ReferralID: ").append(offer.getOfferPayload().getExtraDataMap().get(OfferPayload.REFERRAL_ID));
return sb.toString();

View File

@ -223,15 +223,15 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
public String toString(Number object) {
final double doubleValue = (double) object;
if (CurrencyUtil.isCryptoCurrency(model.getCurrencyCode())) {
final String withCryptoPrecision = formatter.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision);
final String withCryptoPrecision = BSFormatter.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision);
if (withCryptoPrecision.equals("0.000")) {
cryptoPrecision = 8;
return formatter.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision);
return BSFormatter.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision);
} else {
return withCryptoPrecision;
}
} else {
return formatter.formatRoundedDoubleWithPrecision(doubleValue, 2);
return BSFormatter.formatRoundedDoubleWithPrecision(doubleValue, 2);
}
}
@ -268,7 +268,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
priceColumnLabel.set(Res.get("shared.priceWithCur", code));
}
xAxis.setLabel(formatter.getPriceWithCurrencyCode(code));
xAxis.setLabel(BSFormatter.getPriceWithCurrencyCode(code));
seriesBuy.setName(leftHeaderLabel.getText() + " ");
seriesSell.setName(rightHeaderLabel.getText());

View File

@ -26,6 +26,7 @@ import bisq.desktop.main.settings.SettingsView;
import bisq.desktop.main.settings.preferences.PreferencesView;
import bisq.desktop.util.CurrencyList;
import bisq.desktop.util.CurrencyListItem;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.account.witness.AccountAgeWitnessService;
@ -254,7 +255,7 @@ class OfferBookChartViewModel extends ActivatableViewModel {
}
private String formatPrice(Offer offer, boolean decimalAligned) {
return formatter.formatPrice(offer.getPrice(), decimalAligned, offer.isBuyOffer() ? maxPlacesForBuyPrice.get() : maxPlacesForSellPrice.get());
return DisplayUtils.formatPrice(offer.getPrice(), decimalAligned, offer.isBuyOffer() ? maxPlacesForBuyPrice.get() : maxPlacesForSellPrice.get());
}
public String getVolume(Offer offer) {
@ -262,7 +263,7 @@ class OfferBookChartViewModel extends ActivatableViewModel {
}
private String formatVolume(Offer offer, boolean decimalAligned) {
return formatter.formatVolume(offer, decimalAligned, offer.isBuyOffer() ? maxPlacesForBuyVolume.get() : maxPlacesForSellVolume.get(), false);
return DisplayUtils.formatVolume(offer, decimalAligned, offer.isBuyOffer() ? maxPlacesForBuyVolume.get() : maxPlacesForSellVolume.get(), false);
}
///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -185,7 +185,7 @@ class SpreadViewModel extends ActivatableViewModel {
.multiply(BigDecimal.valueOf(10000))
.divide(marketPriceAsBigDecimal, RoundingMode.HALF_UP)
.doubleValue() / 10000;
percentage = formatter.formatPercentagePrice(percentageValue);
percentage = BSFormatter.formatPercentagePrice(percentageValue);
}
} catch (Throwable t) {
try {

View File

@ -27,6 +27,7 @@ import bisq.desktop.components.ColoredDecimalPlacesWithZerosText;
import bisq.desktop.main.market.trades.charts.price.CandleStickChart;
import bisq.desktop.main.market.trades.charts.volume.VolumeChart;
import bisq.desktop.util.CurrencyListItem;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.locale.CurrencyUtil;
@ -239,7 +240,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
String code = selectedTradeCurrency.getCode();
volumeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountWithCur", code)));
priceColumnLabel.set(formatter.getPriceWithCurrencyCode(code));
priceColumnLabel.set(BSFormatter.getPriceWithCurrencyCode(code));
tableView.getColumns().remove(marketColumn);
}
@ -345,9 +346,9 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
double doubleValue = (double) object;
if (CurrencyUtil.isCryptoCurrency(currencyCode)) {
final double value = MathUtils.scaleDownByPowerOf10(doubleValue, 8);
return formatter.formatRoundedDoubleWithPrecision(value, 8);
return BSFormatter.formatRoundedDoubleWithPrecision(value, 8);
} else {
return formatter.formatPrice(Price.valueOf(currencyCode, MathUtils.doubleToLong(doubleValue)));
return BSFormatter.formatPrice(Price.valueOf(currencyCode, MathUtils.doubleToLong(doubleValue)));
}
}
@ -362,9 +363,9 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
public String toString(Number object) {
if (CurrencyUtil.isCryptoCurrency(model.getCurrencyCode())) {
final double value = MathUtils.scaleDownByPowerOf10((long) object, 8);
return formatter.formatRoundedDoubleWithPrecision(value, 8);
return BSFormatter.formatRoundedDoubleWithPrecision(value, 8);
} else {
return formatter.formatPrice(Price.valueOf(model.getCurrencyCode(), (long) object));
return BSFormatter.formatPrice(Price.valueOf(model.getCurrencyCode(), (long) object));
}
}
@ -480,9 +481,9 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
long index = MathUtils.doubleToLong((double) object);
long time = model.getTimeFromTickIndex(index);
if (model.tickUnit.ordinal() <= TradesChartsViewModel.TickUnit.DAY.ordinal())
return index % 4 == 0 ? formatter.formatDate(new Date(time)) : "";
return index % 4 == 0 ? DisplayUtils.formatDate(new Date(time)) : "";
else
return index % 3 == 0 ? formatter.formatTime(new Date(time)) : "";
return index % 3 == 0 ? DisplayUtils.formatTime(new Date(time)) : "";
}
@Override
@ -568,7 +569,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
public void updateItem(final TradeStatistics2 item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(formatter.formatDateTime(item.getTradeDate()));
setText(DisplayUtils.formatDateTime(item.getTradeDate()));
else
setText("");
}
@ -597,7 +598,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
public void updateItem(final TradeStatistics2 item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(formatter.getCurrencyPair(item.getCurrencyCode()));
setText(BSFormatter.getCurrencyPair(item.getCurrencyCode()));
else
setText("");
}
@ -621,7 +622,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
public void updateItem(final TradeStatistics2 item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(formatter.formatPrice(item.getTradePrice()));
setText(BSFormatter.formatPrice(item.getTradePrice()));
else
setText("");
}
@ -671,8 +672,8 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
super.updateItem(item, empty);
if (item != null)
setText(model.showAllTradeCurrenciesProperty.get() ?
formatter.formatVolumeWithCode(item.getTradeVolume()) :
formatter.formatVolume(item.getTradeVolume()));
DisplayUtils.formatVolumeWithCode(item.getTradeVolume()) :
DisplayUtils.formatVolume(item.getTradeVolume()));
else
setText("");
}
@ -744,7 +745,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
@NotNull
private String getDirectionLabel(TradeStatistics2 item) {
return formatter.getDirectionWithCode(OfferPayload.Direction.valueOf(item.getDirection().name()), item.getCurrencyCode());
return DisplayUtils.getDirectionWithCode(OfferPayload.Direction.valueOf(item.getDirection().name()), item.getCurrencyCode());
}
@NotNull

View File

@ -25,6 +25,7 @@ import bisq.desktop.main.settings.SettingsView;
import bisq.desktop.main.settings.preferences.PreferencesView;
import bisq.desktop.util.CurrencyList;
import bisq.desktop.util.CurrencyListItem;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.locale.CryptoCurrency;
@ -345,8 +346,8 @@ class TradesChartsViewModel extends ActivatableViewModel {
final Date dateFrom = new Date(getTimeFromTickIndex(tick));
final Date dateTo = new Date(getTimeFromTickIndex(tick + 1));
String dateString = tickUnit.ordinal() > TickUnit.DAY.ordinal() ?
formatter.formatDateTimeSpan(dateFrom, dateTo) :
formatter.formatDate(dateFrom) + " - " + formatter.formatDate(dateTo);
DisplayUtils.formatDateTimeSpan(dateFrom, dateTo) :
DisplayUtils.formatDate(dateFrom) + " - " + DisplayUtils.formatDate(dateTo);
return new CandleData(tick, open, close, high, low, averagePrice, medianPrice, accumulatedAmount, accumulatedVolume,
numTrades, isBullish, dateString);
}

View File

@ -18,6 +18,7 @@
package bisq.desktop.main.offer;
import bisq.desktop.Navigation;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.account.witness.AccountAgeRestrictions;
@ -642,7 +643,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
!price.get().isZero() &&
allowAmountUpdate) {
try {
Coin value = btcFormatter.reduceTo4Decimals(price.get().getAmountByVolume(volume.get()));
Coin value = DisplayUtils.reduceTo4Decimals(price.get().getAmountByVolume(volume.get()), btcFormatter);
if (isHalCashAccount())
value = OfferUtil.getAdjustedAmountForHalCash(value, price.get(), getMaxTradeLimit());
else if (CurrencyUtil.isFiatCurrency(tradeCurrencyCode.get()))

View File

@ -565,11 +565,11 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel> extends
///////////////////////////////////////////////////////////////////////////////////////////
private void addBindings() {
priceCurrencyLabel.textProperty().bind(createStringBinding(() -> btcFormatter.getCounterCurrency(model.tradeCurrencyCode.get()), model.tradeCurrencyCode));
priceCurrencyLabel.textProperty().bind(createStringBinding(() -> BSFormatter.getCounterCurrency(model.tradeCurrencyCode.get()), model.tradeCurrencyCode));
marketBasedPriceLabel.prefWidthProperty().bind(priceCurrencyLabel.widthProperty());
volumeCurrencyLabel.textProperty().bind(model.tradeCurrencyCode);
priceDescriptionLabel.textProperty().bind(createStringBinding(() -> btcFormatter.getPriceWithCurrencyCode(model.tradeCurrencyCode.get(), "shared.fixedPriceInCurForCur"), model.tradeCurrencyCode));
priceDescriptionLabel.textProperty().bind(createStringBinding(() -> BSFormatter.getPriceWithCurrencyCode(model.tradeCurrencyCode.get(), "shared.fixedPriceInCurForCur"), model.tradeCurrencyCode));
volumeDescriptionLabel.textProperty().bind(createStringBinding(model.volumeDescriptionLabel::get, model.tradeCurrencyCode, model.volumeDescriptionLabel));
amountTextField.textProperty().bindBidirectional(model.amount);
minAmountTextField.textProperty().bindBidirectional(model.minAmount);

View File

@ -25,6 +25,7 @@ import bisq.desktop.main.funds.deposit.DepositView;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.main.settings.SettingsView;
import bisq.desktop.main.settings.preferences.PreferencesView;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.validation.AltcoinValidator;
import bisq.desktop.util.validation.BsqValidator;
@ -51,6 +52,7 @@ import bisq.core.provider.price.PriceFeedService;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;
import bisq.core.util.BsqFormatter;
import bisq.core.util.ParsingUtils;
import bisq.core.util.validation.InputValidator;
import bisq.common.Timer;
@ -306,7 +308,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (marketPrice != null && marketPrice.isRecentExternalPriceAvailable()) {
double marketPriceAsDouble = marketPrice.getPrice();
try {
double priceAsDouble = btcFormatter.parseNumberStringToDouble(price.get());
double priceAsDouble = ParsingUtils.parseNumberStringToDouble(price.get());
double relation = priceAsDouble / marketPriceAsDouble;
final OfferPayload.Direction compareDirection = CurrencyUtil.isCryptoCurrency(currencyCode) ?
OfferPayload.Direction.SELL :
@ -314,7 +316,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
double percentage = dataModel.getDirection() == compareDirection ? 1 - relation : relation - 1;
percentage = MathUtils.roundDouble(percentage, 4);
dataModel.setMarketPriceMargin(percentage);
marketPriceMargin.set(btcFormatter.formatToPercent(percentage));
marketPriceMargin.set(BSFormatter.formatToPercent(percentage));
applyMakerFee();
} catch (NumberFormatException t) {
marketPriceMargin.set("");
@ -332,7 +334,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (inputIsMarketBasedPrice) {
try {
if (!newValue.isEmpty() && !newValue.equals("-")) {
double percentage = btcFormatter.parsePercentStringToDouble(newValue);
double percentage = ParsingUtils.parsePercentStringToDouble(newValue);
if (percentage >= 1 || percentage <= -1) {
new Popup<>().warning(Res.get("popup.warning.tooLargePercentageValue") + "\n" +
Res.get("popup.warning.examplePercentageValue"))
@ -355,7 +357,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
Altcoin.SMALLEST_UNIT_EXPONENT : Fiat.SMALLEST_UNIT_EXPONENT;
// protect from triggering unwanted updates
ignorePriceStringListener = true;
price.set(btcFormatter.formatRoundedDoubleWithPrecision(targetPrice, precision));
price.set(BSFormatter.formatRoundedDoubleWithPrecision(targetPrice, precision));
ignorePriceStringListener = false;
setPriceToModel();
dataModel.setMarketPriceMargin(percentage);
@ -432,7 +434,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
priceListener = (ov, oldValue, newValue) -> {
ignorePriceStringListener = true;
if (newValue != null)
price.set(btcFormatter.formatPrice(newValue));
price.set(BSFormatter.formatPrice(newValue));
else
price.set("");
@ -442,7 +444,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
volumeListener = (ov, oldValue, newValue) -> {
ignoreVolumeStringListener = true;
if (newValue != null)
volume.set(btcFormatter.formatVolume(newValue));
volume.set(DisplayUtils.formatVolume(newValue));
else
volume.set("");
@ -452,7 +454,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
securityDepositAsDoubleListener = (ov, oldValue, newValue) -> {
if (newValue != null) {
buyerSecurityDeposit.set(btcFormatter.formatToPercent((double) newValue));
buyerSecurityDeposit.set(BSFormatter.formatToPercent((double) newValue));
if (dataModel.getAmount().get() != null)
buyerSecurityDepositInBTC.set(btcFormatter.formatCoinWithCode(dataModel.getBuyerSecurityDepositAsCoin()));
} else {
@ -483,7 +485,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
Coin makerFeeInBtc = dataModel.getMakerFeeInBtc();
Optional<Volume> optionalBtcFeeInFiat = OfferUtil.getFeeInUserFiatCurrency(makerFeeInBtc,
true, preferences, priceFeedService, bsqFormatter);
String btcFeeWithFiatAmount = OfferUtil.getFeeWithFiatAmount(makerFeeInBtc, optionalBtcFeeInFiat, btcFormatter);
String btcFeeWithFiatAmount = DisplayUtils.getFeeWithFiatAmount(makerFeeInBtc, optionalBtcFeeInFiat, btcFormatter);
if (DevEnv.isDaoActivated()) {
tradeFeeInBtcWithFiat.set(btcFeeWithFiatAmount);
} else {
@ -493,14 +495,14 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
Coin makerFeeInBsq = dataModel.getMakerFeeInBsq();
Optional<Volume> optionalBsqFeeInFiat = OfferUtil.getFeeInUserFiatCurrency(makerFeeInBsq,
false, preferences, priceFeedService, bsqFormatter);
String bsqFeeWithFiatAmount = OfferUtil.getFeeWithFiatAmount(makerFeeInBsq, optionalBsqFeeInFiat, bsqFormatter);
String bsqFeeWithFiatAmount = DisplayUtils.getFeeWithFiatAmount(makerFeeInBsq, optionalBsqFeeInFiat, bsqFormatter);
if (DevEnv.isDaoActivated()) {
tradeFeeInBsqWithFiat.set(bsqFeeWithFiatAmount);
} else {
// Before DAO is enabled we show fee as fiat and % in second line
String feeInFiatAsString;
if (optionalBtcFeeInFiat != null && optionalBtcFeeInFiat.isPresent()) {
feeInFiatAsString = btcFormatter.formatVolumeWithCode(optionalBtcFeeInFiat.get());
feeInFiatAsString = DisplayUtils.formatVolumeWithCode(optionalBtcFeeInFiat.get());
} else {
feeInFiatAsString = Res.get("shared.na");
}
@ -511,7 +513,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
tradeFeeInBsqWithFiat.set(Res.get("createOffer.tradeFee.fiatAndPercent",
feeInFiatAsString,
btcFormatter.formatToPercentWithSymbol(percent)));
BSFormatter.formatToPercentWithSymbol(percent)));
}
}
tradeFeeCurrencyCode.set(dataModel.isCurrencyForMakerFeeBtc() ? Res.getBaseCurrencyCode() : "BSQ");
@ -592,7 +594,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
isBuy ? Res.get("shared.buy") : Res.get("shared.sell"));
securityDepositValidator.setPaymentAccount(dataModel.paymentAccount);
buyerSecurityDeposit.set(btcFormatter.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
buyerSecurityDeposit.set(BSFormatter.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
buyerSecurityDepositLabel.set(getSecurityDepositLabel());
applyMakerFee();
@ -748,7 +750,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (dataModel.getMinVolume().get() != null) {
InputValidator.ValidationResult minVolumeResult = isVolumeInputValid(
btcFormatter.formatVolume(dataModel.getMinVolume().get()));
DisplayUtils.formatVolume(dataModel.getMinVolume().get()));
volumeValidationResult.set(minVolumeResult);
@ -779,7 +781,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
setPriceToModel();
ignorePriceStringListener = true;
if (dataModel.getPrice().get() != null)
price.set(btcFormatter.formatPrice(dataModel.getPrice().get()));
price.set(BSFormatter.formatPrice(dataModel.getPrice().get()));
ignorePriceStringListener = false;
dataModel.calculateVolume();
dataModel.calculateAmount();
@ -803,7 +805,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
// field wasn't set manually
inputIsMarketBasedPrice = true;
}
marketPriceMargin.set(btcFormatter.formatRoundedDoubleWithPrecision(dataModel.getMarketPriceMargin() * 100, 2));
marketPriceMargin.set(BSFormatter.formatRoundedDoubleWithPrecision(dataModel.getMarketPriceMargin() * 100, 2));
// We want to trigger a recalculation of the volume
UserThread.execute(() -> {
@ -827,7 +829,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
else if (CurrencyUtil.isFiatCurrency(tradeCurrencyCode.get()))
volume = OfferUtil.getRoundedFiatVolume(volume);
this.volume.set(btcFormatter.formatVolume(volume));
this.volume.set(DisplayUtils.formatVolume(volume));
}
ignoreVolumeStringListener = false;
@ -856,20 +858,20 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (result.isValid) {
double defaultSecurityDeposit = Restrictions.getDefaultBuyerSecurityDepositAsPercent(getPaymentAccount());
String key = "buyerSecurityDepositIsLowerAsDefault";
double depositAsDouble = btcFormatter.parsePercentStringToDouble(buyerSecurityDeposit.get());
double depositAsDouble = ParsingUtils.parsePercentStringToDouble(buyerSecurityDeposit.get());
if (preferences.showAgain(key) && depositAsDouble < defaultSecurityDeposit) {
String postfix = dataModel.isBuyOffer() ?
Res.get("createOffer.tooLowSecDeposit.makerIsBuyer") :
Res.get("createOffer.tooLowSecDeposit.makerIsSeller");
new Popup<>()
.warning(Res.get("createOffer.tooLowSecDeposit.warning",
btcFormatter.formatToPercentWithSymbol(defaultSecurityDeposit)) + "\n\n" + postfix)
BSFormatter.formatToPercentWithSymbol(defaultSecurityDeposit)) + "\n\n" + postfix)
.width(800)
.actionButtonText(Res.get("createOffer.resetToDefault"))
.onAction(() -> {
dataModel.setBuyerSecurityDeposit(defaultSecurityDeposit);
ignoreSecurityDepositStringListener = true;
buyerSecurityDeposit.set(btcFormatter.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
buyerSecurityDeposit.set(BSFormatter.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
ignoreSecurityDepositStringListener = false;
})
.closeButtonText(Res.get("createOffer.useLowerValue"))
@ -886,7 +888,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void applyBuyerSecurityDepositOnFocusOut() {
setBuyerSecurityDepositToModel();
ignoreSecurityDepositStringListener = true;
buyerSecurityDeposit.set(btcFormatter.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
buyerSecurityDeposit.set(BSFormatter.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
ignoreSecurityDepositStringListener = false;
}
@ -896,7 +898,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
public boolean isPriceInRange() {
if (marketPriceMargin.get() != null && !marketPriceMargin.get().isEmpty()) {
if (Math.abs(btcFormatter.parsePercentStringToDouble(marketPriceMargin.get())) > preferences.getMaxPriceDistanceInPercent()) {
if (Math.abs(ParsingUtils.parsePercentStringToDouble(marketPriceMargin.get())) > preferences.getMaxPriceDistanceInPercent()) {
displayPriceOutOfRangePopup();
return false;
} else {
@ -910,7 +912,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void displayPriceOutOfRangePopup() {
Popup popup = new Popup<>();
popup.warning(Res.get("createOffer.priceOutSideOfDeviation",
btcFormatter.formatToPercentWithSymbol(preferences.getMaxPriceDistanceInPercent())))
BSFormatter.formatToPercentWithSymbol(preferences.getMaxPriceDistanceInPercent())))
.actionButtonText(Res.get("createOffer.changePrice"))
.onAction(popup::hide)
.closeButtonTextWithGoTo("navigation.settings.preferences")
@ -1042,7 +1044,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void setAmountToModel() {
if (amount.get() != null && !amount.get().isEmpty()) {
Coin amount = btcFormatter.parseToCoinWith4Decimals(this.amount.get());
Coin amount = DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), btcFormatter);
long maxTradeLimit = dataModel.getMaxTradeLimit();
Price price = dataModel.getPrice().get();
@ -1066,7 +1068,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void setMinAmountToModel() {
if (minAmount.get() != null && !minAmount.get().isEmpty()) {
Coin minAmount = btcFormatter.parseToCoinWith4Decimals(this.minAmount.get());
Coin minAmount = DisplayUtils.parseToCoinWith4Decimals(this.minAmount.get(), btcFormatter);
Price price = dataModel.getPrice().get();
long maxTradeLimit = dataModel.getMaxTradeLimit();
@ -1109,7 +1111,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void setBuyerSecurityDepositToModel() {
if (buyerSecurityDeposit.get() != null && !buyerSecurityDeposit.get().isEmpty()) {
dataModel.setBuyerSecurityDeposit(btcFormatter.parsePercentStringToDouble(buyerSecurityDeposit.get()));
dataModel.setBuyerSecurityDeposit(ParsingUtils.parsePercentStringToDouble(buyerSecurityDeposit.get()));
} else {
dataModel.setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent(getPaymentAccount()));
}
@ -1168,7 +1170,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
dataModel.getPrice().get() != null &&
dataModel.getPrice().get().getValue() != 0 &&
isVolumeInputValid(volume.get()).isValid &&
isVolumeInputValid(btcFormatter.formatVolume(dataModel.getMinVolume().get())).isValid &&
isVolumeInputValid(DisplayUtils.formatVolume(dataModel.getMinVolume().get())).isValid &&
dataModel.isMinAmountLessOrEqualAmount();
isNextButtonDisabled.set(!inputDataValid);
@ -1187,4 +1189,5 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private BSFormatter getFormatterForMakerFee() {
return dataModel.isCurrencyForMakerFeeBtc() ? btcFormatter : bsqFormatter;
}
}

View File

@ -37,6 +37,7 @@ import bisq.desktop.main.funds.withdrawal.WithdrawalView;
import bisq.desktop.main.offer.OfferView;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
@ -226,8 +227,8 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
tableView.setPlaceholder(placeholder);
marketColumn.setComparator((o1, o2) -> {
String str1 = formatter.getCurrencyPair(o1.getOffer().getCurrencyCode());
String str2 = formatter.getCurrencyPair(o2.getOffer().getCurrencyCode());
String str1 = BSFormatter.getCurrencyPair(o1.getOffer().getCurrencyCode());
String str2 = BSFormatter.getCurrencyPair(o2.getOffer().getCurrencyCode());
return str1 != null && str2 != null ? str1.compareTo(str2) : 0;
});
priceColumn.setComparator((o1, o2) -> {
@ -324,7 +325,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
tableView.getColumns().add(0, marketColumn);
} else {
volumeColumn.setTitleWithHelpText(Res.get("offerbook.volume", code), Res.get("shared.amountHelp"));
priceColumn.setTitle(formatter.getPriceWithCurrencyCode(code));
priceColumn.setTitle(BSFormatter.getPriceWithCurrencyCode(code));
priceColumn.getStyleClass().add("first-column");
tableView.getColumns().remove(marketColumn);
@ -570,7 +571,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
final long tradeLimit = model.accountAgeWitnessService.getMyTradeLimit(account.get(), offer.getCurrencyCode());
new Popup<>()
.warning(Res.get("offerbook.warning.tradeLimitNotMatching",
formatter.formatAccountAge(model.accountAgeWitnessService.getMyAccountAge(account.get().getPaymentAccountPayload())),
DisplayUtils.formatAccountAge(model.accountAgeWitnessService.getMyAccountAge(account.get().getPaymentAccountPayload())),
formatter.formatCoinWithCode(Coin.valueOf(tradeLimit)),
formatter.formatCoinWithCode(offer.getMinAmount())))
.show();
@ -687,7 +688,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
super.updateItem(item, empty);
if (item != null && !empty)
setText(formatter.getCurrencyPair(item.getOffer().getCurrencyCode()));
setText(BSFormatter.getCurrencyPair(item.getOffer().getCurrencyCode()));
else
setText("");
}

View File

@ -22,6 +22,7 @@ import bisq.desktop.common.model.ActivatableViewModel;
import bisq.desktop.main.MainView;
import bisq.desktop.main.settings.SettingsView;
import bisq.desktop.main.settings.preferences.PreferencesView;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.account.witness.AccountAgeWitnessService;
@ -340,7 +341,7 @@ class OfferBookViewModel extends ActivatableViewModel {
}
private String formatAmount(Offer offer, boolean decimalAligned) {
return formatter.formatAmount(offer, GUIUtil.AMOUNT_DECIMALS, decimalAligned, maxPlacesForAmount.get());
return DisplayUtils.formatAmount(offer, GUIUtil.AMOUNT_DECIMALS, decimalAligned, maxPlacesForAmount.get(), formatter);
}
@ -358,22 +359,22 @@ class OfferBookViewModel extends ActivatableViewModel {
}
String getAbsolutePriceMargin(Offer offer) {
return formatter.formatPercentagePrice(Math.abs(offer.getMarketPriceMargin()));
return BSFormatter.formatPercentagePrice(Math.abs(offer.getMarketPriceMargin()));
}
private String formatPrice(Offer offer, boolean decimalAligned) {
return formatter.formatPrice(offer.getPrice(), decimalAligned, maxPlacesForPrice.get());
return DisplayUtils.formatPrice(offer.getPrice(), decimalAligned, maxPlacesForPrice.get());
}
private String formatMarketPriceMargin(Offer offer, boolean decimalAligned) {
String postFix = "";
if (offer.isUseMarketBasedPrice()) {
postFix = " (" + formatter.formatPercentagePrice(offer.getMarketPriceMargin()) + ")";
postFix = " (" + BSFormatter.formatPercentagePrice(offer.getMarketPriceMargin()) + ")";
}
if (decimalAligned) {
postFix = formatter.fillUpPlacesWithEmptyStrings(postFix, maxPlacesForMarketPriceMargin.get());
postFix = BSFormatter.fillUpPlacesWithEmptyStrings(postFix, maxPlacesForMarketPriceMargin.get());
}
return postFix;
@ -389,7 +390,7 @@ class OfferBookViewModel extends ActivatableViewModel {
if (offerVolume != null && minOfferVolume != null) {
String postFix = showAllTradeCurrenciesProperty.get() ? " " + offer.getCurrencyCode() : "";
decimalAligned = decimalAligned && !showAllTradeCurrenciesProperty.get();
return formatter.formatVolume(offer, decimalAligned, maxPlacesForVolume.get()) + postFix;
return DisplayUtils.formatVolume(offer, decimalAligned, maxPlacesForVolume.get()) + postFix;
} else {
return Res.get("shared.na");
}
@ -470,7 +471,7 @@ class OfferBookViewModel extends ActivatableViewModel {
}
String getDirectionLabelTooltip(Offer offer) {
return formatter.getDirectionWithCodeDetailed(offer.getMirroredDirection(), offer.getCurrencyCode());
return BSFormatter.getDirectionWithCodeDetailed(offer.getMirroredDirection(), offer.getCurrencyCode());
}
Optional<PaymentAccount> getMostMaturePaymentAccountForOffer(Offer offer) {

View File

@ -372,7 +372,7 @@ class TakeOfferDataModel extends OfferDataModel {
feeTxSize = 380;
txFeeFromFeeService = txFeePerByteFromFeeService.multiply(feeTxSize);
log.info("We cannot do the fee estimation because there are no funds in the wallet.\nThis is expected " +
"if the user has not funded his wallet yet.\n" +
"if the user has not funded their wallet yet.\n" +
"In that case we use an estimated tx size of 380 bytes.\n" +
"txFee based on estimated size of {} bytes. feeTxSize = {} bytes. Actual tx size = {} bytes. TxFee is {} ({} sat/byte)",
feeTxSize, feeTxSize, txSize, txFeeFromFeeService.toFriendlyString(), feeService.getTxFeePerByte());

View File

@ -278,7 +278,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
String currencyCode = model.dataModel.getCurrencyCode();
volumeCurrencyLabel.setText(currencyCode);
priceDescriptionLabel.setText(formatter.getPriceWithCurrencyCode(currencyCode));
priceDescriptionLabel.setText(BSFormatter.getPriceWithCurrencyCode(currencyCode));
volumeDescriptionLabel.setText(model.volumeDescriptionLabel.get());
if (model.getPossiblePaymentAccounts().size() > 1) {
@ -606,7 +606,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
totalToPayTextField.textProperty().bind(model.totalToPay);
addressTextField.amountAsCoinProperty().bind(model.dataModel.getMissingCoin());
amountTextField.validationResultProperty().bind(model.amountValidationResult);
priceCurrencyLabel.textProperty().bind(createStringBinding(() -> formatter.getCounterCurrency(model.dataModel.getCurrencyCode())));
priceCurrencyLabel.textProperty().bind(createStringBinding(() -> BSFormatter.getCounterCurrency(model.dataModel.getCurrencyCode())));
priceAsPercentageLabel.prefWidthProperty().bind(priceCurrencyLabel.widthProperty());
nextButton.disableProperty().bind(model.isNextButtonDisabled);
tradeFeeInBtcLabel.textProperty().bind(model.tradeFeeInBtcWithFiat);

View File

@ -24,6 +24,7 @@ import bisq.desktop.main.MainView;
import bisq.desktop.main.funds.FundsView;
import bisq.desktop.main.funds.deposit.DepositView;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.validation.BtcValidator;
@ -205,8 +206,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
}
amountRange = btcFormatter.formatCoin(offer.getMinAmount()) + " - " + btcFormatter.formatCoin(offer.getAmount());
price = btcFormatter.formatPrice(dataModel.tradePrice);
marketPriceMargin = btcFormatter.formatToPercent(offer.getMarketPriceMargin());
price = BSFormatter.formatPrice(dataModel.tradePrice);
marketPriceMargin = BSFormatter.formatToPercent(offer.getMarketPriceMargin());
paymentLabel = Res.get("takeOffer.fundsBox.paymentLabel", offer.getShortId());
checkNotNull(dataModel.getAddressEntry(), "dataModel.getAddressEntry() must not be null");
@ -288,7 +289,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
Coin makerFeeInBtc = dataModel.getTakerFeeInBtc();
Optional<Volume> optionalBtcFeeInFiat = OfferUtil.getFeeInUserFiatCurrency(makerFeeInBtc,
true, preferences, priceFeedService, bsqFormatter);
String btcFeeWithFiatAmount = OfferUtil.getFeeWithFiatAmount(makerFeeInBtc, optionalBtcFeeInFiat, btcFormatter);
String btcFeeWithFiatAmount = DisplayUtils.getFeeWithFiatAmount(makerFeeInBtc, optionalBtcFeeInFiat, btcFormatter);
if (DevEnv.isDaoActivated()) {
tradeFeeInBtcWithFiat.set(btcFeeWithFiatAmount);
} else {
@ -298,14 +299,14 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
Coin makerFeeInBsq = dataModel.getTakerFeeInBsq();
Optional<Volume> optionalBsqFeeInFiat = OfferUtil.getFeeInUserFiatCurrency(makerFeeInBsq,
false, preferences, priceFeedService, bsqFormatter);
String bsqFeeWithFiatAmount = OfferUtil.getFeeWithFiatAmount(makerFeeInBsq, optionalBsqFeeInFiat, bsqFormatter);
String bsqFeeWithFiatAmount = DisplayUtils.getFeeWithFiatAmount(makerFeeInBsq, optionalBsqFeeInFiat, bsqFormatter);
if (DevEnv.isDaoActivated()) {
tradeFeeInBsqWithFiat.set(bsqFeeWithFiatAmount);
} else {
// Before DAO is enabled we show fee as fiat and % in second line
String feeInFiatAsString;
if (optionalBtcFeeInFiat != null && optionalBtcFeeInFiat.isPresent()) {
feeInFiatAsString = btcFormatter.formatVolumeWithCode(optionalBtcFeeInFiat.get());
feeInFiatAsString = DisplayUtils.formatVolumeWithCode(optionalBtcFeeInFiat.get());
} else {
feeInFiatAsString = Res.get("shared.na");
}
@ -316,7 +317,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
tradeFeeInBsqWithFiat.set(Res.get("createOffer.tradeFee.fiatAndPercent",
feeInFiatAsString,
btcFormatter.formatToPercentWithSymbol(percent)));
BSFormatter.formatToPercentWithSymbol(percent)));
}
}
tradeFeeDescription.set(DevEnv.isDaoActivated() ? Res.get("createOffer.tradeFee.descriptionBSQEnabled") :
@ -334,7 +335,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
InputValidator.ValidationResult result = isBtcInputValid(amount.get());
amountValidationResult.set(result);
if (result.isValid) {
showWarningInvalidBtcDecimalPlaces.set(!btcFormatter.hasBtcValidDecimals(userInput));
showWarningInvalidBtcDecimalPlaces.set(!DisplayUtils.hasBtcValidDecimals(userInput, btcFormatter));
// only allow max 4 decimal places for btc values
setAmountToModel();
// reformat input
@ -503,7 +504,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
///////////////////////////////////////////////////////////////////////////////////////////
private void addBindings() {
volume.bind(createStringBinding(() -> btcFormatter.formatVolume(dataModel.volume.get()), dataModel.volume));
volume.bind(createStringBinding(() -> DisplayUtils.formatVolume(dataModel.volume.get()), dataModel.volume));
if (dataModel.getDirection() == OfferPayload.Direction.SELL) {
volumeDescriptionLabel.set(Res.get("createOffer.amountPriceBox.buy.volumeDescription", dataModel.getCurrencyCode()));
@ -626,7 +627,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
private void setAmountToModel() {
if (amount.get() != null && !amount.get().isEmpty()) {
Coin amount = btcFormatter.parseToCoinWith4Decimals(this.amount.get());
Coin amount = DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), btcFormatter);
long maxTradeLimit = dataModel.getMaxTradeLimit();
Price price = dataModel.tradePrice;
if (price != null) {

View File

@ -20,6 +20,7 @@ package bisq.desktop.main.overlays.windows;
import bisq.desktop.components.BisqTextArea;
import bisq.desktop.main.MainView;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.Layout;
import bisq.core.account.witness.AccountAgeWitnessService;
@ -140,16 +141,16 @@ public class ContractWindow extends Overlay<ContractWindow> {
addConfirmationLabelTextFieldWithCopyIcon(gridPane, rowIndex, Res.get("shared.offerId"), offer.getId(),
Layout.TWICE_FIRST_ROW_DISTANCE).second.setMouseTransparent(false);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("contractWindow.dates"),
formatter.formatDateTime(offer.getDate()) + " / " + formatter.formatDateTime(dispute.getTradeDate()));
DisplayUtils.formatDateTime(offer.getDate()) + " / " + DisplayUtils.formatDateTime(dispute.getTradeDate()));
String currencyCode = offer.getCurrencyCode();
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.offerType"),
formatter.getDirectionBothSides(offer.getDirection(), currencyCode));
DisplayUtils.getDirectionBothSides(offer.getDirection(), currencyCode));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradePrice"),
formatter.formatPrice(contract.getTradePrice()));
BSFormatter.formatPrice(contract.getTradePrice()));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeAmount"),
formatter.formatCoinWithCode(contract.getTradeAmount()));
addConfirmationLabelLabel(gridPane, ++rowIndex, formatter.formatVolumeLabel(currencyCode, ":"),
formatter.formatVolumeWithCode(contract.getTradeVolume()));
addConfirmationLabelLabel(gridPane, ++rowIndex, DisplayUtils.formatVolumeLabel(currencyCode, ":"),
DisplayUtils.formatVolumeWithCode(contract.getTradeVolume()));
String securityDeposit = Res.getWithColAndCap("shared.buyer") +
" " +
formatter.formatCoinWithCode(offer.getBuyerSecurityDeposit()) +
@ -279,7 +280,7 @@ public class ContractWindow extends Overlay<ContractWindow> {
String currencyCode) {
long age = accountAgeWitnessService.getAccountAge(paymentAccountPayload, pubKeyRing);
return CurrencyUtil.isFiatCurrency(currencyCode) ?
age > -1 ? Res.get("peerInfoIcon.tooltip.age", formatter.formatAccountAge(age)) :
age > -1 ? Res.get("peerInfoIcon.tooltip.age", DisplayUtils.formatAccountAge(age)) :
Res.get("peerInfoIcon.tooltip.unknownAge") :
"";
}

View File

@ -23,6 +23,7 @@ import bisq.desktop.components.BisqTextArea;
import bisq.desktop.components.InputTextField;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.Layout;
import bisq.core.btc.exceptions.TransactionVerificationException;
@ -39,6 +40,7 @@ import bisq.core.support.dispute.arbitration.ArbitrationManager;
import bisq.core.support.dispute.mediation.MediationManager;
import bisq.core.trade.Contract;
import bisq.core.util.BSFormatter;
import bisq.core.util.ParsingUtils;
import bisq.common.UserThread;
import bisq.common.app.DevEnv;
@ -259,7 +261,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
addTitledGroupBg(gridPane, ++rowIndex, 17, Res.get("disputeSummaryWindow.title")).getStyleClass().add("last");
addConfirmationLabelLabel(gridPane, rowIndex, Res.get("shared.tradeId"), dispute.getShortTradeId(),
Layout.TWICE_FIRST_ROW_DISTANCE);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("disputeSummaryWindow.openDate"), formatter.formatDateTime(dispute.getOpeningDate()));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("disputeSummaryWindow.openDate"), DisplayUtils.formatDateTime(dispute.getOpeningDate()));
if (dispute.isDisputeOpenerIsMaker()) {
if (dispute.isDisputeOpenerIsBuyer())
role = Res.get("support.buyerOfferer");
@ -275,9 +277,9 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeAmount"),
formatter.formatCoinWithCode(contract.getTradeAmount()));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradePrice"),
formatter.formatPrice(contract.getTradePrice()));
BSFormatter.formatPrice(contract.getTradePrice()));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeVolume"),
formatter.formatVolumeWithCode(contract.getTradeVolume()));
DisplayUtils.formatVolumeWithCode(contract.getTradeVolume()));
String securityDeposit = Res.getWithColAndCap("shared.buyer") +
" " +
formatter.formatCoinWithCode(contract.getOfferPayload().getBuyerSecurityDeposit()) +
@ -344,8 +346,8 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
}
private boolean isPayoutAmountValid() {
Coin buyerAmount = formatter.parseToCoin(buyerPayoutAmountInputTextField.getText());
Coin sellerAmount = formatter.parseToCoin(sellerPayoutAmountInputTextField.getText());
Coin buyerAmount = ParsingUtils.parseToCoin(buyerPayoutAmountInputTextField.getText(), formatter);
Coin sellerAmount = ParsingUtils.parseToCoin(sellerPayoutAmountInputTextField.getText(), formatter);
Contract contract = dispute.getContract();
Coin tradeAmount = contract.getTradeAmount();
Offer offer = new Offer(contract.getOfferPayload());
@ -362,7 +364,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
Coin available = contract.getTradeAmount()
.add(offer.getBuyerSecurityDeposit())
.add(offer.getSellerSecurityDeposit());
Coin enteredAmount = formatter.parseToCoin(inputTextField.getText());
Coin enteredAmount = ParsingUtils.parseToCoin(inputTextField.getText(), formatter);
if (enteredAmount.compareTo(available) > 0) {
enteredAmount = available;
Coin finalEnteredAmount = enteredAmount;
@ -551,7 +553,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
dispute.setDisputeResult(disputeResult);
dispute.setIsClosed(true);
String text = Res.get("disputeSummaryWindow.close.msg",
formatter.formatDateTime(disputeResult.getCloseDate()),
DisplayUtils.formatDateTime(disputeResult.getCloseDate()),
formatter.formatCoinWithCode(disputeResult.getBuyerPayoutAmount()),
formatter.formatCoinWithCode(disputeResult.getSellerPayoutAmount()),
disputeResult.summaryNotesProperty().get());

View File

@ -21,6 +21,7 @@ import bisq.desktop.Navigation;
import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.BusyAnimation;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
@ -172,49 +173,49 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
double firstRowDistance = Layout.TWICE_FIRST_ROW_DISTANCE;
if (takeOfferHandlerOptional.isPresent()) {
addConfirmationLabelLabel(gridPane, rowIndex, offerTypeLabel,
formatter.getDirectionForTakeOffer(direction, currencyCode), firstRowDistance);
DisplayUtils.getDirectionForTakeOffer(direction, currencyCode), firstRowDistance);
fiatDirectionInfo = direction == OfferPayload.Direction.BUY ? toReceive : toSpend;
btcDirectionInfo = direction == OfferPayload.Direction.SELL ? toReceive : toSpend;
} else if (placeOfferHandlerOptional.isPresent()) {
addConfirmationLabelLabel(gridPane, rowIndex, offerTypeLabel,
formatter.getOfferDirectionForCreateOffer(direction, currencyCode), firstRowDistance);
DisplayUtils.getOfferDirectionForCreateOffer(direction, currencyCode), firstRowDistance);
fiatDirectionInfo = direction == OfferPayload.Direction.SELL ? toReceive : toSpend;
btcDirectionInfo = direction == OfferPayload.Direction.BUY ? toReceive : toSpend;
} else {
addConfirmationLabelLabel(gridPane, rowIndex, offerTypeLabel,
formatter.getDirectionBothSides(direction, currencyCode), firstRowDistance);
DisplayUtils.getDirectionBothSides(direction, currencyCode), firstRowDistance);
}
String btcAmount = Res.get("shared.btcAmount");
if (takeOfferHandlerOptional.isPresent()) {
addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + btcDirectionInfo,
formatter.formatCoinWithCode(tradeAmount));
addConfirmationLabelLabel(gridPane, ++rowIndex, formatter.formatVolumeLabel(currencyCode) + fiatDirectionInfo,
formatter.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount)));
addConfirmationLabelLabel(gridPane, ++rowIndex, DisplayUtils.formatVolumeLabel(currencyCode) + fiatDirectionInfo,
DisplayUtils.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount)));
} else {
addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + btcDirectionInfo,
formatter.formatCoinWithCode(offer.getAmount()));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minBtcAmount"),
formatter.formatCoinWithCode(offer.getMinAmount()));
String volume = formatter.formatVolumeWithCode(offer.getVolume());
String volume = DisplayUtils.formatVolumeWithCode(offer.getVolume());
String minVolume = "";
if (offer.getVolume() != null && offer.getMinVolume() != null &&
!offer.getVolume().equals(offer.getMinVolume()))
minVolume = " " + Res.get("offerDetailsWindow.min", formatter.formatVolumeWithCode(offer.getMinVolume()));
minVolume = " " + Res.get("offerDetailsWindow.min", DisplayUtils.formatVolumeWithCode(offer.getMinVolume()));
addConfirmationLabelLabel(gridPane, ++rowIndex,
formatter.formatVolumeLabel(currencyCode) + fiatDirectionInfo, volume + minVolume);
DisplayUtils.formatVolumeLabel(currencyCode) + fiatDirectionInfo, volume + minVolume);
}
String priceLabel = Res.get("shared.price");
if (takeOfferHandlerOptional.isPresent()) {
addConfirmationLabelLabel(gridPane, ++rowIndex, priceLabel, formatter.formatPrice(tradePrice));
addConfirmationLabelLabel(gridPane, ++rowIndex, priceLabel, BSFormatter.formatPrice(tradePrice));
} else {
Price price = offer.getPrice();
if (offer.isUseMarketBasedPrice()) {
addConfirmationLabelLabel(gridPane, ++rowIndex, priceLabel, formatter.formatPrice(price) +
addConfirmationLabelLabel(gridPane, ++rowIndex, priceLabel, BSFormatter.formatPrice(price) +
" " + Res.get("offerDetailsWindow.distance",
formatter.formatPercentagePrice(offer.getMarketPriceMargin())));
BSFormatter.formatPercentagePrice(offer.getMarketPriceMargin())));
} else {
addConfirmationLabelLabel(gridPane, ++rowIndex, priceLabel, formatter.formatPrice(price));
addConfirmationLabelLabel(gridPane, ++rowIndex, priceLabel, BSFormatter.formatPrice(price));
}
}
final PaymentMethod paymentMethod = offer.getPaymentMethod();
@ -309,7 +310,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("offerDetailsWindow.makersOnion"),
offer.getMakerNodeAddress().getFullAddress());
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.creationDate"),
formatter.formatDateTime(offer.getDate()));
DisplayUtils.formatDateTime(offer.getDate()));
String value = Res.getWithColAndCap("shared.buyer") +
" " +
formatter.formatCoinWithCode(offer.getBuyerSecurityDeposit()) +

View File

@ -25,6 +25,7 @@ import bisq.desktop.components.TableGroupHeadline;
import bisq.desktop.main.dao.governance.ProposalDisplay;
import bisq.desktop.main.dao.governance.result.VoteListItem;
import bisq.desktop.main.overlays.TabbedOverlay;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
@ -240,7 +241,7 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
super.updateItem(item, empty);
if (item != null && !empty) {
setText(bsqFormatter.formatDateTime(item.getBlindVoteDate()));
setText(DisplayUtils.formatDateTime(item.getBlindVoteDate()));
} else {
setText("");
}

View File

@ -84,7 +84,7 @@ public class TacWindow extends Overlay<TacWindow> {
"accordance with the Bisq arbitration rules as at present in force. The arbitration is conducted online. " +
"The language to be used in the arbitration proceedings shall be English if not otherwise stated.\n\n" +
"6. The user confirms that he has read and agreed to the rules regarding the dispute process:\n" +
"6. The user confirms that they have read and agreed to the rules regarding the dispute process:\n" +
" - You must complete trades within the maximum duration specified for each payment method.\n" +
" - You must enter the trade ID in the \"reason for payment\" text field when doing the fiat payment transfer.\n" +
" - If the bank of the fiat sender charges fees, the sender (" + Res.getBaseCurrencyCode() + " buyer) has to cover the fees.\n" +

View File

@ -21,6 +21,7 @@ import bisq.desktop.components.BisqTextArea;
import bisq.desktop.components.TextFieldWithCopyIcon;
import bisq.desktop.main.MainView;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.Layout;
import bisq.core.account.witness.AccountAgeWitnessService;
@ -138,12 +139,12 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
String offerType = Res.get("shared.offerType");
if (tradeManager.isBuyer(offer)) {
addConfirmationLabelLabel(gridPane, rowIndex, offerType,
formatter.getDirectionForBuyer(myOffer, offer.getCurrencyCode()), Layout.TWICE_FIRST_ROW_DISTANCE);
DisplayUtils.getDirectionForBuyer(myOffer, offer.getCurrencyCode()), Layout.TWICE_FIRST_ROW_DISTANCE);
fiatDirectionInfo = toSpend;
btcDirectionInfo = toReceive;
} else {
addConfirmationLabelLabel(gridPane, rowIndex, offerType,
formatter.getDirectionForSeller(myOffer, offer.getCurrencyCode()), Layout.TWICE_FIRST_ROW_DISTANCE);
DisplayUtils.getDirectionForSeller(myOffer, offer.getCurrencyCode()), Layout.TWICE_FIRST_ROW_DISTANCE);
fiatDirectionInfo = toReceive;
btcDirectionInfo = toSpend;
}
@ -151,10 +152,10 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.btcAmount") + btcDirectionInfo,
formatter.formatCoinWithCode(trade.getTradeAmount()));
addConfirmationLabelLabel(gridPane, ++rowIndex,
formatter.formatVolumeLabel(offer.getCurrencyCode()) + fiatDirectionInfo,
formatter.formatVolumeWithCode(trade.getTradeVolume()));
DisplayUtils.formatVolumeLabel(offer.getCurrencyCode()) + fiatDirectionInfo,
DisplayUtils.formatVolumeWithCode(trade.getTradeVolume()));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradePrice"),
formatter.formatPrice(trade.getTradePrice()));
BSFormatter.formatPrice(trade.getTradePrice()));
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.paymentMethod"),
Res.get(offer.getPaymentMethod().getId()));
@ -202,7 +203,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
addConfirmationLabelTextFieldWithCopyIcon(gridPane, rowIndex, Res.get("shared.tradeId"),
trade.getId(), Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("tradeDetailsWindow.tradeDate"),
formatter.formatDateTime(trade.getDate()));
DisplayUtils.formatDateTime(trade.getDate()));
String securityDeposit = Res.getWithColAndCap("shared.buyer") +
" " +
formatter.formatCoinWithCode(offer.getBuyerSecurityDeposit()) +
@ -234,7 +235,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
String paymentDetails = buyerPaymentAccountPayload.getPaymentDetails();
long age = accountAgeWitnessService.getAccountAge(buyerPaymentAccountPayload, contract.getBuyerPubKeyRing());
buyersAccountAge = CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) ?
age > -1 ? Res.get("peerInfoIcon.tooltip.age", formatter.formatAccountAge(age)) :
age > -1 ? Res.get("peerInfoIcon.tooltip.age", DisplayUtils.formatAccountAge(age)) :
Res.get("peerInfoIcon.tooltip.unknownAge") :
"";
@ -248,7 +249,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
String paymentDetails = sellerPaymentAccountPayload.getPaymentDetails();
long age = accountAgeWitnessService.getAccountAge(sellerPaymentAccountPayload, contract.getSellerPubKeyRing());
sellersAccountAge = CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) ?
age > -1 ? Res.get("peerInfoIcon.tooltip.age", formatter.formatAccountAge(age)) :
age > -1 ? Res.get("peerInfoIcon.tooltip.age", DisplayUtils.formatAccountAge(age)) :
Res.get("peerInfoIcon.tooltip.unknownAge") :
"";
String postFix = sellersAccountAge.isEmpty() ? "" : " / " + sellersAccountAge;

View File

@ -94,8 +94,7 @@ public class BisqInstaller {
public VerifyTask verify(List<FileDescriptor> fileDescriptors) {
VerifyTask verifyTask = new VerifyTask(fileDescriptors);
Thread th = new Thread(verifyTask);
th.start();
new Thread(verifyTask, "BisqInstaller VerifyTask").start();
// TODO: check for problems when creating task
return verifyTask;
}
@ -120,8 +119,7 @@ public class BisqInstaller {
if (saveDir == null)
saveDir = Utilities.getDownloadOfHomeDir();
DownloadTask task = new DownloadTask(fileDescriptors, saveDir);
Thread th = new Thread(task);
th.start();
new Thread(task, "BisqInstaller DownloadTask").start();
// TODO: check for problems when creating task
return task;
}

View File

@ -26,6 +26,7 @@ import bisq.desktop.components.InputTextField;
import bisq.desktop.components.PeerInfoIcon;
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.alert.PrivateNotificationManager;
@ -317,7 +318,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
Offer offer = item.getTradable().getOffer();
boolean matchesId = offer.getId().contains(filterString);
boolean matchesOfferDate = formatter.formatDate(offer.getDate()).contains(filterString);
boolean matchesOfferDate = DisplayUtils.formatDate(offer.getDate()).contains(filterString);
boolean isMakerOnion = offer.getMakerNodeAddress().getFullAddress().contains(filterString);
if (item.getTradable() instanceof Trade) {
@ -327,7 +328,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
boolean matchesSellersPaymentAccountData = false;
Trade trade = (Trade) item.getTradable();
boolean matchesTradeDate = formatter.formatDate(trade.getTakeOfferDate()).contains(filterString);
boolean matchesTradeDate = DisplayUtils.formatDate(trade.getTakeOfferDate()).contains(filterString);
Contract contract = trade.getContract();
if (contract != null) {
isBuyerOnion = contract.getBuyerNodeAddress().getFullAddress().contains(filterString);

View File

@ -19,6 +19,7 @@ package bisq.desktop.main.portfolio.closedtrades;
import bisq.desktop.common.model.ActivatableWithDataModel;
import bisq.desktop.common.model.ViewModel;
import bisq.desktop.util.DisplayUtils;
import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
@ -68,14 +69,14 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
return "";
Tradable tradable = item.getTradable();
if (tradable instanceof Trade)
return formatter.formatPrice(((Trade) tradable).getTradePrice());
return BSFormatter.formatPrice(((Trade) tradable).getTradePrice());
else
return formatter.formatPrice(tradable.getOffer().getPrice());
return BSFormatter.formatPrice(tradable.getOffer().getPrice());
}
String getVolume(ClosedTradableListItem item) {
if (item != null && item.getTradable() instanceof Trade)
return formatter.formatVolumeWithCode(((Trade) item.getTradable()).getTradeVolume());
return DisplayUtils.formatVolumeWithCode(((Trade) item.getTradable()).getTradeVolume());
else if (item != null && item.getTradable() instanceof OpenOffer)
return "-";
else
@ -123,18 +124,18 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
}
String getDirectionLabel(ClosedTradableListItem item) {
return (item != null) ? formatter.getDirectionWithCode(dataModel.getDirection(item.getTradable().getOffer()), item.getTradable().getOffer().getCurrencyCode()) : "";
return (item != null) ? DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getTradable().getOffer()), item.getTradable().getOffer().getCurrencyCode()) : "";
}
String getDate(ClosedTradableListItem item) {
return formatter.formatDateTime(item.getTradable().getDate());
return DisplayUtils.formatDateTime(item.getTradable().getDate());
}
String getMarketLabel(ClosedTradableListItem item) {
if ((item == null))
return "";
return formatter.getCurrencyPair(item.getTradable().getOffer().getCurrencyCode());
return BSFormatter.getCurrencyPair(item.getTradable().getOffer().getCurrencyCode());
}
String getState(ClosedTradableListItem item) {

View File

@ -92,12 +92,12 @@ class EditOfferViewModel extends MutableOfferViewModel<EditOfferDataModel> {
public void onInvalidateMarketPriceMargin() {
marketPriceMargin.set("0.00%");
marketPriceMargin.set(btcFormatter.formatToPercent(dataModel.getMarketPriceMargin()));
marketPriceMargin.set(BSFormatter.formatToPercent(dataModel.getMarketPriceMargin()));
}
public void onInvalidatePrice() {
price.set(btcFormatter.formatPrice(null));
price.set(btcFormatter.formatPrice(dataModel.getPrice().get()));
price.set(BSFormatter.formatPrice(null));
price.set(BSFormatter.formatPrice(dataModel.getPrice().get()));
}
public boolean isSecurityDepositValid() {

View File

@ -19,6 +19,7 @@ package bisq.desktop.main.portfolio.failedtrades;
import bisq.desktop.common.model.ActivatableWithDataModel;
import bisq.desktop.common.model.ViewModel;
import bisq.desktop.util.DisplayUtils;
import bisq.core.locale.Res;
import bisq.core.util.BSFormatter;
@ -54,29 +55,29 @@ class FailedTradesViewModel extends ActivatableWithDataModel<FailedTradesDataMod
}
String getPrice(FailedTradesListItem item) {
return (item != null) ? formatter.formatPrice(item.getTrade().getTradePrice()) : "";
return (item != null) ? BSFormatter.formatPrice(item.getTrade().getTradePrice()) : "";
}
String getVolume(FailedTradesListItem item) {
if (item != null && item.getTrade() != null)
return formatter.formatVolumeWithCode(item.getTrade().getTradeVolume());
return DisplayUtils.formatVolumeWithCode(item.getTrade().getTradeVolume());
else
return "";
}
String getDirectionLabel(FailedTradesListItem item) {
return (item != null) ? formatter.getDirectionWithCode(dataModel.getDirection(item.getTrade().getOffer()), item.getTrade().getOffer().getCurrencyCode()) : "";
return (item != null) ? DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getTrade().getOffer()), item.getTrade().getOffer().getCurrencyCode()) : "";
}
String getMarketLabel(FailedTradesListItem item) {
if ((item == null))
return "";
return formatter.getCurrencyPair(item.getTrade().getOffer().getCurrencyCode());
return BSFormatter.getCurrencyPair(item.getTrade().getOffer().getCurrencyCode());
}
String getDate(FailedTradesListItem item) {
return formatter.formatDateTime(item.getTrade().getDate());
return DisplayUtils.formatDateTime(item.getTrade().getDate());
}
String getState(FailedTradesListItem item) {

View File

@ -19,6 +19,7 @@ package bisq.desktop.main.portfolio.openoffer;
import bisq.desktop.common.model.ActivatableWithDataModel;
import bisq.desktop.common.model.ViewModel;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.core.locale.Res;
@ -72,7 +73,7 @@ class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel>
}
String getAmount(OpenOfferListItem item) {
return (item != null) ? formatter.formatAmount(item.getOffer()) : "";
return (item != null) ? DisplayUtils.formatAmount(item.getOffer(), formatter) : "";
}
String getPrice(OpenOfferListItem item) {
@ -84,33 +85,33 @@ class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel>
if (price != null) {
String postFix = "";
if (offer.isUseMarketBasedPrice())
postFix = " (" + formatter.formatPercentagePrice(offer.getMarketPriceMargin()) + ")";
return formatter.formatPrice(price) + postFix;
postFix = " (" + BSFormatter.formatPercentagePrice(offer.getMarketPriceMargin()) + ")";
return BSFormatter.formatPrice(price) + postFix;
} else {
return Res.get("shared.na");
}
}
String getVolume(OpenOfferListItem item) {
return (item != null) ? formatter.formatVolume(item.getOffer(), false, 0) + " " + item.getOffer().getCurrencyCode() : "";
return (item != null) ? DisplayUtils.formatVolume(item.getOffer(), false, 0) + " " + item.getOffer().getCurrencyCode() : "";
}
String getDirectionLabel(OpenOfferListItem item) {
if ((item == null))
return "";
return formatter.getDirectionWithCode(dataModel.getDirection(item.getOffer()), item.getOffer().getCurrencyCode());
return DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getOffer()), item.getOffer().getCurrencyCode());
}
String getMarketLabel(OpenOfferListItem item) {
if ((item == null))
return "";
return formatter.getCurrencyPair(item.getOffer().getCurrencyCode());
return BSFormatter.getCurrencyPair(item.getOffer().getCurrencyCode());
}
String getDate(OpenOfferListItem item) {
return formatter.formatDateTime(item.getOffer().getDate());
return DisplayUtils.formatDateTime(item.getOffer().getDate());
}
boolean isDeactivated(OpenOfferListItem item) {

Some files were not shown because too many files have changed in this diff Show More