diff --git a/common/src/main/java/bisq/common/app/Capability.java b/common/src/main/java/bisq/common/app/Capability.java
index e01814fd35..ed11d61c87 100644
--- a/common/src/main/java/bisq/common/app/Capability.java
+++ b/common/src/main/java/bisq/common/app/Capability.java
@@ -33,5 +33,6 @@ public enum Capability {
ACK_MSG,
BSQ_BLOCK,
DAO_STATE,
- BUNDLE_OF_ENVELOPES
+ BUNDLE_OF_ENVELOPES,
+ SIGNED_ACCOUNT_AGE_WITNESS
}
diff --git a/common/src/main/java/bisq/common/crypto/Sig.java b/common/src/main/java/bisq/common/crypto/Sig.java
index 85e1483896..659ed3d6b8 100644
--- a/common/src/main/java/bisq/common/crypto/Sig.java
+++ b/common/src/main/java/bisq/common/crypto/Sig.java
@@ -111,7 +111,7 @@ public class Sig {
sig.update(data);
return sig.verify(signature);
} catch (SignatureException | InvalidKeyException | NoSuchAlgorithmException e) {
- throw new CryptoException("Signature verification failed. " + e.getMessage());
+ throw new CryptoException("Signature verification failed", e);
}
}
diff --git a/common/src/main/proto/pb.proto b/common/src/main/proto/pb.proto
index 54d170ec67..8f518b8ec5 100644
--- a/common/src/main/proto/pb.proto
+++ b/common/src/main/proto/pb.proto
@@ -438,6 +438,7 @@ message PersistableNetworkPayload {
TradeStatistics2 trade_statistics2 = 2;
ProposalPayload proposal_payload = 3;
BlindVotePayload blind_vote_payload = 4;
+ SignedWitness signed_witness = 5;
}
}
@@ -639,6 +640,16 @@ message AccountAgeWitness {
int64 date = 2;
}
+message SignedWitness {
+ bool signed_by_arbitrator = 1;
+ bytes witness_hash = 2;
+ bytes signature = 3;
+ bytes signer_pub_key = 4;
+ bytes witness_owner_pub_key = 5;
+ int64 date = 6;
+ int64 trade_amount = 7;
+}
+
///////////////////////////////////////////////////////////////////////////////////////////
// Dispute payload
///////////////////////////////////////////////////////////////////////////////////////////
@@ -1020,6 +1031,7 @@ message PersistableEnvelope {
MyReputationList my_reputation_list = 25;
MyProofOfBurnList my_proof_of_burn_list = 26;
UnconfirmedBsqChangeOutputList unconfirmed_bsq_change_output_list = 27;
+ SignedWitnessStore signed_witness_store = 28;
}
}
@@ -1060,6 +1072,10 @@ message AccountAgeWitnessStore {
repeated AccountAgeWitness items = 1;
}
+message SignedWitnessStore {
+ repeated SignedWitness items = 1;
+}
+
// We use a list not a hash map to save disc space. The hash can be calculated from the payload anyway
message TradeStatistics2Store {
repeated TradeStatistics2 items = 1;
diff --git a/core/src/main/java/bisq/core/account/sign/SignedWitness.java b/core/src/main/java/bisq/core/account/sign/SignedWitness.java
new file mode 100644
index 0000000000..aab54a8364
--- /dev/null
+++ b/core/src/main/java/bisq/core/account/sign/SignedWitness.java
@@ -0,0 +1,169 @@
+/*
+ * 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 .
+ */
+
+package bisq.core.account.sign;
+
+import bisq.network.p2p.storage.P2PDataStorage;
+import bisq.network.p2p.storage.payload.CapabilityRequiringPayload;
+import bisq.network.p2p.storage.payload.DateTolerantPayload;
+import bisq.network.p2p.storage.payload.LazyProcessedPayload;
+import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
+
+import bisq.common.app.Capabilities;
+import bisq.common.app.Capability;
+import bisq.common.crypto.Hash;
+import bisq.common.proto.persistable.PersistableEnvelope;
+import bisq.common.util.Utilities;
+
+
+import com.google.protobuf.ByteString;
+
+import org.bitcoinj.core.Coin;
+
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+import lombok.Value;
+import lombok.extern.slf4j.Slf4j;
+
+// Supports signatures made from EC key (arbitrators) and signature created with DSA key.
+@Slf4j
+@Value
+public class SignedWitness implements LazyProcessedPayload, PersistableNetworkPayload, PersistableEnvelope,
+ DateTolerantPayload, CapabilityRequiringPayload {
+ private static final long TOLERANCE = TimeUnit.DAYS.toMillis(1);
+
+ private final boolean signedByArbitrator;
+ private final byte[] witnessHash;
+ private final byte[] signature;
+ private final byte[] signerPubKey;
+ private final byte[] witnessOwnerPubKey;
+ private final long date;
+ private final long tradeAmount;
+
+ transient private final byte[] hash;
+
+ public SignedWitness(boolean signedByArbitrator,
+ byte[] witnessHash,
+ byte[] signature,
+ byte[] signerPubKey,
+ byte[] witnessOwnerPubKey,
+ long date,
+ long tradeAmount) {
+ this.signedByArbitrator = signedByArbitrator;
+ this.witnessHash = witnessHash;
+ this.signature = signature;
+ this.signerPubKey = signerPubKey;
+ this.witnessOwnerPubKey = witnessOwnerPubKey;
+ this.date = date;
+ this.tradeAmount = tradeAmount;
+
+ // The hash is only using the data which do not change in repeated trades between same users (no date or amount).
+ // We only want to store the first and oldest one and will ignore others. That will help also to protect privacy
+ // so that the total number of trades is not revealed. We use putIfAbsent when we store the data so first
+ // object will win. We consider one signed trade with one peer enough and do not consider repeated trades with
+ // same peer to add more security as if that one would be colluding it would be not detected anyway. The total
+ // number of signed trades with different peers is still available and can be considered more valuable data for
+ // security.
+ byte[] data = Utilities.concatenateByteArrays(witnessHash, signature);
+ data = Utilities.concatenateByteArrays(data, signerPubKey);
+ hash = Hash.getSha256Ripemd160hash(data);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // PROTO BUFFER
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public protobuf.PersistableNetworkPayload toProtoMessage() {
+ final protobuf.SignedWitness.Builder builder = protobuf.SignedWitness.newBuilder()
+ .setSignedByArbitrator(signedByArbitrator)
+ .setWitnessHash(ByteString.copyFrom(witnessHash))
+ .setSignature(ByteString.copyFrom(signature))
+ .setSignerPubKey(ByteString.copyFrom(signerPubKey))
+ .setWitnessOwnerPubKey(ByteString.copyFrom(witnessOwnerPubKey))
+ .setDate(date)
+ .setTradeAmount(tradeAmount);
+ return protobuf.PersistableNetworkPayload.newBuilder().setSignedWitness(builder).build();
+ }
+
+ public protobuf.SignedWitness toProtoSignedWitness() {
+ return toProtoMessage().getSignedWitness();
+ }
+
+ public static SignedWitness fromProto(protobuf.SignedWitness proto) {
+ return new SignedWitness(proto.getSignedByArbitrator(),
+ proto.getWitnessHash().toByteArray(),
+ proto.getSignature().toByteArray(),
+ proto.getSignerPubKey().toByteArray(),
+ proto.getWitnessOwnerPubKey().toByteArray(),
+ proto.getDate(),
+ proto.getTradeAmount());
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // API
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public boolean isDateInTolerance() {
+ // We don't allow older or newer then 1 day.
+ // Preventing forward dating is also important to protect against a sophisticated attack
+ return Math.abs(new Date().getTime() - date) <= TOLERANCE;
+ }
+
+ @Override
+ public boolean verifyHashSize() {
+ return hash.length == 20;
+ }
+
+ // Pre 1.0.1 version don't know the new message type and throw an error which leads to disconnecting the peer.
+ @Override
+ public Capabilities getRequiredCapabilities() {
+ return new Capabilities(Capability.SIGNED_ACCOUNT_AGE_WITNESS);
+ }
+
+ @Override
+ public byte[] getHash() {
+ return hash;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Getters
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ public P2PDataStorage.ByteArray getHashAsByteArray() {
+ return new P2PDataStorage.ByteArray(hash);
+ }
+
+ @Override
+ public String toString() {
+ return "SignedWitness{" +
+ ",\n signedByArbitrator=" + signedByArbitrator +
+ ",\n witnessHash=" + Utilities.bytesAsHexString(witnessHash) +
+ ",\n signature=" + Utilities.bytesAsHexString(signature) +
+ ",\n signerPubKey=" + Utilities.bytesAsHexString(signerPubKey) +
+ ",\n witnessOwnerPubKey=" + Utilities.bytesAsHexString(witnessOwnerPubKey) +
+ ",\n date=" + date +
+ ",\n tradeAmount=" + Coin.valueOf(tradeAmount).toFriendlyString() +
+ ",\n hash=" + Utilities.bytesAsHexString(hash) +
+ "\n}";
+ }
+}
diff --git a/core/src/main/java/bisq/core/account/sign/SignedWitnessService.java b/core/src/main/java/bisq/core/account/sign/SignedWitnessService.java
new file mode 100644
index 0000000000..808d48cf16
--- /dev/null
+++ b/core/src/main/java/bisq/core/account/sign/SignedWitnessService.java
@@ -0,0 +1,298 @@
+/*
+ * 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 .
+ */
+
+package bisq.core.account.sign;
+
+import bisq.core.account.witness.AccountAgeWitness;
+import bisq.core.account.witness.AccountAgeWitnessService;
+import bisq.core.arbitration.ArbitratorManager;
+import bisq.core.payment.payload.PaymentAccountPayload;
+
+import bisq.network.p2p.P2PService;
+import bisq.network.p2p.storage.P2PDataStorage;
+import bisq.network.p2p.storage.persistence.AppendOnlyDataStoreService;
+
+import bisq.common.crypto.CryptoException;
+import bisq.common.crypto.KeyRing;
+import bisq.common.crypto.Sig;
+import bisq.common.util.Utilities;
+
+import org.bitcoinj.core.Coin;
+import org.bitcoinj.core.ECKey;
+
+import javax.inject.Inject;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+
+import java.security.PublicKey;
+import java.security.SignatureException;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+import java.util.stream.Collectors;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class SignedWitnessService {
+ public static final long CHARGEBACK_SAFETY_DAYS = 30;
+
+ private final KeyRing keyRing;
+ private final P2PService p2PService;
+ private final AccountAgeWitnessService accountAgeWitnessService;
+ private final ArbitratorManager arbitratorManager;
+ private final Map signedWitnessMap = new HashMap<>();
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Constructor
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Inject
+ public SignedWitnessService(KeyRing keyRing,
+ P2PService p2PService,
+ AccountAgeWitnessService accountAgeWitnessService,
+ ArbitratorManager arbitratorManager,
+ SignedWitnessStorageService signedWitnessStorageService,
+ AppendOnlyDataStoreService appendOnlyDataStoreService) {
+ this.keyRing = keyRing;
+ this.p2PService = p2PService;
+ this.accountAgeWitnessService = accountAgeWitnessService;
+ this.arbitratorManager = arbitratorManager;
+
+ // We need to add that early (before onAllServicesInitialized) as it will be used at startup.
+ appendOnlyDataStoreService.addService(signedWitnessStorageService);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Lifecycle
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ public void onAllServicesInitialized() {
+ p2PService.getP2PDataStorage().addAppendOnlyDataStoreListener(payload -> {
+ if (payload instanceof SignedWitness)
+ addToMap((SignedWitness) payload);
+ });
+
+ // At startup the P2PDataStorage initializes earlier, otherwise we ge the listener called.
+ p2PService.getP2PDataStorage().getAppendOnlyDataStoreMap().values().forEach(e -> {
+ if (e instanceof SignedWitness)
+ addToMap((SignedWitness) e);
+ });
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // API
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ public List getMyWitnessAgeList(PaymentAccountPayload myPaymentAccountPayload) {
+ AccountAgeWitness accountAgeWitness = accountAgeWitnessService.getMyWitness(myPaymentAccountPayload);
+ // We do not validate as it would not make sense to cheat one self...
+ return getSignedWitnessSet(accountAgeWitness).stream()
+ .map(SignedWitness::getDate)
+ .sorted()
+ .collect(Collectors.toList());
+ }
+
+
+ public List getVerifiedWitnessAgeList(AccountAgeWitness accountAgeWitness) {
+ return signedWitnessMap.values().stream()
+ .filter(e -> Arrays.equals(e.getWitnessHash(), accountAgeWitness.getHash()))
+ .filter(this::verifySignature)
+ .map(SignedWitness::getDate)
+ .sorted()
+ .collect(Collectors.toList());
+ }
+
+ // Arbitrators sign with EC key
+ public SignedWitness signAccountAgeWitness(Coin tradeAmount, AccountAgeWitness accountAgeWitness, ECKey key, PublicKey peersPubKey) {
+ String accountAgeWitnessHashAsHex = Utilities.encodeToHex(accountAgeWitness.getHash());
+ String signatureBase64 = key.signMessage(accountAgeWitnessHashAsHex);
+ return new SignedWitness(true,
+ accountAgeWitness.getHash(),
+ signatureBase64.getBytes(Charsets.UTF_8),
+ key.getPubKey(),
+ peersPubKey.getEncoded(),
+ new Date().getTime(),
+ tradeAmount.value);
+ }
+
+ // Any peer can sign with DSA key
+ public SignedWitness signAccountAgeWitness(Coin tradeAmount, AccountAgeWitness accountAgeWitness, PublicKey peersPubKey) throws CryptoException {
+ byte[] signature = Sig.sign(keyRing.getSignatureKeyPair().getPrivate(), accountAgeWitness.getHash());
+ return new SignedWitness(false,
+ accountAgeWitness.getHash(),
+ signature,
+ keyRing.getSignatureKeyPair().getPublic().getEncoded(),
+ peersPubKey.getEncoded(),
+ new Date().getTime(),
+ tradeAmount.value);
+ }
+
+ public boolean verifySignature(SignedWitness signedWitness) {
+ if (signedWitness.isSignedByArbitrator()) {
+ return verifySignatureWithECKey(signedWitness);
+ } else {
+ return verifySignatureWithDSAKey(signedWitness);
+ }
+ }
+
+ private boolean verifySignatureWithECKey(SignedWitness signedWitness) {
+ try {
+ String message = Utilities.encodeToHex(signedWitness.getWitnessHash());
+ String signatureBase64 = new String(signedWitness.getSignature(), Charsets.UTF_8);
+ ECKey key = ECKey.fromPublicOnly(signedWitness.getSignerPubKey());
+ if (arbitratorManager.isPublicKeyInList(Utilities.encodeToHex(key.getPubKey()))) {
+ key.verifyMessage(message, signatureBase64);
+ return true;
+ } else {
+ log.warn("Provided EC key is not in list of valid arbitrators.");
+ return false;
+ }
+ } catch (SignatureException e) {
+ log.warn("verifySignature signedWitness failed. signedWitness={}", signedWitness);
+ log.warn("Caused by ", e);
+ return false;
+ }
+ }
+
+ private boolean verifySignatureWithDSAKey(SignedWitness signedWitness) {
+ try {
+ PublicKey signaturePubKey = Sig.getPublicKeyFromBytes(signedWitness.getSignerPubKey());
+ Sig.verify(signaturePubKey, signedWitness.getWitnessHash(), signedWitness.getSignature());
+ return true;
+ } catch (CryptoException e) {
+ log.warn("verifySignature signedWitness failed. signedWitness={}", signedWitness);
+ log.warn("Caused by ", e);
+ return false;
+ }
+ }
+
+ public Set getSignedWitnessSet(AccountAgeWitness accountAgeWitness) {
+ return signedWitnessMap.values().stream()
+ .filter(e -> Arrays.equals(e.getWitnessHash(), accountAgeWitness.getHash()))
+ .collect(Collectors.toSet());
+ }
+
+ // SignedWitness objects signed by arbitrators
+ public Set getArbitratorsSignedWitnessSet(AccountAgeWitness accountAgeWitness) {
+ return signedWitnessMap.values().stream()
+ .filter(SignedWitness::isSignedByArbitrator)
+ .filter(e -> Arrays.equals(e.getWitnessHash(), accountAgeWitness.getHash()))
+ .collect(Collectors.toSet());
+ }
+
+ // SignedWitness objects signed by any other peer
+ public Set getTrustedPeerSignedWitnessSet(AccountAgeWitness accountAgeWitness) {
+ return signedWitnessMap.values().stream()
+ .filter(e -> !e.isSignedByArbitrator())
+ .filter(e -> Arrays.equals(e.getWitnessHash(), accountAgeWitness.getHash()))
+ .collect(Collectors.toSet());
+ }
+
+ // We go one level up by using the signer Key to lookup for SignedWitness objects which contain the signerKey as
+ // witnessOwnerPubKey
+ public Set getSignedWitnessSetByOwnerPubKey(byte[] ownerPubKey, Stack excluded) {
+ return signedWitnessMap.values().stream()
+ .filter(e -> Arrays.equals(e.getWitnessOwnerPubKey(), ownerPubKey))
+ .filter(e -> !excluded.contains(new P2PDataStorage.ByteArray(e.getSignerPubKey())))
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Checks whether the accountAgeWitness has a valid signature from a peer/arbitrator.
+ * @param accountAgeWitness
+ * @return true if accountAgeWitness is valid, false otherwise.
+ */
+ public boolean isValidAccountAgeWitness(AccountAgeWitness accountAgeWitness) {
+ Stack excludedPubKeys = new Stack<>();
+ long now = new Date().getTime();
+ Set signedWitnessSet = getSignedWitnessSet(accountAgeWitness);
+ for (SignedWitness signedWitness : signedWitnessSet) {
+ if (isValidSignedWitnessInternal(signedWitness, now, excludedPubKeys)) {
+ return true;
+ }
+ }
+ // If we have not returned in the loops or they have been empty we have not found a valid signer.
+ return false;
+ }
+
+ /**
+ * Helper to isValidAccountAgeWitness(accountAgeWitness)
+ * @param signedWitness the signedWitness to validate
+ * @param childSignedWitnessDateMillis the date the child SignedWitness was signed or current time if it is a leave.
+ * @param excludedPubKeys stack to preventsrecursive loops
+ * @return true if signedWitness is valid, false otherwise.
+ */
+ private boolean isValidSignedWitnessInternal(SignedWitness signedWitness, long childSignedWitnessDateMillis, Stack excludedPubKeys) {
+ if (!verifySignature(signedWitness)) {
+ return false;
+ }
+ if (signedWitness.isSignedByArbitrator()) {
+ // If signed by an arbitrator we don't have to check anything else.
+ return true;
+ } else {
+ if (!verifyDate(signedWitness, childSignedWitnessDateMillis)) {
+ return false;
+ }
+ if (excludedPubKeys.size() >= 2000) {
+ // Prevent DoS attack: an attacker floods the SignedWitness db with a long chain that takes lots of time to verify.ca
+ return false;
+ }
+ excludedPubKeys.push(new P2PDataStorage.ByteArray(signedWitness.getSignerPubKey()));
+ excludedPubKeys.push(new P2PDataStorage.ByteArray(signedWitness.getWitnessOwnerPubKey()));
+ // Iterate over signedWitness signers
+ Set signerSignedWitnessSet = getSignedWitnessSetByOwnerPubKey(signedWitness.getSignerPubKey(), excludedPubKeys);
+ for (SignedWitness signerSignedWitness : signerSignedWitnessSet) {
+ if (isValidSignedWitnessInternal(signerSignedWitness, signedWitness.getDate(), excludedPubKeys)) {
+ return true;
+ }
+ }
+ excludedPubKeys.pop();
+ excludedPubKeys.pop();
+ }
+ // If we have not returned in the loops or they have been empty we have not found a valid signer.
+ return false;
+ }
+
+ private boolean verifyDate(SignedWitness signedWitness, long childSignedWitnessDateMillis) {
+ long childSignedWitnessDateMinusChargebackPeriodMillis = Instant.ofEpochMilli(childSignedWitnessDateMillis).minus(CHARGEBACK_SAFETY_DAYS, ChronoUnit.DAYS).toEpochMilli();
+ long signedWitnessDateMillis = signedWitness.getDate();
+ return signedWitnessDateMillis <= childSignedWitnessDateMinusChargebackPeriodMillis;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Private
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @VisibleForTesting
+ void addToMap(SignedWitness signedWitness) {
+ signedWitnessMap.putIfAbsent(signedWitness.getHashAsByteArray(), signedWitness);
+ }
+}
diff --git a/core/src/main/java/bisq/core/account/sign/SignedWitnessStorageService.java b/core/src/main/java/bisq/core/account/sign/SignedWitnessStorageService.java
new file mode 100644
index 0000000000..b28040f7b6
--- /dev/null
+++ b/core/src/main/java/bisq/core/account/sign/SignedWitnessStorageService.java
@@ -0,0 +1,89 @@
+/*
+ * 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 .
+ */
+
+package bisq.core.account.sign;
+
+import bisq.network.p2p.storage.P2PDataStorage;
+import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
+import bisq.network.p2p.storage.persistence.MapStoreService;
+
+import bisq.common.storage.Storage;
+
+import com.google.inject.name.Named;
+
+import javax.inject.Inject;
+
+import java.io.File;
+
+import java.util.Map;
+
+import lombok.extern.slf4j.Slf4j;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+@Slf4j
+public class SignedWitnessStorageService extends MapStoreService {
+ private static final String FILE_NAME = "SignedWitnessStore";
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Constructor
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Inject
+ public SignedWitnessStorageService(@Named(Storage.STORAGE_DIR) File storageDir,
+ Storage persistableNetworkPayloadMapStorage) {
+ super(storageDir, persistableNetworkPayloadMapStorage);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // API
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public String getFileName() {
+ return FILE_NAME;
+ }
+
+ @Override
+ public Map getMap() {
+ return store.getMap();
+ }
+
+ @Override
+ public boolean canHandle(PersistableNetworkPayload payload) {
+ return payload instanceof SignedWitness;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Protected
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ protected SignedWitnessStore createStore() {
+ return new SignedWitnessStore();
+ }
+
+ @Override
+ protected void readStore() {
+ super.readStore();
+ checkArgument(store instanceof SignedWitnessStore,
+ "Store is not instance of SignedWitnessStore. That can happen if the ProtoBuffer " +
+ "file got changed. We clear the data store and recreated it again.");
+ }
+}
diff --git a/core/src/main/java/bisq/core/account/sign/SignedWitnessStore.java b/core/src/main/java/bisq/core/account/sign/SignedWitnessStore.java
new file mode 100644
index 0000000000..1f05e66ff5
--- /dev/null
+++ b/core/src/main/java/bisq/core/account/sign/SignedWitnessStore.java
@@ -0,0 +1,82 @@
+/*
+ * 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 .
+ */
+
+package bisq.core.account.sign;
+
+
+import bisq.network.p2p.storage.P2PDataStorage;
+import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
+
+import bisq.common.proto.persistable.PersistableEnvelope;
+
+import com.google.protobuf.Message;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+
+/**
+ * We store only the payload in the PB file to save disc space. The hash of the payload can be created anyway and
+ * is only used as key in the map. So we have a hybrid data structure which is represented as list in the protobuf
+ * definition and provide a hashMap for the domain access.
+ */
+@Slf4j
+public class SignedWitnessStore implements PersistableEnvelope {
+ @Getter
+ private Map map = new ConcurrentHashMap<>();
+
+ SignedWitnessStore() {
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // PROTO BUFFER
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ private SignedWitnessStore(List list) {
+ list.forEach(item -> map.put(new P2PDataStorage.ByteArray(item.getHash()), item));
+ }
+
+ public Message toProtoMessage() {
+ return protobuf.PersistableEnvelope.newBuilder()
+ .setSignedWitnessStore(getBuilder())
+ .build();
+ }
+
+ private protobuf.SignedWitnessStore.Builder getBuilder() {
+ final List protoList = map.values().stream()
+ .map(payload -> (SignedWitness) payload)
+ .map(SignedWitness::toProtoSignedWitness)
+ .collect(Collectors.toList());
+ return protobuf.SignedWitnessStore.newBuilder().addAllItems(protoList);
+ }
+
+ public static PersistableEnvelope fromProto(protobuf.SignedWitnessStore proto) {
+ List list = proto.getItemsList().stream()
+ .map(SignedWitness::fromProto).collect(Collectors.toList());
+ return new SignedWitnessStore(list);
+ }
+
+ public boolean containsKey(P2PDataStorage.ByteArray hash) {
+ return map.containsKey(hash);
+ }
+}
diff --git a/core/src/main/java/bisq/core/payment/AccountAgeRestrictions.java b/core/src/main/java/bisq/core/account/witness/AccountAgeRestrictions.java
similarity index 98%
rename from core/src/main/java/bisq/core/payment/AccountAgeRestrictions.java
rename to core/src/main/java/bisq/core/account/witness/AccountAgeRestrictions.java
index 85dd82cef3..e6f555ac4b 100644
--- a/core/src/main/java/bisq/core/payment/AccountAgeRestrictions.java
+++ b/core/src/main/java/bisq/core/account/witness/AccountAgeRestrictions.java
@@ -15,11 +15,12 @@
* along with Bisq. If not, see .
*/
-package bisq.core.payment;
+package bisq.core.account.witness;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferRestrictions;
+import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.Trade;
diff --git a/core/src/main/java/bisq/core/payment/AccountAgeWitness.java b/core/src/main/java/bisq/core/account/witness/AccountAgeWitness.java
similarity index 99%
rename from core/src/main/java/bisq/core/payment/AccountAgeWitness.java
rename to core/src/main/java/bisq/core/account/witness/AccountAgeWitness.java
index 256bf74ce7..c4588bdebd 100644
--- a/core/src/main/java/bisq/core/payment/AccountAgeWitness.java
+++ b/core/src/main/java/bisq/core/account/witness/AccountAgeWitness.java
@@ -15,7 +15,7 @@
* along with bisq. If not, see .
*/
-package bisq.core.payment;
+package bisq.core.account.witness;
import bisq.network.p2p.storage.P2PDataStorage;
import bisq.network.p2p.storage.payload.CapabilityRequiringPayload;
diff --git a/core/src/main/java/bisq/core/payment/AccountAgeWitnessService.java b/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessService.java
similarity index 99%
rename from core/src/main/java/bisq/core/payment/AccountAgeWitnessService.java
rename to core/src/main/java/bisq/core/account/witness/AccountAgeWitnessService.java
index 547a9401a3..16da03f853 100644
--- a/core/src/main/java/bisq/core/payment/AccountAgeWitnessService.java
+++ b/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessService.java
@@ -15,10 +15,12 @@
* along with bisq. If not, see .
*/
-package bisq.core.payment;
+package bisq.core.account.witness;
import bisq.core.locale.CurrencyUtil;
import bisq.core.offer.Offer;
+import bisq.core.payment.AssetAccount;
+import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.Trade;
diff --git a/core/src/main/java/bisq/core/payment/AccountAgeWitnessStorageService.java b/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessStorageService.java
similarity index 98%
rename from core/src/main/java/bisq/core/payment/AccountAgeWitnessStorageService.java
rename to core/src/main/java/bisq/core/account/witness/AccountAgeWitnessStorageService.java
index 437014d979..84fd4d8d5c 100644
--- a/core/src/main/java/bisq/core/payment/AccountAgeWitnessStorageService.java
+++ b/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessStorageService.java
@@ -15,7 +15,7 @@
* along with Bisq. If not, see .
*/
-package bisq.core.payment;
+package bisq.core.account.witness;
import bisq.network.p2p.storage.P2PDataStorage;
import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
diff --git a/core/src/main/java/bisq/core/payment/AccountAgeWitnessStore.java b/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessStore.java
similarity index 98%
rename from core/src/main/java/bisq/core/payment/AccountAgeWitnessStore.java
rename to core/src/main/java/bisq/core/account/witness/AccountAgeWitnessStore.java
index 05a2362e42..e25f73e28b 100644
--- a/core/src/main/java/bisq/core/payment/AccountAgeWitnessStore.java
+++ b/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessStore.java
@@ -15,7 +15,7 @@
* along with Bisq. If not, see .
*/
-package bisq.core.payment;
+package bisq.core.account.witness;
import bisq.network.p2p.storage.P2PDataStorage;
import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
diff --git a/core/src/main/java/bisq/core/app/BisqSetup.java b/core/src/main/java/bisq/core/app/BisqSetup.java
index f6d5f0459d..d59dbd89bd 100644
--- a/core/src/main/java/bisq/core/app/BisqSetup.java
+++ b/core/src/main/java/bisq/core/app/BisqSetup.java
@@ -17,6 +17,7 @@
package bisq.core.app;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.alert.Alert;
import bisq.core.alert.AlertManager;
import bisq.core.alert.PrivateNotificationManager;
@@ -41,7 +42,6 @@ import bisq.core.notifications.alerts.TradeEvents;
import bisq.core.notifications.alerts.market.MarketAlerts;
import bisq.core.notifications.alerts.price.PriceAlert;
import bisq.core.offer.OpenOfferManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.TradeLimits;
import bisq.core.provider.fee.FeeService;
diff --git a/core/src/main/java/bisq/core/app/misc/AppSetupWithP2P.java b/core/src/main/java/bisq/core/app/misc/AppSetupWithP2P.java
index 07c74d7e76..c708552d1a 100644
--- a/core/src/main/java/bisq/core/app/misc/AppSetupWithP2P.java
+++ b/core/src/main/java/bisq/core/app/misc/AppSetupWithP2P.java
@@ -17,10 +17,10 @@
package bisq.core.app.misc;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.app.SetupUtils;
import bisq.core.app.TorSetup;
import bisq.core.filter.FilterManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.trade.statistics.TradeStatisticsManager;
import bisq.network.crypto.EncryptionService;
diff --git a/core/src/main/java/bisq/core/app/misc/AppSetupWithP2PAndDAO.java b/core/src/main/java/bisq/core/app/misc/AppSetupWithP2PAndDAO.java
index 4a2a89c295..9de90a9d09 100644
--- a/core/src/main/java/bisq/core/app/misc/AppSetupWithP2PAndDAO.java
+++ b/core/src/main/java/bisq/core/app/misc/AppSetupWithP2PAndDAO.java
@@ -17,6 +17,7 @@
package bisq.core.app.misc;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.app.TorSetup;
import bisq.core.dao.DaoOptionKeys;
import bisq.core.dao.DaoSetup;
@@ -27,7 +28,6 @@ import bisq.core.dao.governance.myvote.MyVoteListService;
import bisq.core.dao.governance.proofofburn.MyProofOfBurnListService;
import bisq.core.dao.governance.proposal.MyProposalListService;
import bisq.core.filter.FilterManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.trade.statistics.TradeStatisticsManager;
import bisq.network.crypto.EncryptionService;
diff --git a/core/src/main/java/bisq/core/offer/OfferUtil.java b/core/src/main/java/bisq/core/offer/OfferUtil.java
index 14e30a6291..7d26b6cad3 100644
--- a/core/src/main/java/bisq/core/offer/OfferUtil.java
+++ b/core/src/main/java/bisq/core/offer/OfferUtil.java
@@ -17,6 +17,7 @@
package bisq.core.offer;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.Restrictions;
import bisq.core.filter.FilterManager;
@@ -24,7 +25,6 @@ import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.monetary.Price;
import bisq.core.monetary.Volume;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.F2FAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.provider.fee.FeeService;
diff --git a/core/src/main/java/bisq/core/payment/PaymentAccountUtil.java b/core/src/main/java/bisq/core/payment/PaymentAccountUtil.java
index 37c607b999..7dc43f623c 100644
--- a/core/src/main/java/bisq/core/payment/PaymentAccountUtil.java
+++ b/core/src/main/java/bisq/core/payment/PaymentAccountUtil.java
@@ -17,6 +17,8 @@
package bisq.core.payment;
+import bisq.core.account.witness.AccountAgeRestrictions;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Country;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferRestrictions;
diff --git a/core/src/main/java/bisq/core/payment/PaymentAccounts.java b/core/src/main/java/bisq/core/payment/PaymentAccounts.java
index 817ba27181..e6fe3a32bb 100644
--- a/core/src/main/java/bisq/core/payment/PaymentAccounts.java
+++ b/core/src/main/java/bisq/core/payment/PaymentAccounts.java
@@ -17,6 +17,8 @@
package bisq.core.payment;
+import bisq.core.account.witness.AccountAgeWitness;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.offer.Offer;
import java.util.Comparator;
diff --git a/core/src/main/java/bisq/core/proto/CoreProtoResolver.java b/core/src/main/java/bisq/core/proto/CoreProtoResolver.java
index 53abde92da..6bc80505cc 100644
--- a/core/src/main/java/bisq/core/proto/CoreProtoResolver.java
+++ b/core/src/main/java/bisq/core/proto/CoreProtoResolver.java
@@ -17,9 +17,10 @@
package bisq.core.proto;
+import bisq.core.account.sign.SignedWitness;
+import bisq.core.account.witness.AccountAgeWitness;
import bisq.core.dao.governance.blindvote.storage.BlindVotePayload;
import bisq.core.dao.governance.proposal.storage.appendonly.ProposalPayload;
-import bisq.core.payment.AccountAgeWitness;
import bisq.core.payment.payload.AdvancedCashAccountPayload;
import bisq.core.payment.payload.AliPayAccountPayload;
import bisq.core.payment.payload.CashAppAccountPayload;
@@ -166,6 +167,8 @@ public class CoreProtoResolver implements ProtoResolver {
return ProposalPayload.fromProto(proto.getProposalPayload());
case BLIND_VOTE_PAYLOAD:
return BlindVotePayload.fromProto(proto.getBlindVotePayload());
+ case SIGNED_WITNESS:
+ return SignedWitness.fromProto(proto.getSignedWitness());
default:
throw new ProtobufferRuntimeException("Unknown proto message case (PB.PersistableNetworkPayload). messageCase=" + proto.getMessageCase());
}
diff --git a/core/src/main/java/bisq/core/proto/persistable/CorePersistenceProtoResolver.java b/core/src/main/java/bisq/core/proto/persistable/CorePersistenceProtoResolver.java
index 858ba7456a..4e4e5114c9 100644
--- a/core/src/main/java/bisq/core/proto/persistable/CorePersistenceProtoResolver.java
+++ b/core/src/main/java/bisq/core/proto/persistable/CorePersistenceProtoResolver.java
@@ -17,6 +17,8 @@
package bisq.core.proto.persistable;
+import bisq.core.account.sign.SignedWitnessStore;
+import bisq.core.account.witness.AccountAgeWitnessStore;
import bisq.core.arbitration.DisputeList;
import bisq.core.btc.model.AddressEntryList;
import bisq.core.btc.wallet.BtcWalletService;
@@ -32,7 +34,6 @@ import bisq.core.dao.state.DaoStateStore;
import bisq.core.dao.state.model.governance.BallotList;
import bisq.core.dao.state.model.governance.MeritList;
import bisq.core.dao.state.unconfirmed.UnconfirmedBsqChangeOutputList;
-import bisq.core.payment.AccountAgeWitnessStore;
import bisq.core.payment.PaymentAccountList;
import bisq.core.proto.CoreProtoResolver;
import bisq.core.trade.TradableList;
@@ -136,6 +137,8 @@ public class CorePersistenceProtoResolver extends CoreProtoResolver implements P
return MyProofOfBurnList.fromProto(proto.getMyProofOfBurnList());
case UNCONFIRMED_BSQ_CHANGE_OUTPUT_LIST:
return UnconfirmedBsqChangeOutputList.fromProto(proto.getUnconfirmedBsqChangeOutputList());
+ case SIGNED_WITNESS_STORE:
+ return SignedWitnessStore.fromProto(proto.getSignedWitnessStore());
default:
throw new ProtobufferRuntimeException("Unknown proto message case(PB.PersistableEnvelope). " +
diff --git a/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java b/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java
index b49cf9ac6b..0a84eee15f 100644
--- a/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java
+++ b/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java
@@ -29,7 +29,7 @@ import lombok.extern.slf4j.Slf4j;
public class CoreNetworkCapabilities {
public static void setSupportedCapabilities(BisqEnvironment bisqEnvironment) {
Capabilities.app.addAll(Capability.TRADE_STATISTICS, Capability.TRADE_STATISTICS_2, Capability.ACCOUNT_AGE_WITNESS, Capability.ACK_MSG);
- Capabilities.app.addAll(Capability.BUNDLE_OF_ENVELOPES);
+ Capabilities.app.addAll(Capability.BUNDLE_OF_ENVELOPES,Capability.SIGNED_ACCOUNT_AGE_WITNESS);
if (BisqEnvironment.isDaoActivated(bisqEnvironment)) {
Capabilities.app.addAll(Capability.PROPOSAL, Capability.BLIND_VOTE, Capability.BSQ_BLOCK, Capability.DAO_STATE);
diff --git a/core/src/main/java/bisq/core/trade/Trade.java b/core/src/main/java/bisq/core/trade/Trade.java
index ed96bd1ae7..e09755ffcc 100644
--- a/core/src/main/java/bisq/core/trade/Trade.java
+++ b/core/src/main/java/bisq/core/trade/Trade.java
@@ -17,6 +17,7 @@
package bisq.core.trade;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.arbitration.Arbitrator;
import bisq.core.arbitration.ArbitratorManager;
import bisq.core.arbitration.Mediator;
@@ -30,7 +31,6 @@ import bisq.core.monetary.Volume;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferUtil;
import bisq.core.offer.OpenOfferManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.proto.CoreProtoResolver;
import bisq.core.trade.protocol.ProcessModel;
diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java
index 4698f435f1..015a73ecff 100644
--- a/core/src/main/java/bisq/core/trade/TradeManager.java
+++ b/core/src/main/java/bisq/core/trade/TradeManager.java
@@ -17,6 +17,7 @@
package bisq.core.trade;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.arbitration.ArbitratorManager;
import bisq.core.btc.exceptions.AddressEntryException;
import bisq.core.btc.model.AddressEntry;
@@ -29,7 +30,6 @@ import bisq.core.offer.OfferPayload;
import bisq.core.offer.OpenOffer;
import bisq.core.offer.OpenOfferManager;
import bisq.core.offer.availability.OfferAvailabilityModel;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.closed.ClosedTradableManager;
import bisq.core.trade.failed.FailedTradesManager;
diff --git a/core/src/main/java/bisq/core/trade/TradeModule.java b/core/src/main/java/bisq/core/trade/TradeModule.java
index 7d0ed2ce4c..c26420f6a6 100644
--- a/core/src/main/java/bisq/core/trade/TradeModule.java
+++ b/core/src/main/java/bisq/core/trade/TradeModule.java
@@ -17,9 +17,11 @@
package bisq.core.trade;
+import bisq.core.account.sign.SignedWitnessService;
+import bisq.core.account.sign.SignedWitnessStorageService;
+import bisq.core.account.witness.AccountAgeWitnessService;
+import bisq.core.account.witness.AccountAgeWitnessStorageService;
import bisq.core.app.AppOptionKeys;
-import bisq.core.payment.AccountAgeWitnessService;
-import bisq.core.payment.AccountAgeWitnessStorageService;
import bisq.core.trade.closed.ClosedTradableManager;
import bisq.core.trade.failed.FailedTradesManager;
import bisq.core.trade.statistics.AssetTradeActivityCheck;
@@ -49,8 +51,10 @@ public class TradeModule extends AppModule {
bind(ClosedTradableManager.class).in(Singleton.class);
bind(FailedTradesManager.class).in(Singleton.class);
bind(AccountAgeWitnessService.class).in(Singleton.class);
- bind(ReferralIdService.class).in(Singleton.class);
bind(AccountAgeWitnessStorageService.class).in(Singleton.class);
+ bind(SignedWitnessService.class).in(Singleton.class);
+ bind(SignedWitnessStorageService.class).in(Singleton.class);
+ bind(ReferralIdService.class).in(Singleton.class);
bind(AssetTradeActivityCheck.class).in(Singleton.class);
bindConstant().annotatedWith(named(AppOptionKeys.DUMP_STATISTICS)).to(environment.getRequiredProperty(AppOptionKeys.DUMP_STATISTICS));
}
diff --git a/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java b/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java
index 254387e4a4..185dcee0cc 100644
--- a/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java
+++ b/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java
@@ -17,6 +17,7 @@
package bisq.core.trade.protocol;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.arbitration.ArbitratorManager;
import bisq.core.btc.model.RawTransactionInput;
import bisq.core.btc.wallet.BsqWalletService;
@@ -26,7 +27,6 @@ import bisq.core.filter.FilterManager;
import bisq.core.network.MessageState;
import bisq.core.offer.Offer;
import bisq.core.offer.OpenOfferManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.proto.CoreProtoResolver;
diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java b/core/src/main/java/bisq/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java
index 379512ca61..2497f88939 100644
--- a/core/src/main/java/bisq/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java
+++ b/core/src/main/java/bisq/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java
@@ -17,8 +17,8 @@
package bisq.core.trade.protocol.tasks;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.CurrencyUtil;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.trade.Trade;
import bisq.core.trade.protocol.TradingPeer;
diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerVerifiesPeersAccountAge.java b/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerVerifiesPeersAccountAge.java
index 5d8ac144ef..78591b641a 100644
--- a/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerVerifiesPeersAccountAge.java
+++ b/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerVerifiesPeersAccountAge.java
@@ -17,8 +17,8 @@
package bisq.core.trade.protocol.tasks.seller;
+import bisq.core.account.witness.AccountAgeRestrictions;
import bisq.core.offer.OfferRestrictions;
-import bisq.core.payment.AccountAgeRestrictions;
import bisq.core.trade.Trade;
import bisq.core.trade.protocol.tasks.TradeTask;
diff --git a/core/src/test/java/bisq/core/account/sign/SignedWitnessServiceTest.java b/core/src/test/java/bisq/core/account/sign/SignedWitnessServiceTest.java
new file mode 100644
index 0000000000..205222e8d6
--- /dev/null
+++ b/core/src/test/java/bisq/core/account/sign/SignedWitnessServiceTest.java
@@ -0,0 +1,243 @@
+/*
+ * 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 .
+ */
+
+package bisq.core.account.sign;
+
+
+import bisq.core.account.witness.AccountAgeWitness;
+import bisq.core.arbitration.ArbitratorManager;
+
+import bisq.network.p2p.storage.persistence.AppendOnlyDataStoreService;
+
+import bisq.common.crypto.Sig;
+import bisq.common.util.Utilities;
+
+import org.bitcoinj.core.ECKey;
+
+import com.google.common.base.Charsets;
+
+import java.security.KeyPair;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+
+import java.util.Date;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class SignedWitnessServiceTest {
+ private SignedWitnessService service;
+
+ @Before
+ public void setup() {
+ AppendOnlyDataStoreService appendOnlyDataStoreService = mock(AppendOnlyDataStoreService.class);
+ ArbitratorManager arbitratorManager = mock(ArbitratorManager.class);
+ when(arbitratorManager.isPublicKeyInList(any())).thenReturn(true);
+ service = new SignedWitnessService(null, null, null, arbitratorManager, null, appendOnlyDataStoreService);
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ @Test
+ public void testIsValidAccountAgeWitnessOk() throws Exception {
+ testIsValidAccountAgeWitness(false, false, false, false);
+ }
+
+ @Test
+ public void testIsValidAccountAgeWitnessArbitratorSignatureProblem() throws Exception {
+ testIsValidAccountAgeWitness(true, false, false, false);
+ }
+
+ @Test
+ public void testIsValidAccountAgeWitnessPeerSignatureProblem() throws Exception {
+ testIsValidAccountAgeWitness(false, true, false, false);
+ }
+
+ @Test
+ public void testIsValidAccountAgeWitnessDateTooSoonProblem() throws Exception {
+ testIsValidAccountAgeWitness(false, false, true, false);
+ }
+
+ @Test
+ public void testIsValidAccountAgeWitnessDateTooLateProblem() throws Exception {
+ testIsValidAccountAgeWitness(false, false, false, true);
+ }
+
+ private void testIsValidAccountAgeWitness(boolean signature1Problem, boolean signature2Problem, boolean date3TooSoonProblem, boolean date3TooLateProblem) throws Exception {
+ byte[] account1DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{1});
+ byte[] account2DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{2});
+ byte[] account3DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{3});
+ long account1CreationTime = getTodayMinusNDays(96);
+ long account2CreationTime = getTodayMinusNDays(66);
+ long account3CreationTime = getTodayMinusNDays(36);
+ AccountAgeWitness aew1 = new AccountAgeWitness(account1DataHash, account1CreationTime);
+ AccountAgeWitness aew2 = new AccountAgeWitness(account2DataHash, account2CreationTime);
+ AccountAgeWitness aew3 = new AccountAgeWitness(account3DataHash, account3CreationTime);
+
+ ECKey arbitrator1Key = new ECKey();
+ KeyPair peer1KeyPair = Sig.generateKeyPair();
+ KeyPair peer2KeyPair = Sig.generateKeyPair();
+ KeyPair peer3KeyPair = Sig.generateKeyPair();
+
+
+ String account1DataHashAsHexString = Utilities.encodeToHex(account1DataHash);
+ String account2DataHashAsHexString = Utilities.encodeToHex(account2DataHash);
+ String account3DataHashAsHexString = Utilities.encodeToHex(account3DataHash);
+ String signature1String = arbitrator1Key.signMessage(account1DataHashAsHexString);
+ byte[] signature1 = signature1String.getBytes(Charsets.UTF_8);
+ if (signature1Problem) {
+ signature1 = new byte[]{1, 2, 3};
+ }
+ byte[] signature2 = Sig.sign(peer1KeyPair.getPrivate(), account2DataHashAsHexString.getBytes(Charsets.UTF_8));
+ if (signature2Problem) {
+ signature2 = new byte[]{1, 2, 3};
+ }
+ byte[] signature3 = Sig.sign(peer2KeyPair.getPrivate(), account3DataHashAsHexString.getBytes(Charsets.UTF_8));
+ byte[] signer1PubKey = arbitrator1Key.getPubKey();
+ byte[] signer2PubKey = Sig.getPublicKeyBytes(peer1KeyPair.getPublic());
+ byte[] signer3PubKey = Sig.getPublicKeyBytes(peer2KeyPair.getPublic());
+ byte[] witnessOwner1PubKey = Sig.getPublicKeyBytes(peer1KeyPair.getPublic());
+ byte[] witnessOwner2PubKey = Sig.getPublicKeyBytes(peer2KeyPair.getPublic());
+ byte[] witnessOwner3PubKey = Sig.getPublicKeyBytes(peer3KeyPair.getPublic());
+ long date1 = getTodayMinusNDays(95);
+ long date2 = getTodayMinusNDays(64);
+ long date3 = getTodayMinusNDays(33);
+ if (date3TooSoonProblem) {
+ date3 = getTodayMinusNDays(63);
+ } else if (date3TooLateProblem) {
+ date3 = getTodayMinusNDays(3);
+ }
+ long tradeAmount1 = 1000;
+ long tradeAmount2 = 1001;
+ long tradeAmount3 = 1001;
+
+ SignedWitness sw1 = new SignedWitness(true, account1DataHash, signature1, signer1PubKey, witnessOwner1PubKey, date1, tradeAmount1);
+ SignedWitness sw2 = new SignedWitness(false, account2DataHash, signature2, signer2PubKey, witnessOwner2PubKey, date2, tradeAmount2);
+ SignedWitness sw3 = new SignedWitness(false, account3DataHash, signature3, signer3PubKey, witnessOwner3PubKey, date3, tradeAmount3);
+
+ service.addToMap(sw1);
+ service.addToMap(sw2);
+ service.addToMap(sw3);
+
+ Assert.assertEquals(!signature1Problem, service.isValidAccountAgeWitness(aew1));
+ Assert.assertEquals(!signature1Problem && !signature2Problem, service.isValidAccountAgeWitness(aew2));
+ Assert.assertEquals(!signature1Problem && !signature2Problem && !date3TooSoonProblem && !date3TooLateProblem, service.isValidAccountAgeWitness(aew3));
+ }
+
+
+ @Test
+ public void testIsValidAccountAgeWitnessEndlessLoop() throws Exception {
+ byte[] account1DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{1});
+ byte[] account2DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{2});
+ byte[] account3DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{3});
+ long account1CreationTime = getTodayMinusNDays(96);
+ long account2CreationTime = getTodayMinusNDays(66);
+ long account3CreationTime = getTodayMinusNDays(36);
+ AccountAgeWitness aew1 = new AccountAgeWitness(account1DataHash, account1CreationTime);
+ AccountAgeWitness aew2 = new AccountAgeWitness(account2DataHash, account2CreationTime);
+ AccountAgeWitness aew3 = new AccountAgeWitness(account3DataHash, account3CreationTime);
+
+ KeyPair peer1KeyPair = Sig.generateKeyPair();
+ KeyPair peer2KeyPair = Sig.generateKeyPair();
+ KeyPair peer3KeyPair = Sig.generateKeyPair();
+
+
+ String account1DataHashAsHexString = Utilities.encodeToHex(account1DataHash);
+ String account2DataHashAsHexString = Utilities.encodeToHex(account2DataHash);
+ String account3DataHashAsHexString = Utilities.encodeToHex(account3DataHash);
+
+ byte[] signature1 = Sig.sign(peer3KeyPair.getPrivate(), account1DataHashAsHexString.getBytes(Charsets.UTF_8));
+ byte[] signature2 = Sig.sign(peer1KeyPair.getPrivate(), account2DataHashAsHexString.getBytes(Charsets.UTF_8));
+ byte[] signature3 = Sig.sign(peer2KeyPair.getPrivate(), account3DataHashAsHexString.getBytes(Charsets.UTF_8));
+
+ byte[] signer1PubKey = Sig.getPublicKeyBytes(peer3KeyPair.getPublic());
+ byte[] signer2PubKey = Sig.getPublicKeyBytes(peer1KeyPair.getPublic());
+ byte[] signer3PubKey = Sig.getPublicKeyBytes(peer2KeyPair.getPublic());
+ byte[] witnessOwner1PubKey = Sig.getPublicKeyBytes(peer1KeyPair.getPublic());
+ byte[] witnessOwner2PubKey = Sig.getPublicKeyBytes(peer2KeyPair.getPublic());
+ byte[] witnessOwner3PubKey = Sig.getPublicKeyBytes(peer3KeyPair.getPublic());
+ long date1 = getTodayMinusNDays(95);
+ long date2 = getTodayMinusNDays(64);
+ long date3 = getTodayMinusNDays(33);
+
+ long tradeAmount1 = 1000;
+ long tradeAmount2 = 1001;
+ long tradeAmount3 = 1001;
+
+ SignedWitness sw1 = new SignedWitness(false, account1DataHash, signature1, signer1PubKey, witnessOwner1PubKey, date1, tradeAmount1);
+ SignedWitness sw2 = new SignedWitness(false, account2DataHash, signature2, signer2PubKey, witnessOwner2PubKey, date2, tradeAmount2);
+ SignedWitness sw3 = new SignedWitness(false, account3DataHash, signature3, signer3PubKey, witnessOwner3PubKey, date3, tradeAmount3);
+
+ service.addToMap(sw1);
+ service.addToMap(sw2);
+ service.addToMap(sw3);
+
+ Assert.assertFalse(service.isValidAccountAgeWitness(aew3));
+ }
+
+
+ @Test
+ public void testIsValidAccountAgeWitnessLongLoop() throws Exception {
+ AccountAgeWitness aew = null;
+ KeyPair signerKeyPair = Sig.generateKeyPair();
+ KeyPair signedKeyPair = Sig.generateKeyPair();
+ int iterations = 1002;
+ for (int i = 0; i < iterations; i++) {
+ byte[] accountDataHash = org.bitcoinj.core.Utils.sha256hash160(String.valueOf(i).getBytes(Charsets.UTF_8));
+ long accountCreationTime = getTodayMinusNDays((iterations - i) * (SignedWitnessService.CHARGEBACK_SAFETY_DAYS + 1));
+ aew = new AccountAgeWitness(accountDataHash, accountCreationTime);
+ String accountDataHashAsHexString = Utilities.encodeToHex(accountDataHash);
+ byte[] signature;
+ byte[] signerPubKey;
+ if (i == 0) {
+ // use arbitrator key
+ ECKey arbitratorKey = new ECKey();
+ signedKeyPair = Sig.generateKeyPair();
+ String signature1String = arbitratorKey.signMessage(accountDataHashAsHexString);
+ signature = signature1String.getBytes(Charsets.UTF_8);
+ signerPubKey = arbitratorKey.getPubKey();
+ } else {
+ signerKeyPair = signedKeyPair;
+ signedKeyPair = Sig.generateKeyPair();
+ signature = Sig.sign(signedKeyPair.getPrivate(), accountDataHashAsHexString.getBytes(Charsets.UTF_8));
+ signerPubKey = Sig.getPublicKeyBytes(signerKeyPair.getPublic());
+ }
+ byte[] witnessOwnerPubKey = Sig.getPublicKeyBytes(signedKeyPair.getPublic());
+ long date = getTodayMinusNDays((iterations - i) * (SignedWitnessService.CHARGEBACK_SAFETY_DAYS + 1));
+ long tradeAmount = 1000;
+ SignedWitness sw = new SignedWitness(i == 0, accountDataHash, signature, signerPubKey, witnessOwnerPubKey, date, tradeAmount);
+ service.addToMap(sw);
+ }
+ Assert.assertFalse(service.isValidAccountAgeWitness(aew));
+ }
+
+
+ private long getTodayMinusNDays(long days) {
+ return Instant.ofEpochMilli(new Date().getTime()).minus(days, ChronoUnit.DAYS).toEpochMilli();
+ }
+
+}
+
diff --git a/core/src/test/java/bisq/core/payment/AccountAgeWitnessServiceTest.java b/core/src/test/java/bisq/core/account/witness/AccountAgeWitnessServiceTest.java
similarity index 99%
rename from core/src/test/java/bisq/core/payment/AccountAgeWitnessServiceTest.java
rename to core/src/test/java/bisq/core/account/witness/AccountAgeWitnessServiceTest.java
index b9af820237..c5f28113f5 100644
--- a/core/src/test/java/bisq/core/payment/AccountAgeWitnessServiceTest.java
+++ b/core/src/test/java/bisq/core/account/witness/AccountAgeWitnessServiceTest.java
@@ -15,7 +15,7 @@
* along with Bisq. If not, see .
*/
-package bisq.core.payment;
+package bisq.core.account.witness;
import bisq.common.crypto.CryptoException;
import bisq.common.crypto.Sig;
diff --git a/core/src/test/java/bisq/core/payment/PaymentAccountsTest.java b/core/src/test/java/bisq/core/payment/PaymentAccountsTest.java
index 871215967a..82f9c5f634 100644
--- a/core/src/test/java/bisq/core/payment/PaymentAccountsTest.java
+++ b/core/src/test/java/bisq/core/payment/PaymentAccountsTest.java
@@ -17,6 +17,8 @@
package bisq.core.payment;
+import bisq.core.account.witness.AccountAgeWitness;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.offer.Offer;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/PeerInfoIcon.java b/desktop/src/main/java/bisq/desktop/components/PeerInfoIcon.java
index 8886ec24bb..68e4d2f364 100644
--- a/desktop/src/main/java/bisq/desktop/components/PeerInfoIcon.java
+++ b/desktop/src/main/java/bisq/desktop/components/PeerInfoIcon.java
@@ -19,11 +19,11 @@ package bisq.desktop.components;
import bisq.desktop.main.overlays.editor.PeerInfoWithTagEditor;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.alert.PrivateNotificationManager;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.offer.Offer;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.trade.Trade;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/components/PeerInfoIconSmall.java b/desktop/src/main/java/bisq/desktop/components/PeerInfoIconSmall.java
index 1099282614..c07bc5ff32 100644
--- a/desktop/src/main/java/bisq/desktop/components/PeerInfoIconSmall.java
+++ b/desktop/src/main/java/bisq/desktop/components/PeerInfoIconSmall.java
@@ -1,8 +1,8 @@
package bisq.desktop.components;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.alert.PrivateNotificationManager;
import bisq.core.offer.Offer;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AdvancedCashForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AdvancedCashForm.java
index 44d03fbede..e605b48cfa 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AdvancedCashForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AdvancedCashForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.AdvancedCashValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.AdvancedCashAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.AdvancedCashAccountPayload;
@@ -37,17 +37,15 @@ import bisq.common.util.Tuple2;
import org.apache.commons.lang3.StringUtils;
import javafx.scene.control.Label;
-import javafx.scene.control.TextField;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
-import javafx.geometry.Insets;
-import javafx.geometry.VPos;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static bisq.desktop.util.FormBuilder.*;
+import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextField;
+import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextFieldWithCopyIcon;
+import static bisq.desktop.util.FormBuilder.addTopLabelFlowPane;
@Deprecated
public class AdvancedCashForm extends PaymentMethodForm {
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AliPayForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AliPayForm.java
index 3b565c8165..1d93e374f0 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AliPayForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AliPayForm.java
@@ -19,8 +19,8 @@ package bisq.desktop.components.paymentmethods;
import bisq.desktop.util.validation.AliPayValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.AliPayAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.AliPayAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AssetsForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AssetsForm.java
index 76bad08bbe..ad6c6d0eb4 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/AssetsForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/AssetsForm.java
@@ -23,12 +23,12 @@ import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.dao.governance.asset.AssetService;
import bisq.core.filter.FilterManager;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.AssetAccount;
import bisq.core.payment.InstantCryptoCurrencyAccount;
import bisq.core.payment.PaymentAccount;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/BankForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/BankForm.java
index 0c1b303495..f9b2d13127 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/BankForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/BankForm.java
@@ -21,6 +21,7 @@ import bisq.desktop.components.InputTextField;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.BankUtil;
import bisq.core.locale.Country;
import bisq.core.locale.CountryUtil;
@@ -28,7 +29,6 @@ import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.FiatCurrency;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.CountryBasedPaymentAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.BankAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/CashDepositForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/CashDepositForm.java
index 04ce422bca..d61d204392 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/CashDepositForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/CashDepositForm.java
@@ -22,6 +22,7 @@ import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.EmailValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.BankUtil;
import bisq.core.locale.Country;
import bisq.core.locale.CountryUtil;
@@ -29,7 +30,6 @@ import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.FiatCurrency;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.CountryBasedPaymentAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.CashDepositAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/ChaseQuickPayForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/ChaseQuickPayForm.java
index 291358e60b..77bc4f7eae 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/ChaseQuickPayForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/ChaseQuickPayForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.ChaseQuickPayValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.ChaseQuickPayAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.ChaseQuickPayAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/ClearXchangeForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/ClearXchangeForm.java
index 83f65bfe62..85111a06c8 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/ClearXchangeForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/ClearXchangeForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.ClearXchangeValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.ClearXchangeAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.ClearXchangeAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java
index 5ead5ebc66..10f10f2e7d 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/F2FForm.java
@@ -23,6 +23,7 @@ import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.F2FValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Country;
import bisq.core.locale.CountryUtil;
import bisq.core.locale.CurrencyUtil;
@@ -30,7 +31,6 @@ import bisq.core.locale.FiatCurrency;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
import bisq.core.offer.Offer;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.CountryBasedPaymentAccount;
import bisq.core.payment.F2FAccount;
import bisq.core.payment.PaymentAccount;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/FasterPaymentsForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/FasterPaymentsForm.java
index cdeb6aaceb..ad68a8f8dc 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/FasterPaymentsForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/FasterPaymentsForm.java
@@ -23,9 +23,9 @@ import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.AccountNrValidator;
import bisq.desktop.util.validation.BranchIdValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.FasterPaymentsAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.FasterPaymentsAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralAccountNumberForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralAccountNumberForm.java
index b32d0704b3..7cf16a67cb 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralAccountNumberForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralAccountNumberForm.java
@@ -3,9 +3,9 @@ package bisq.desktop.components.paymentmethods;
import bisq.desktop.components.InputTextField;
import bisq.desktop.util.Layout;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralBankForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralBankForm.java
index 2e3935d85b..9ea45fd7b7 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralBankForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralBankForm.java
@@ -6,9 +6,9 @@ import bisq.desktop.util.validation.BankIdValidator;
import bisq.desktop.util.validation.BranchIdValidator;
import bisq.desktop.util.validation.NationalAccountIdValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.BankUtil;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.CountryBasedPaymentAccountPayload;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralSepaForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralSepaForm.java
index d6c1d2013e..83a14f3923 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralSepaForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralSepaForm.java
@@ -3,11 +3,11 @@ package bisq.desktop.components.paymentmethods;
import bisq.desktop.components.InputTextField;
import bisq.desktop.util.FormBuilder;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Country;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.CountryBasedPaymentAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/HalCashForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/HalCashForm.java
index 1fb08de78c..2aaff157a5 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/HalCashForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/HalCashForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.HalCashValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.HalCashAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.HalCashAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/InteracETransferForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/InteracETransferForm.java
index ffe20fccb4..bbde09363f 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/InteracETransferForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/InteracETransferForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.InteracETransferValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.InteracETransferAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.InteracETransferAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyBeamForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyBeamForm.java
index 39e741f2bc..1659b16a01 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyBeamForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyBeamForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.MoneyBeamValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.MoneyBeamAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.MoneyBeamAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java
index a6b1b67352..9fe85cd0a9 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/MoneyGramForm.java
@@ -22,12 +22,12 @@ import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.EmailValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.BankUtil;
import bisq.core.locale.Country;
import bisq.core.locale.CountryUtil;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.MoneyGramAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.MoneyGramAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/NationalBankForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/NationalBankForm.java
index ec2edc7e58..c0753c61af 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/NationalBankForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/NationalBankForm.java
@@ -17,7 +17,7 @@
package bisq.desktop.components.paymentmethods;
-import bisq.core.payment.AccountAgeWitnessService;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PaymentMethodForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PaymentMethodForm.java
index 61d965a708..2f962975e7 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PaymentMethodForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PaymentMethodForm.java
@@ -24,13 +24,13 @@ import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Country;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.FiatCurrency;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
import bisq.core.offer.Offer;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.AssetAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PerfectMoneyForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PerfectMoneyForm.java
index dfb799201c..4e71a5a92e 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PerfectMoneyForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PerfectMoneyForm.java
@@ -19,9 +19,9 @@ package bisq.desktop.components.paymentmethods;
import bisq.desktop.util.validation.PerfectMoneyValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.FiatCurrency;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PerfectMoneyAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PopmoneyForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PopmoneyForm.java
index a5c629e91a..ee1e3666b7 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PopmoneyForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PopmoneyForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.PopmoneyValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PopmoneyAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PromptPayForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PromptPayForm.java
index 7ddeb92d14..c5c5f47ff5 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/PromptPayForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/PromptPayForm.java
@@ -21,9 +21,9 @@ import bisq.desktop.components.InputTextField;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.PromptPayValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PromptPayAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/RevolutForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/RevolutForm.java
index e01833c5e4..d9d26dc833 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/RevolutForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/RevolutForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.RevolutValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.RevolutAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SameBankForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SameBankForm.java
index a6ca52f80b..617e224f4c 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SameBankForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SameBankForm.java
@@ -17,7 +17,7 @@
package bisq.desktop.components.paymentmethods;
-import bisq.core.payment.AccountAgeWitnessService;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SepaForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SepaForm.java
index 3ebad03ad0..6e80d315ae 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SepaForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SepaForm.java
@@ -23,12 +23,12 @@ import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.BICValidator;
import bisq.desktop.util.validation.IBANValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Country;
import bisq.core.locale.CountryUtil;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.SepaAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SepaInstantForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SepaInstantForm.java
index 545a161889..fb57147b40 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SepaInstantForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SepaInstantForm.java
@@ -23,12 +23,12 @@ import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.BICValidator;
import bisq.desktop.util.validation.IBANValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Country;
import bisq.core.locale.CountryUtil;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.SepaInstantAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SpecificBankForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SpecificBankForm.java
index 1f0e6fd377..96bcb07a6e 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SpecificBankForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SpecificBankForm.java
@@ -19,8 +19,8 @@ package bisq.desktop.components.paymentmethods;
import bisq.desktop.components.InputTextField;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.SpecificBanksAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SwishForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SwishForm.java
index 4258f6214c..c8f22f7cfe 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SwishForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SwishForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.SwishValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.SwishAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/USPostalMoneyOrderForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/USPostalMoneyOrderForm.java
index 0aa70c7049..fbb988e8c6 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/USPostalMoneyOrderForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/USPostalMoneyOrderForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.USPostalMoneyOrderValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.USPostalMoneyOrderAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/UpholdForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/UpholdForm.java
index 2ee6dae511..9e00124a9b 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/UpholdForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/UpholdForm.java
@@ -22,9 +22,9 @@ import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.UpholdValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.UpholdAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/WeChatPayForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/WeChatPayForm.java
index 7292f2eeb2..60ba1bd3ee 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/WeChatPayForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/WeChatPayForm.java
@@ -19,8 +19,8 @@ package bisq.desktop.components.paymentmethods;
import bisq.desktop.util.validation.WeChatPayValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.WeChatPayAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/WesternUnionForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/WesternUnionForm.java
index 9470cd2b2c..1526ece284 100644
--- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/WesternUnionForm.java
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/WesternUnionForm.java
@@ -23,13 +23,13 @@ import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.EmailValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.BankUtil;
import bisq.core.locale.Country;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.FiatCurrency;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.CountryBasedPaymentAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
diff --git a/desktop/src/main/java/bisq/desktop/main/MainViewModel.java b/desktop/src/main/java/bisq/desktop/main/MainViewModel.java
index bc180a27d6..61aefb01d4 100644
--- a/desktop/src/main/java/bisq/desktop/main/MainViewModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/MainViewModel.java
@@ -34,6 +34,7 @@ import bisq.desktop.main.presentation.DaoPresentation;
import bisq.desktop.main.presentation.MarketPricePresentation;
import bisq.desktop.util.GUIUtil;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.alert.PrivateNotificationManager;
import bisq.core.app.AppOptionKeys;
import bisq.core.app.BisqEnvironment;
@@ -42,7 +43,6 @@ import bisq.core.btc.setup.WalletsSetup;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.AliPayAccount;
import bisq.core.payment.CryptoCurrencyAccount;
import bisq.core.presentation.BalancePresentation;
diff --git a/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java b/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java
index 11fbec3a87..b37aa50d3a 100644
--- a/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java
@@ -20,11 +20,11 @@ package bisq.desktop.main.account.content.altcoinaccounts;
import bisq.desktop.common.model.ActivatableDataModel;
import bisq.desktop.util.GUIUtil;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.CryptoCurrency;
import bisq.core.locale.FiatCurrency;
import bisq.core.locale.TradeCurrency;
import bisq.core.offer.OpenOfferManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.AssetAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.trade.TradeManager;
diff --git a/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsView.java b/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsView.java
index 0ca30300bc..c00bb275b5 100644
--- a/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsView.java
+++ b/desktop/src/main/java/bisq/desktop/main/account/content/altcoinaccounts/AltCoinAccountsView.java
@@ -26,13 +26,13 @@ import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.dao.governance.asset.AssetService;
import bisq.core.filter.FilterManager;
import bisq.core.locale.CryptoCurrency;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountFactory;
import bisq.core.payment.payload.PaymentMethod;
diff --git a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsDataModel.java b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsDataModel.java
index a60cc95e07..331fbf237c 100644
--- a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsDataModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsDataModel.java
@@ -20,12 +20,12 @@ package bisq.desktop.main.account.content.fiataccounts;
import bisq.desktop.common.model.ActivatableDataModel;
import bisq.desktop.util.GUIUtil;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.CryptoCurrency;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.FiatCurrency;
import bisq.core.locale.TradeCurrency;
import bisq.core.offer.OpenOfferManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.AssetAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.trade.TradeManager;
diff --git a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java
index 2360dc15fb..ff10dec601 100644
--- a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java
+++ b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java
@@ -69,9 +69,9 @@ import bisq.desktop.util.validation.USPostalMoneyOrderValidator;
import bisq.desktop.util.validation.UpholdValidator;
import bisq.desktop.util.validation.WeChatPayValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.app.BisqEnvironment;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.CashDepositAccount;
import bisq.core.payment.ClearXchangeAccount;
import bisq.core.payment.F2FAccount;
diff --git a/desktop/src/main/java/bisq/desktop/main/disputes/arbitrator/ArbitratorDisputeView.java b/desktop/src/main/java/bisq/desktop/main/disputes/arbitrator/ArbitratorDisputeView.java
index c7f8ecb340..f21f53fa39 100644
--- a/desktop/src/main/java/bisq/desktop/main/disputes/arbitrator/ArbitratorDisputeView.java
+++ b/desktop/src/main/java/bisq/desktop/main/disputes/arbitrator/ArbitratorDisputeView.java
@@ -23,10 +23,10 @@ import bisq.desktop.main.overlays.windows.ContractWindow;
import bisq.desktop.main.overlays.windows.DisputeSummaryWindow;
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.alert.PrivateNotificationManager;
import bisq.core.app.AppOptionKeys;
import bisq.core.arbitration.DisputeManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.trade.TradeManager;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/main/disputes/trader/TraderDisputeView.java b/desktop/src/main/java/bisq/desktop/main/disputes/trader/TraderDisputeView.java
index 753c795638..9f1b4d5a84 100644
--- a/desktop/src/main/java/bisq/desktop/main/disputes/trader/TraderDisputeView.java
+++ b/desktop/src/main/java/bisq/desktop/main/disputes/trader/TraderDisputeView.java
@@ -35,6 +35,7 @@ import bisq.desktop.main.overlays.windows.SendPrivateNotificationWindow;
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
import bisq.desktop.util.GUIUtil;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.alert.PrivateNotificationManager;
import bisq.core.app.AppOptionKeys;
import bisq.core.arbitration.Attachment;
@@ -43,7 +44,6 @@ import bisq.core.arbitration.DisputeManager;
import bisq.core.arbitration.messages.DisputeCommunicationMessage;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.trade.Contract;
import bisq.core.trade.Trade;
import bisq.core.trade.TradeManager;
diff --git a/desktop/src/main/java/bisq/desktop/main/market/offerbook/OfferBookChartViewModel.java b/desktop/src/main/java/bisq/desktop/main/market/offerbook/OfferBookChartViewModel.java
index 397b374641..74220d84f4 100644
--- a/desktop/src/main/java/bisq/desktop/main/market/offerbook/OfferBookChartViewModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/market/offerbook/OfferBookChartViewModel.java
@@ -28,13 +28,13 @@ import bisq.desktop.util.CurrencyList;
import bisq.desktop.util.CurrencyListItem;
import bisq.desktop.util.GUIUtil;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.GlobalSettings;
import bisq.core.locale.TradeCurrency;
import bisq.core.monetary.Price;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java
index 67f5188062..325ebcace3 100644
--- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java
@@ -17,6 +17,8 @@
package bisq.desktop.main.offer;
+import bisq.core.account.witness.AccountAgeRestrictions;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.arbitration.Arbitrator;
import bisq.core.btc.TxFeeEstimationService;
import bisq.core.btc.listeners.BalanceListener;
@@ -35,8 +37,6 @@ import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferUtil;
import bisq.core.offer.OpenOfferManager;
-import bisq.core.payment.AccountAgeRestrictions;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.HalCashAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil;
diff --git a/desktop/src/main/java/bisq/desktop/main/offer/createoffer/CreateOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/offer/createoffer/CreateOfferDataModel.java
index 2128616636..0fb6b01db0 100644
--- a/desktop/src/main/java/bisq/desktop/main/offer/createoffer/CreateOfferDataModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/offer/createoffer/CreateOfferDataModel.java
@@ -23,12 +23,12 @@ package bisq.desktop.main.offer.createoffer;
import bisq.desktop.main.offer.MutableOfferDataModel;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.TxFeeEstimationService;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.filter.FilterManager;
import bisq.core.offer.OpenOfferManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.statistics.ReferralIdService;
diff --git a/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java
index f3a0d9ed6b..b6bcef8e24 100644
--- a/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/offer/offerbook/OfferBookViewModel.java
@@ -24,6 +24,7 @@ import bisq.desktop.main.settings.SettingsView;
import bisq.desktop.main.settings.preferences.PreferencesView;
import bisq.desktop.util.GUIUtil;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.filter.FilterManager;
import bisq.core.locale.BankUtil;
import bisq.core.locale.CountryUtil;
@@ -37,7 +38,6 @@ import bisq.core.monetary.Volume;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OpenOfferManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil;
import bisq.core.payment.payload.PaymentMethod;
diff --git a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java
index 5d2dfabbc0..e27356082d 100644
--- a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferDataModel.java
@@ -20,6 +20,8 @@ package bisq.desktop.main.offer.takeoffer;
import bisq.desktop.main.offer.OfferDataModel;
import bisq.desktop.main.overlays.popups.Popup;
+import bisq.core.account.witness.AccountAgeRestrictions;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.arbitration.Arbitrator;
import bisq.core.btc.TxFeeEstimationService;
import bisq.core.btc.listeners.BalanceListener;
@@ -35,8 +37,6 @@ import bisq.core.monetary.Volume;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferUtil;
-import bisq.core.payment.AccountAgeRestrictions;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.HalCashAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil;
diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/ContractWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/ContractWindow.java
index 17c3d26925..0d04a44896 100644
--- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/ContractWindow.java
+++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/ContractWindow.java
@@ -22,13 +22,13 @@ import bisq.desktop.main.MainView;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.util.Layout;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.arbitration.Dispute;
import bisq.core.arbitration.DisputeManager;
import bisq.core.locale.CountryUtil;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.offer.Offer;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.Contract;
diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java
index d76732e8da..6c3d94152d 100644
--- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java
+++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java
@@ -23,11 +23,11 @@ import bisq.desktop.main.MainView;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.util.Layout;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.arbitration.DisputeManager;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.offer.Offer;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.trade.Contract;
import bisq.core.trade.Trade;
diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java
index d6865f836a..a54848066d 100644
--- a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java
@@ -20,9 +20,9 @@ package bisq.desktop.main.portfolio.closedtrades;
import bisq.desktop.common.model.ActivatableWithDataModel;
import bisq.desktop.common.model.ViewModel;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.offer.OpenOffer;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.trade.Tradable;
import bisq.core.trade.Trade;
import bisq.core.util.BSFormatter;
diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModel.java
index 27772a2941..fd38c89ddd 100644
--- a/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModel.java
@@ -20,6 +20,7 @@ package bisq.desktop.main.portfolio.editoffer;
import bisq.desktop.main.offer.MutableOfferDataModel;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.TxFeeEstimationService;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
@@ -31,7 +32,6 @@ import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OpenOffer;
import bisq.core.offer.OpenOfferManager;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.proto.persistable.CorePersistenceProtoResolver;
import bisq.core.provider.fee.FeeService;
diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java
index 319f8dd844..43f187028e 100644
--- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java
@@ -26,6 +26,7 @@ import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.main.overlays.windows.WalletPasswordWindow;
import bisq.desktop.util.GUIUtil;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.arbitration.Dispute;
import bisq.core.arbitration.DisputeAlreadyOpenException;
import bisq.core.arbitration.DisputeManager;
@@ -34,7 +35,6 @@ import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.locale.Res;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.trade.BuyerTrade;
import bisq.core.trade.SellerTrade;
diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java
index 234a216497..2236da4963 100644
--- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java
@@ -21,10 +21,10 @@ import bisq.desktop.common.model.ActivatableWithDataModel;
import bisq.desktop.common.model.ViewModel;
import bisq.desktop.util.GUIUtil;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Res;
import bisq.core.network.MessageState;
import bisq.core.offer.Offer;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.trade.Contract;
import bisq.core.trade.Trade;
import bisq.core.trade.closed.ClosedTradableManager;
diff --git a/desktop/src/test/java/bisq/desktop/main/offer/createoffer/CreateOfferViewModelTest.java b/desktop/src/test/java/bisq/desktop/main/offer/createoffer/CreateOfferViewModelTest.java
index e0173a6b2f..5fb65904bd 100644
--- a/desktop/src/test/java/bisq/desktop/main/offer/createoffer/CreateOfferViewModelTest.java
+++ b/desktop/src/test/java/bisq/desktop/main/offer/createoffer/CreateOfferViewModelTest.java
@@ -22,6 +22,7 @@ import bisq.desktop.util.validation.BtcValidator;
import bisq.desktop.util.validation.FiatPriceValidator;
import bisq.desktop.util.validation.SecurityDepositValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.TxFeeEstimationService;
import bisq.core.btc.model.AddressEntry;
import bisq.core.btc.wallet.BsqWalletService;
@@ -31,7 +32,6 @@ import bisq.core.locale.CryptoCurrency;
import bisq.core.locale.GlobalSettings;
import bisq.core.locale.Res;
import bisq.core.offer.OfferPayload;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.MarketPrice;
diff --git a/desktop/src/test/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModelTest.java b/desktop/src/test/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModelTest.java
index 2cece3114c..e6c9e798d1 100644
--- a/desktop/src/test/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModelTest.java
+++ b/desktop/src/test/java/bisq/desktop/main/portfolio/editoffer/EditOfferDataModelTest.java
@@ -2,6 +2,7 @@ package bisq.desktop.main.portfolio.editoffer;
import bisq.desktop.util.validation.SecurityDepositValidator;
+import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.model.AddressEntry;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
@@ -11,7 +12,6 @@ import bisq.core.locale.GlobalSettings;
import bisq.core.locale.Res;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OpenOffer;
-import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.CryptoCurrencyAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.provider.fee.FeeService;