add missing files

This commit is contained in:
Manfred Karrer 2015-10-28 13:34:03 +01:00
parent c6ece486ed
commit 9ef8b42509
239 changed files with 20558 additions and 51 deletions

View file

@ -0,0 +1,16 @@
package io.bitsquare.p2p.seed;
import java.security.NoSuchAlgorithmException;
public class SeedNodeMain {
// args: port useLocalhost seedNodes
// eg. 4444 true localhost:7777 localhost:8888
// To stop enter: q
public static void main(String[] args) throws NoSuchAlgorithmException {
SeedNode seedNode = new SeedNode();
seedNode.processArgs(args);
seedNode.createAndStartP2PService();
seedNode.listenForExitCommand();
}
}

28
common/pom.xml Normal file
View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.3.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common</artifactId>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.1.RELEASE</version>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,65 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app;
import com.google.common.base.Preconditions;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import org.springframework.core.env.Environment;
import java.util.ArrayList;
import java.util.List;
public abstract class AppModule extends AbstractModule {
protected final Environment env;
private final List<AppModule> modules = new ArrayList<>();
protected AppModule(Environment env) {
Preconditions.checkNotNull(env, "Environment must not be null");
this.env = env;
}
protected void install(AppModule module) {
super.install(module);
modules.add(module);
}
/**
* Close any instances this module is responsible for and recursively close any
* sub-modules installed via {@link #install(AppModule)}. This method
* must be called manually, e.g. at the end of a main() method or in the stop() method
* of a JavaFX Application; alternatively it may be registered as a JVM shutdown hook.
*
* @param injector the Injector originally initialized with this module
* @see #doClose(com.google.inject.Injector)
*/
public final void close(Injector injector) {
modules.forEach(module -> module.close(injector));
doClose(injector);
}
/**
* Actually perform closing of any instances this module is responsible for. Called by
* {@link #close(Injector)}.
*
* @param injector the Injector originally initialized with this module
*/
protected void doClose(Injector injector) {
}
}

View file

@ -0,0 +1,19 @@
package io.bitsquare.app;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// TODO too app specific for common...
public class ProgramArguments {
// program arg names
public static final String TOR_DIR = "torDir";
public static final String USE_LOCALHOST = "useLocalhost";
public static final String DEV_TEST = "devTest";
public static final String NAME_KEY = "node.name";
public static final String PORT_KEY = "node.port";
private static final Logger log = LoggerFactory.getLogger(ProgramArguments.class);
}

View file

@ -0,0 +1,45 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Version {
private static final Logger log = LoggerFactory.getLogger(Version.class);
// The application versions
private static final int MAJOR_VERSION = 0;
private static final int MINOR_VERSION = 3;
// used as updateFX index
public static final int PATCH_VERSION = 2;
public static final String VERSION = MAJOR_VERSION + "." + MINOR_VERSION + "." + PATCH_VERSION;
// The version nr. for the objects sent over the network. A change will break the serialization of old objects.
// If objects are used for both network and database the network version is applied.
public static final long NETWORK_PROTOCOL_VERSION = 1;
// The version nr. of the serialized data stored to disc. A change will break the serialization of old objects.
public static final long LOCAL_DB_VERSION = 1;
// The version nr. of the current protocol. The offer holds that version. A taker will check the version of the offers to see if he his version is
// compatible.
public static final long PROTOCOL_VERSION = 1;
}

View file

@ -0,0 +1,81 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
public class ByteArrayUtils {
private static final Logger log = LoggerFactory.getLogger(ByteArrayUtils.class);
private static long lastTimeStamp = System.currentTimeMillis();
public static <T> T byteArrayToObject(byte[] data) {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInput in = null;
Object result = null;
try {
in = new ObjectInputStream(bis);
result = in.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bis.close();
} catch (IOException ex) {
// ignore close exception
}
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
// ignore close exception
}
}
return (T) result;
}
public static byte[] objectToByteArray(Object object) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
byte[] result = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(object);
result = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException ex) {
// ignore close exception
}
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
return result;
}
}

View file

@ -0,0 +1,38 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class UserThread {
public static Executor getExecutor() {
return executor;
}
public static void setExecutor(Executor executor) {
UserThread.executor = executor;
}
public static Executor executor = Executors.newSingleThreadExecutor();
public static void execute(Runnable command) {
UserThread.executor.execute(command);
}
}

View file

@ -0,0 +1,25 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.handlers;
/**
* For reporting error message only (UI)
*/
public interface ErrorMessageHandler {
void handleErrorMessage(String errorMessage);
}

View file

@ -0,0 +1,25 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.handlers;
/**
* For reporting throwable objects only
*/
public interface ExceptionHandler {
void handleException(Throwable throwable);
}

View file

@ -0,0 +1,25 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.handlers;
/**
* For reporting a description message and throwable
*/
public interface FaultHandler {
void handleFault(String errorMessage, Throwable throwable);
}

View file

@ -0,0 +1,22 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.handlers;
public interface ResultHandler extends Runnable {
void handleResult();
}

View file

@ -0,0 +1,30 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.taskrunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InterceptTaskException extends RuntimeException {
private static final Logger log = LoggerFactory.getLogger(InterceptTaskException.class);
private static final long serialVersionUID = 5216202440370333534L;
public InterceptTaskException(String message) {
super(message);
}
}

View file

@ -0,0 +1,24 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.taskrunner;
public interface Model {
void persist();
void onComplete();
}

View file

@ -0,0 +1,74 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.taskrunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class Task<T extends Model> {
private static final Logger log = LoggerFactory.getLogger(Task.class);
public static Class<? extends Task> taskToIntercept;
private final TaskRunner taskHandler;
protected final T model;
protected String errorMessage = "An error occurred at task: " + getClass().getSimpleName();
public Task(TaskRunner taskHandler, T model) {
this.taskHandler = taskHandler;
this.model = model;
}
abstract protected void run();
protected void runInterceptHook() {
if (getClass() == taskToIntercept)
throw new InterceptTaskException("Task intercepted for testing purpose. Task = " + getClass().getSimpleName());
}
protected void appendToErrorMessage(String message) {
errorMessage += "\n" + message;
}
protected void appendExceptionToErrorMessage(Throwable t) {
if (t.getMessage() != null)
errorMessage += "\nException message: " + t.getMessage();
else
errorMessage += "\nException: " + t.toString();
}
protected void complete() {
taskHandler.handleComplete();
}
protected void failed(String message) {
appendToErrorMessage(message);
failed();
}
protected void failed(Throwable t) {
t.printStackTrace();
appendExceptionToErrorMessage(t);
failed();
}
protected void failed() {
taskHandler.handleErrorMessage(errorMessage);
}
}

View file

@ -0,0 +1,95 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.taskrunner;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
public class TaskRunner<T extends Model> {
private static final Logger log = LoggerFactory.getLogger(TaskRunner.class);
private final Queue<Class<? extends Task>> tasks = new LinkedBlockingQueue<>();
private final T sharedModel;
private final Class<T> sharedModelClass;
private final ResultHandler resultHandler;
private final ErrorMessageHandler errorMessageHandler;
private boolean failed = false;
private boolean isCanceled;
private Class<? extends Task> currentTask;
public TaskRunner(T sharedModel, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
this(sharedModel, (Class<T>) sharedModel.getClass(), resultHandler, errorMessageHandler);
}
public TaskRunner(T sharedModel, Class<T> sharedModelClass, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
this.sharedModel = sharedModel;
this.resultHandler = resultHandler;
this.errorMessageHandler = errorMessageHandler;
this.sharedModelClass = sharedModelClass;
}
public final void addTasks(Class<? extends Task<T>>... items) {
tasks.addAll(Arrays.asList(items));
}
public void run() {
next();
}
private void next() {
if (!failed && !isCanceled) {
if (tasks.size() > 0) {
try {
currentTask = tasks.poll();
log.trace("Run task: " + currentTask.getSimpleName());
currentTask.getDeclaredConstructor(TaskRunner.class, sharedModelClass).newInstance(this, sharedModel).run();
} catch (Throwable throwable) {
throwable.printStackTrace();
handleErrorMessage("Error at taskRunner: " + throwable.getMessage());
}
} else {
resultHandler.handleResult();
}
}
}
public void cancel() {
isCanceled = true;
}
void handleComplete() {
log.trace("Task completed: " + currentTask.getSimpleName());
sharedModel.persist();
next();
}
void handleErrorMessage(String errorMessage) {
log.error("Task failed: " + currentTask.getSimpleName());
log.error("errorMessage: " + errorMessage);
failed = true;
errorMessageHandler.handleErrorMessage(errorMessage);
}
}

View file

@ -0,0 +1,28 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonExclude {
}

View file

@ -0,0 +1,34 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Profiler {
private static final Logger log = LoggerFactory.getLogger(Profiler.class);
public static void printSystemLoad(Logger log) {
Runtime runtime = Runtime.getRuntime();
long free = runtime.freeMemory() / 1024 / 1024;
long total = runtime.totalMemory() / 1024 / 1024;
long used = total - free;
log.info("System load (nr. threads/used memory (MB)): " + Thread.activeCount() + "/" + used);
}
}

View file

@ -0,0 +1,47 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.util;
public class Tuple2<A, B> {
final public A first;
final public B second;
public Tuple2(A first, B second) {
this.first = first;
this.second = second;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Tuple2)) return false;
Tuple2<?, ?> tuple2 = (Tuple2<?, ?>) o;
if (first != null ? !first.equals(tuple2.first) : tuple2.first != null) return false;
return !(second != null ? !second.equals(tuple2.second) : tuple2.second != null);
}
@Override
public int hashCode() {
int result = first != null ? first.hashCode() : 0;
result = 31 * result + (second != null ? second.hashCode() : 0);
return result;
}
}

View file

@ -0,0 +1,51 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.common.util;
public class Tuple3<A, B, C> {
final public A first;
final public B second;
final public C third;
public Tuple3(A first, B second, C third) {
this.first = first;
this.second = second;
this.third = third;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Tuple3)) return false;
Tuple3<?, ?, ?> tuple3 = (Tuple3<?, ?, ?>) o;
if (first != null ? !first.equals(tuple3.first) : tuple3.first != null) return false;
if (second != null ? !second.equals(tuple3.second) : tuple3.second != null) return false;
return !(third != null ? !third.equals(tuple3.third) : tuple3.third != null);
}
@Override
public int hashCode() {
int result = first != null ? first.hashCode() : 0;
result = 31 * result + (second != null ? second.hashCode() : 0);
result = 31 * result + (third != null ? third.hashCode() : 0);
return result;
}
}

View file

@ -0,0 +1,84 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.alert;
import io.bitsquare.app.Version;
import io.bitsquare.p2p.storage.data.PubKeyProtectedExpirablePayload;
import java.security.PublicKey;
public final class Alert implements PubKeyProtectedExpirablePayload {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
public static final long TTL = 10 * 24 * 60 * 60 * 1000; // 10 days
public final String message;
private String signatureAsBase64;
private PublicKey storagePublicKey;
public Alert(String message) {
this.message = message;
}
public void setSigAndStoragePubKey(String signatureAsBase64, PublicKey storagePublicKey) {
this.signatureAsBase64 = signatureAsBase64;
this.storagePublicKey = storagePublicKey;
}
public String getSignatureAsBase64() {
return signatureAsBase64;
}
@Override
public long getTTL() {
return TTL;
}
@Override
public PublicKey getPubKey() {
return storagePublicKey;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Alert)) return false;
Alert that = (Alert) o;
if (message != null ? !message.equals(that.message) : that.message != null) return false;
return !(getSignatureAsBase64() != null ? !getSignatureAsBase64().equals(that.getSignatureAsBase64()) : that.getSignatureAsBase64() != null);
}
@Override
public int hashCode() {
int result = message != null ? message.hashCode() : 0;
result = 31 * result + (getSignatureAsBase64() != null ? getSignatureAsBase64().hashCode() : 0);
return result;
}
@Override
public String toString() {
return "AlertMessage{" +
"message='" + message + '\'' +
", signature.hashCode()='" + signatureAsBase64.hashCode() + '\'' +
'}';
}
}

View file

@ -0,0 +1,144 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.alert;
import com.google.inject.Inject;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.p2p.storage.HashSetChangedListener;
import io.bitsquare.p2p.storage.data.ProtectedData;
import io.bitsquare.user.User;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.SignatureException;
import static org.bitcoinj.core.Utils.HEX;
public class AlertManager {
transient private static final Logger log = LoggerFactory.getLogger(AlertManager.class);
private final AlertService alertService;
private KeyRing keyRing;
private User user;
private final ObjectProperty<Alert> alertMessageProperty = new SimpleObjectProperty<>();
// Pub key for developer global alert message
private static final String devPubKeyAsHex = "02682880ae61fc1ea9375198bf2b5594fc3ed28074d3f5f0ed907e38acc5fb1fdc";
private ECKey alertSigningKey;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, Initialization
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public AlertManager(AlertService alertService, KeyRing keyRing, User user) {
this.alertService = alertService;
this.keyRing = keyRing;
this.user = user;
alertService.addHashSetChangedListener(new HashSetChangedListener() {
@Override
public void onAdded(ProtectedData entry) {
Serializable data = entry.expirablePayload;
if (data instanceof Alert) {
Alert alert = (Alert) data;
if (verifySignature(alert))
alertMessageProperty.set(alert);
}
}
@Override
public void onRemoved(ProtectedData entry) {
Serializable data = entry.expirablePayload;
if (data instanceof Alert) {
Alert alert = (Alert) data;
if (verifySignature(alert))
alertMessageProperty.set(null);
}
}
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public ReadOnlyObjectProperty<Alert> alertMessageProperty() {
return alertMessageProperty;
}
public boolean addAlertMessageIfKeyIsValid(Alert alert, String privKeyString) {
// if there is a previous message we remove that first
if (user.getDevelopersAlert() != null)
removeAlertMessageIfKeyIsValid(privKeyString);
boolean isKeyValid = isKeyValid(privKeyString);
if (isKeyValid) {
signAndAddSignatureToAlertMessage(alert);
user.setDevelopersAlert(alert);
alertService.addAlertMessage(alert, null, null);
}
return isKeyValid;
}
public boolean removeAlertMessageIfKeyIsValid(String privKeyString) {
Alert developersAlert = user.getDevelopersAlert();
if (isKeyValid(privKeyString) && developersAlert != null) {
alertService.removeAlertMessage(developersAlert, null, null);
user.setDevelopersAlert(null);
return true;
} else {
return false;
}
}
private boolean isKeyValid(String privKeyString) {
try {
alertSigningKey = ECKey.fromPrivate(new BigInteger(1, HEX.decode(privKeyString)));
return devPubKeyAsHex.equals(Utils.HEX.encode(alertSigningKey.getPubKey()));
} catch (Throwable t) {
return false;
}
}
private void signAndAddSignatureToAlertMessage(Alert alert) {
String alertMessageAsHex = Utils.HEX.encode(alert.message.getBytes());
String signatureAsBase64 = alertSigningKey.signMessage(alertMessageAsHex);
alert.setSigAndStoragePubKey(signatureAsBase64, keyRing.getStorageSignatureKeyPair().getPublic());
}
private boolean verifySignature(Alert alert) {
String alertMessageAsHex = Utils.HEX.encode(alert.message.getBytes());
try {
ECKey.fromPublicOnly(HEX.decode(devPubKeyAsHex)).verifyMessage(alertMessageAsHex, alert.getSignatureAsBase64());
return true;
} catch (SignatureException e) {
log.warn("verifySignature failed");
return false;
}
}
}

View file

@ -0,0 +1,38 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.alert;
import com.google.inject.Singleton;
import io.bitsquare.app.AppModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
public class AlertModule extends AppModule {
private static final Logger log = LoggerFactory.getLogger(AlertModule.class);
public AlertModule(Environment env) {
super(env);
}
@Override
protected final void configure() {
bind(AlertManager.class).in(Singleton.class);
bind(AlertService.class).in(Singleton.class);
}
}

View file

@ -0,0 +1,71 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.alert;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.p2p.P2PService;
import io.bitsquare.p2p.storage.HashSetChangedListener;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
/**
* Used to load global alert messages.
* The message is signed by the project developers private key and use data protection.
*/
public class AlertService {
private static final Logger log = LoggerFactory.getLogger(AlertService.class);
private P2PService p2PService;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, Initialization
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public AlertService(P2PService p2PService) {
this.p2PService = p2PService;
}
public void addHashSetChangedListener(HashSetChangedListener hashSetChangedListener) {
p2PService.addHashSetChangedListener(hashSetChangedListener);
}
public void addAlertMessage(Alert alert, @Nullable ResultHandler resultHandler, @Nullable ErrorMessageHandler errorMessageHandler) {
boolean result = p2PService.addData(alert);
if (result) {
log.trace("Add alertMessage to network was successful. AlertMessage = " + alert);
if (resultHandler != null) resultHandler.handleResult();
} else {
if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage("Add alertMessage failed");
}
}
public void removeAlertMessage(Alert alert, @Nullable ResultHandler resultHandler, @Nullable ErrorMessageHandler errorMessageHandler) {
if (p2PService.removeData(alert)) {
log.trace("Remove alertMessage from network was successful. AlertMessage = " + alert);
if (resultHandler != null) resultHandler.handleResult();
} else {
if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage("Remove alertMessage failed");
}
}
}

View file

@ -0,0 +1,264 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.bitsquare.app.ProgramArguments;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.p2p.Address;
import io.bitsquare.p2p.P2PService;
import io.bitsquare.p2p.P2PServiceListener;
import io.bitsquare.p2p.storage.HashSetChangedListener;
import io.bitsquare.p2p.storage.data.ProtectedData;
import io.bitsquare.user.User;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Utils;
import org.reactfx.util.FxTimer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.math.BigInteger;
import java.security.PublicKey;
import java.security.SignatureException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.bitcoinj.core.Utils.HEX;
public class ArbitratorManager {
transient private static final Logger log = LoggerFactory.getLogger(ArbitratorManager.class);
private final KeyRing keyRing;
private final ArbitratorService arbitratorService;
private final User user;
private final ObservableMap<Address, Arbitrator> arbitratorsObservableMap = FXCollections.observableHashMap();
// Keys for invited arbitrators in bootstrapping phase (before registration is open to anyone and security payment is implemented)
// For testing purpose here is a private key so anyone can setup an arbitrator for now.
// The matching pubkey will be removed once we use real arbitrators.
// PrivKey for testing: 6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a
// Matching pubKey: 027a381b5333a56e1cc3d90d3a7d07f26509adf7029ed06fc997c656621f8da1ee
private static final List<String> publicKeys = new ArrayList<>(Arrays.asList(
"03697a499d24f497b3c46bf716318231e46c4e6a685a4e122d8e2a2b229fa1f4b8",
"0365c6af94681dbee69de1851f98d4684063bf5c2d64b1c73ed5d90434f375a054",
"031c502a60f9dbdb5ae5e438a79819e4e1f417211dd537ac12c9bc23246534c4bd",
"02c1e5a242387b6d5319ce27246cea6edaaf51c3550591b528d2578a4753c56c2c",
"025c319faf7067d9299590dd6c97fe7e56cd4dac61205ccee1cd1fc390142390a2",
"038f6e24c2bfe5d51d0a290f20a9a657c270b94ef2b9c12cd15ca3725fa798fc55",
"0255256ff7fb615278c4544a9bbd3f5298b903b8a011cd7889be19b6b1c45cbefe",
"024a3a37289f08c910fbd925ebc72b946f33feaeff451a4738ee82037b4cda2e95",
"02a88b75e9f0f8afba1467ab26799dcc38fd7a6468fb2795444b425eb43e2c10bd",
"02349a51512c1c04c67118386f4d27d768c5195a83247c150a4b722d161722ba81",
"03f718a2e0dc672c7cdec0113e72c3322efc70412bb95870750d25c32cd98de17d",
"028ff47ee2c56e66313928975c58fa4f1b19a0f81f3a96c4e9c9c3c6768075509e",
"02b517c0cbc3a49548f448ddf004ed695c5a1c52ec110be1bfd65fa0ca0761c94b",
"03df837a3a0f3d858e82f3356b71d1285327f101f7c10b404abed2abc1c94e7169",
"0203a90fb2ab698e524a5286f317a183a84327b8f8c3f7fa4a98fec9e1cefd6b72",
"023c99cc073b851c892d8c43329ca3beb5d2213ee87111af49884e3ce66cbd5ba5",
"0274f772a98d23e7a0251ab30d7121897b5aebd11a2f1e45ab654aa57503173245",
"036d8a1dfcb406886037d2381da006358722823e1940acc2598c844bbc0fd1026f"
));
private static final String publicKeyForTesting = "027a381b5333a56e1cc3d90d3a7d07f26509adf7029ed06fc997c656621f8da1ee";
private final boolean isDevTest;
private P2PServiceListener p2PServiceListener;
@Inject
public ArbitratorManager(@Named(ProgramArguments.DEV_TEST) boolean isDevTest, KeyRing keyRing, ArbitratorService arbitratorService, User user) {
this.isDevTest = isDevTest;
this.keyRing = keyRing;
this.arbitratorService = arbitratorService;
this.user = user;
arbitratorService.addHashSetChangedListener(new HashSetChangedListener() {
@Override
public void onAdded(ProtectedData entry) {
applyArbitrators();
}
@Override
public void onRemoved(ProtectedData entry) {
applyArbitrators();
}
});
}
public void onAllServicesInitialized() {
if (user.getRegisteredArbitrator() != null) {
P2PService p2PService = arbitratorService.getP2PService();
if (!p2PService.isAuthenticated()) {
p2PServiceListener = new P2PServiceListener() {
@Override
public void onTorNodeReady() {
}
@Override
public void onHiddenServiceReady() {
}
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onAllDataReceived() {
}
@Override
public void onAuthenticated() {
republishArbitrator();
}
};
p2PService.addP2PServiceListener(p2PServiceListener);
} else {
republishArbitrator();
}
// re-publish periodically
FxTimer.runPeriodically(
Duration.ofMillis(Arbitrator.TTL / 2),
() -> republishArbitrator()
);
}
applyArbitrators();
}
private void republishArbitrator() {
if (p2PServiceListener != null) arbitratorService.getP2PService().removeP2PServiceListener(p2PServiceListener);
Arbitrator registeredArbitrator = user.getRegisteredArbitrator();
if (registeredArbitrator != null) {
addArbitrator(registeredArbitrator,
this::applyArbitrators,
log::error
);
}
}
public void applyArbitrators() {
Map<Address, Arbitrator> map = arbitratorService.getArbitrators();
log.trace("Arbitrators . size=" + (map.values() != null ? map.values().size() : "0"));
arbitratorsObservableMap.clear();
Map<Address, Arbitrator> filtered = map.values().stream()
.filter(e -> isPublicKeyInList(Utils.HEX.encode(e.getRegistrationPubKey()))
&& verifySignature(e.getPubKeyRing().getStorageSignaturePubKey(), e.getRegistrationPubKey(), e.getRegistrationSignature()))
.collect(Collectors.toMap(Arbitrator::getArbitratorAddress, Function.identity()));
arbitratorsObservableMap.putAll(filtered);
log.debug("filtered arbitrators: " + arbitratorsObservableMap.values());
log.trace("user.getAcceptedArbitrators(): " + user.getAcceptedArbitrators().toString());
// we need to remove accepted arbitrators which are not available anymore
if (user.getAcceptedArbitrators() != null) {
List<Arbitrator> removeList = user.getAcceptedArbitrators().stream()
.filter(e -> !arbitratorsObservableMap.containsValue(e))
.collect(Collectors.toList());
removeList.stream().forEach(user::removeAcceptedArbitrator);
log.trace("removeList arbitrators: " + removeList.toString());
log.trace("user.getAcceptedArbitrators(): " + user.getAcceptedArbitrators().toString());
// if we don't have any arbitrator anymore we set all matching
if (user.getAcceptedArbitrators().isEmpty()) {
arbitratorsObservableMap.values().stream()
.filter(arbitrator -> user.hasMatchingLanguage(arbitrator))
.forEach(arbitrator -> user.addAcceptedArbitrator(arbitrator));
}
log.trace("user.getAcceptedArbitrators(): " + user.getAcceptedArbitrators().toString());
}
}
public void addArbitrator(Arbitrator arbitrator, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
user.setRegisteredArbitrator(arbitrator);
arbitratorsObservableMap.put(arbitrator.getArbitratorAddress(), arbitrator);
arbitratorService.addArbitrator(arbitrator,
() -> {
log.debug("Arbitrator successfully saved in P2P network");
resultHandler.handleResult();
if (arbitratorsObservableMap.size() > 0)
FxTimer.runLater(Duration.ofMillis(1000), this::applyArbitrators);
},
errorMessageHandler::handleErrorMessage);
}
public void removeArbitrator(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
Arbitrator registeredArbitrator = user.getRegisteredArbitrator();
if (registeredArbitrator != null) {
user.setRegisteredArbitrator(null);
arbitratorsObservableMap.remove(registeredArbitrator.getArbitratorAddress());
arbitratorService.removeArbitrator(registeredArbitrator,
() -> {
log.debug("Arbitrator successfully removed from P2P network");
resultHandler.handleResult();
},
errorMessageHandler::handleErrorMessage);
}
}
public ObservableMap<Address, Arbitrator> getArbitratorsObservableMap() {
return arbitratorsObservableMap;
}
// A private key is handed over to selected arbitrators for registration.
// An invited arbitrator will sign at registration his storageSignaturePubKey with that private key and attach the signature and pubKey to his data.
// Other users will check the signature with the list of public keys hardcoded in the app.
public String signStorageSignaturePubKey(ECKey key) {
String keyToSignAsHex = Utils.HEX.encode(keyRing.getPubKeyRing().getStorageSignaturePubKey().getEncoded());
return key.signMessage(keyToSignAsHex);
}
private boolean verifySignature(PublicKey storageSignaturePubKey, byte[] registrationPubKey, String signature) {
String keyToSignAsHex = Utils.HEX.encode(storageSignaturePubKey.getEncoded());
try {
ECKey key = ECKey.fromPublicOnly(registrationPubKey);
key.verifyMessage(keyToSignAsHex, signature);
return true;
} catch (SignatureException e) {
log.warn("verifySignature failed");
return false;
}
}
@Nullable
public ECKey getRegistrationKey(String privKeyBigIntString) {
try {
return ECKey.fromPrivate(new BigInteger(1, HEX.decode(privKeyBigIntString)));
} catch (Throwable t) {
return null;
}
}
public boolean isPublicKeyInList(String pubKeyAsHex) {
return isDevTest && pubKeyAsHex.equals(publicKeyForTesting) || publicKeys.contains(pubKeyAsHex);
}
}

View file

@ -0,0 +1,354 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.messages.DisputeMailMessage;
import io.bitsquare.common.crypto.PubKeyRing;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.Contract;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
public class Dispute implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
transient private static final Logger log = LoggerFactory.getLogger(Dispute.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Fields
///////////////////////////////////////////////////////////////////////////////////////////
private final String tradeId;
private final int traderId;
private final boolean disputeOpenerIsBuyer;
private final boolean disputeOpenerIsOfferer;
private final long openingDate;
private final PubKeyRing traderPubKeyRing;
private final long tradeDate;
private final Contract contract;
private final byte[] contractHash;
@Nullable
private final byte[] depositTxSerialized;
@Nullable
private final byte[] payoutTxSerialized;
@Nullable
private final String depositTxId;
@Nullable
private final String payoutTxId;
private final String contractAsJson;
private final String offererContractSignature;
private final String takerContractSignature;
private final PubKeyRing arbitratorPubKeyRing;
private final boolean isSupportTicket;
private final List<DisputeMailMessage> disputeMailMessages = new ArrayList<>();
private boolean isClosed;
private DisputeResult disputeResult;
transient private Storage<DisputeList<Dispute>> storage;
transient private ObservableList<DisputeMailMessage> disputeMailMessagesAsObservableList = FXCollections.observableArrayList(disputeMailMessages);
transient private BooleanProperty isClosedProperty = new SimpleBooleanProperty(isClosed);
transient private ObjectProperty<DisputeResult> disputeResultProperty = new SimpleObjectProperty<>(disputeResult);
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public Dispute(Storage<DisputeList<Dispute>> storage,
String tradeId,
int traderId,
boolean disputeOpenerIsBuyer,
boolean disputeOpenerIsOfferer,
PubKeyRing traderPubKeyRing,
Date tradeDate,
Contract contract,
byte[] contractHash,
@Nullable byte[] depositTxSerialized,
@Nullable byte[] payoutTxSerialized,
@Nullable String depositTxId,
@Nullable String payoutTxId,
String contractAsJson,
String offererContractSignature,
String takerContractSignature,
PubKeyRing arbitratorPubKeyRing,
boolean isSupportTicket) {
this.storage = storage;
this.tradeId = tradeId;
this.traderId = traderId;
this.disputeOpenerIsBuyer = disputeOpenerIsBuyer;
this.disputeOpenerIsOfferer = disputeOpenerIsOfferer;
this.traderPubKeyRing = traderPubKeyRing;
this.tradeDate = tradeDate.getTime();
this.contract = contract;
this.contractHash = contractHash;
this.depositTxSerialized = depositTxSerialized;
this.payoutTxSerialized = payoutTxSerialized;
this.depositTxId = depositTxId;
this.payoutTxId = payoutTxId;
this.contractAsJson = contractAsJson;
this.offererContractSignature = offererContractSignature;
this.takerContractSignature = takerContractSignature;
this.arbitratorPubKeyRing = arbitratorPubKeyRing;
this.isSupportTicket = isSupportTicket;
this.openingDate = new Date().getTime();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
try {
in.defaultReadObject();
disputeMailMessagesAsObservableList = FXCollections.observableArrayList(disputeMailMessages);
disputeResultProperty = new SimpleObjectProperty<>(disputeResult);
isClosedProperty = new SimpleBooleanProperty(isClosed);
} catch (Throwable t) {
log.trace("Cannot be deserialized." + t.getMessage());
}
}
public void addDisputeMessage(DisputeMailMessage disputeMailMessage) {
if (!disputeMailMessages.contains(disputeMailMessage)) {
disputeMailMessages.add(disputeMailMessage);
disputeMailMessagesAsObservableList.add(disputeMailMessage);
storage.queueUpForSave();
} else {
log.error("disputeMailMessage already exists");
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
// In case we get the object via the network storage is not set as its transient, so we need to set it.
public void setStorage(Storage<DisputeList<Dispute>> storage) {
this.storage = storage;
}
public void setIsClosed(boolean isClosed) {
this.isClosed = isClosed;
isClosedProperty.set(isClosed);
storage.queueUpForSave();
}
public void setDisputeResult(DisputeResult disputeResult) {
this.disputeResult = disputeResult;
disputeResultProperty.set(disputeResult);
storage.queueUpForSave();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public String getTradeId() {
return tradeId;
}
public String getShortTradeId() {
return tradeId.substring(0, 8);
}
public int getTraderId() {
return traderId;
}
public boolean isDisputeOpenerIsBuyer() {
return disputeOpenerIsBuyer;
}
public boolean isDisputeOpenerIsOfferer() {
return disputeOpenerIsOfferer;
}
public Date getOpeningDate() {
return new Date(openingDate);
}
public PubKeyRing getTraderPubKeyRing() {
return traderPubKeyRing;
}
public Contract getContract() {
return contract;
}
@Nullable
public byte[] getDepositTxSerialized() {
return depositTxSerialized;
}
@Nullable
public byte[] getPayoutTxSerialized() {
return payoutTxSerialized;
}
@Nullable
public String getDepositTxId() {
return depositTxId;
}
@Nullable
public String getPayoutTxId() {
return payoutTxId;
}
public String getContractAsJson() {
return contractAsJson;
}
public String getOffererContractSignature() {
return offererContractSignature;
}
public String getTakerContractSignature() {
return takerContractSignature;
}
public ObservableList<DisputeMailMessage> getDisputeMailMessagesAsObservableList() {
return disputeMailMessagesAsObservableList;
}
public boolean isClosed() {
return isClosedProperty.get();
}
public ReadOnlyBooleanProperty isClosedProperty() {
return isClosedProperty;
}
public PubKeyRing getArbitratorPubKeyRing() {
return arbitratorPubKeyRing;
}
public ObjectProperty<DisputeResult> disputeResultProperty() {
return disputeResultProperty;
}
public boolean isSupportTicket() {
return isSupportTicket;
}
public byte[] getContractHash() {
return contractHash;
}
public Date getTradeDate() {
return new Date(tradeDate);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Dispute)) return false;
Dispute dispute = (Dispute) o;
if (traderId != dispute.traderId) return false;
if (disputeOpenerIsBuyer != dispute.disputeOpenerIsBuyer) return false;
if (disputeOpenerIsOfferer != dispute.disputeOpenerIsOfferer) return false;
if (openingDate != dispute.openingDate) return false;
if (tradeDate != dispute.tradeDate) return false;
if (isSupportTicket != dispute.isSupportTicket) return false;
if (isClosed != dispute.isClosed) return false;
if (tradeId != null ? !tradeId.equals(dispute.tradeId) : dispute.tradeId != null) return false;
if (traderPubKeyRing != null ? !traderPubKeyRing.equals(dispute.traderPubKeyRing) : dispute.traderPubKeyRing != null)
return false;
if (contract != null ? !contract.equals(dispute.contract) : dispute.contract != null) return false;
if (!Arrays.equals(contractHash, dispute.contractHash)) return false;
if (!Arrays.equals(depositTxSerialized, dispute.depositTxSerialized)) return false;
if (!Arrays.equals(payoutTxSerialized, dispute.payoutTxSerialized)) return false;
if (depositTxId != null ? !depositTxId.equals(dispute.depositTxId) : dispute.depositTxId != null) return false;
if (payoutTxId != null ? !payoutTxId.equals(dispute.payoutTxId) : dispute.payoutTxId != null) return false;
if (contractAsJson != null ? !contractAsJson.equals(dispute.contractAsJson) : dispute.contractAsJson != null)
return false;
if (offererContractSignature != null ? !offererContractSignature.equals(dispute.offererContractSignature) : dispute.offererContractSignature != null)
return false;
if (takerContractSignature != null ? !takerContractSignature.equals(dispute.takerContractSignature) : dispute.takerContractSignature != null)
return false;
if (arbitratorPubKeyRing != null ? !arbitratorPubKeyRing.equals(dispute.arbitratorPubKeyRing) : dispute.arbitratorPubKeyRing != null)
return false;
if (disputeMailMessages != null ? !disputeMailMessages.equals(dispute.disputeMailMessages) : dispute.disputeMailMessages != null)
return false;
return !(disputeResult != null ? !disputeResult.equals(dispute.disputeResult) : dispute.disputeResult != null);
}
@Override
public int hashCode() {
int result = tradeId != null ? tradeId.hashCode() : 0;
result = 31 * result + traderId;
result = 31 * result + (disputeOpenerIsBuyer ? 1 : 0);
result = 31 * result + (disputeOpenerIsOfferer ? 1 : 0);
result = 31 * result + (int) (openingDate ^ (openingDate >>> 32));
result = 31 * result + (traderPubKeyRing != null ? traderPubKeyRing.hashCode() : 0);
result = 31 * result + (int) (tradeDate ^ (tradeDate >>> 32));
result = 31 * result + (contract != null ? contract.hashCode() : 0);
result = 31 * result + (contractHash != null ? Arrays.hashCode(contractHash) : 0);
result = 31 * result + (depositTxSerialized != null ? Arrays.hashCode(depositTxSerialized) : 0);
result = 31 * result + (payoutTxSerialized != null ? Arrays.hashCode(payoutTxSerialized) : 0);
result = 31 * result + (depositTxId != null ? depositTxId.hashCode() : 0);
result = 31 * result + (payoutTxId != null ? payoutTxId.hashCode() : 0);
result = 31 * result + (contractAsJson != null ? contractAsJson.hashCode() : 0);
result = 31 * result + (offererContractSignature != null ? offererContractSignature.hashCode() : 0);
result = 31 * result + (takerContractSignature != null ? takerContractSignature.hashCode() : 0);
result = 31 * result + (arbitratorPubKeyRing != null ? arbitratorPubKeyRing.hashCode() : 0);
result = 31 * result + (isSupportTicket ? 1 : 0);
result = 31 * result + (disputeMailMessages != null ? disputeMailMessages.hashCode() : 0);
result = 31 * result + (isClosed ? 1 : 0);
result = 31 * result + (disputeResult != null ? disputeResult.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Dispute{" +
", tradeId='" + tradeId + '\'' +
", traderId='" + traderId + '\'' +
", disputeOpenerIsBuyer=" + disputeOpenerIsBuyer +
", disputeOpenerIsOfferer=" + disputeOpenerIsOfferer +
", openingDate=" + openingDate +
", traderPubKeyRing=" + traderPubKeyRing +
", contract=" + contract +
", contractAsJson='" + contractAsJson + '\'' +
", buyerContractSignature='" + offererContractSignature + '\'' +
", sellerContractSignature='" + takerContractSignature + '\'' +
", arbitratorPubKeyRing=" + arbitratorPubKeyRing +
", disputeMailMessages=" + disputeMailMessages +
", disputeMailMessagesAsObservableList=" + disputeMailMessagesAsObservableList +
", isClosed=" + isClosed +
", disputeResult=" + disputeResult +
", disputeResultProperty=" + disputeResultProperty +
'}';
}
}

View file

@ -0,0 +1,93 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration;
import io.bitsquare.app.Version;
import io.bitsquare.storage.Storage;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
public class DisputeList<DisputeCase> extends ArrayList<DisputeCase> implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
private static final Logger log = LoggerFactory.getLogger(DisputeList.class);
final transient private Storage<DisputeList<DisputeCase>> storage;
transient private ObservableList<DisputeCase> observableList;
public DisputeList(Storage<DisputeList<DisputeCase>> storage) {
this.storage = storage;
DisputeList persisted = storage.initAndGetPersisted(this);
if (persisted != null) {
this.addAll(persisted);
}
observableList = FXCollections.observableArrayList(this);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
try {
in.defaultReadObject();
} catch (Throwable t) {
log.trace("Cannot be deserialized." + t.getMessage());
}
}
@Override
public boolean add(DisputeCase disputeCase) {
if (!super.contains(disputeCase)) {
boolean result = super.add(disputeCase);
getObservableList().add(disputeCase);
storage.queueUpForSave();
return result;
} else {
return false;
}
}
@Override
public boolean remove(Object disputeCase) {
boolean result = super.remove(disputeCase);
getObservableList().remove(disputeCase);
storage.queueUpForSave();
return result;
}
private ObservableList<DisputeCase> getObservableList() {
if (observableList == null)
observableList = FXCollections.observableArrayList(this);
return observableList;
}
@NotNull
@Override
public String toString() {
return "DisputeList{" +
", observableList=" + observableList +
'}';
}
}

View file

@ -0,0 +1,608 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration;
import com.google.common.util.concurrent.FutureCallback;
import com.google.inject.Inject;
import io.bitsquare.arbitration.messages.*;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.exceptions.TransactionVerificationException;
import io.bitsquare.btc.exceptions.WalletException;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.crypto.PubKeyRing;
import io.bitsquare.p2p.Address;
import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.P2PService;
import io.bitsquare.p2p.P2PServiceListener;
import io.bitsquare.p2p.messaging.DecryptedMessageWithPubKey;
import io.bitsquare.p2p.messaging.SendMailboxMessageListener;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.trade.offer.OpenOffer;
import io.bitsquare.trade.offer.OpenOfferManager;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Transaction;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Named;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
public class DisputeManager {
private static final Logger log = LoggerFactory.getLogger(DisputeManager.class);
private final TradeWalletService tradeWalletService;
private final WalletService walletService;
private final TradeManager tradeManager;
private final OpenOfferManager openOfferManager;
private final P2PService p2PService;
private final KeyRing keyRing;
private final Storage<DisputeList<Dispute>> disputeStorage;
private final DisputeList<Dispute> disputes;
transient private final ObservableList<Dispute> disputesObservableList;
private final String disputeInfo;
private final P2PServiceListener p2PServiceListener;
private final List<DecryptedMessageWithPubKey> decryptedMailboxMessageWithPubKeys = new CopyOnWriteArrayList<>();
private final List<DecryptedMessageWithPubKey> decryptedMailMessageWithPubKeys = new CopyOnWriteArrayList<>();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public DisputeManager(P2PService p2PService,
TradeWalletService tradeWalletService,
WalletService walletService,
TradeManager tradeManager,
OpenOfferManager openOfferManager,
KeyRing keyRing,
@Named("storage.dir") File storageDir) {
this.p2PService = p2PService;
this.tradeWalletService = tradeWalletService;
this.walletService = walletService;
this.tradeManager = tradeManager;
this.openOfferManager = openOfferManager;
this.keyRing = keyRing;
disputeStorage = new Storage<>(storageDir);
disputes = new DisputeList<>(disputeStorage);
disputesObservableList = FXCollections.observableArrayList(disputes);
disputes.stream().forEach(e -> e.setStorage(getDisputeStorage()));
disputeInfo = "Please note the basic rules for the dispute process:\n" +
"1. You need to respond to the arbitrators requests in between 2 days.\n" +
"2. The maximum period for the dispute is 14 days.\n" +
"3. You need to fulfill what the arbitrator is requesting from you to deliver evidence for your case.\n" +
"4. You accepted the rules outlined in the wiki in the user agreement when you first started the application.\n\n" +
"Please read more in detail about the dispute process in our wiki:\nhttps://github" +
".com/bitsquare/bitsquare/wiki/Dispute-process";
p2PService.addDecryptedMailListener((decryptedMessageWithPubKey, senderAddress) -> {
decryptedMailMessageWithPubKeys.add(decryptedMessageWithPubKey);
if (p2PService.isAuthenticated())
applyMessages();
});
p2PService.addDecryptedMailboxListener((decryptedMessageWithPubKey, senderAddress) -> {
decryptedMailboxMessageWithPubKeys.add(decryptedMessageWithPubKey);
if (p2PService.isAuthenticated())
applyMessages();
});
p2PServiceListener = new P2PServiceListener() {
@Override
public void onTorNodeReady() {
}
@Override
public void onHiddenServiceReady() {
}
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onAllDataReceived() {
}
@Override
public void onAuthenticated() {
applyMessages();
}
};
p2PService.addP2PServiceListener(p2PServiceListener);
}
private void applyMessages() {
decryptedMailMessageWithPubKeys.forEach(decryptedMessageWithPubKey -> {
Message message = decryptedMessageWithPubKey.message;
if (message instanceof DisputeMessage)
dispatchMessage((DisputeMessage) message);
});
decryptedMailMessageWithPubKeys.clear();
decryptedMailboxMessageWithPubKeys.forEach(decryptedMessageWithPubKey -> {
Message message = decryptedMessageWithPubKey.message;
log.debug("decryptedMessageWithPubKey.message " + message);
if (message instanceof DisputeMessage) {
dispatchMessage((DisputeMessage) message);
p2PService.removeEntryFromMailbox(decryptedMessageWithPubKey);
}
});
decryptedMailboxMessageWithPubKeys.clear();
p2PService.removeP2PServiceListener(p2PServiceListener);
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void onAllServicesInitialized() {
}
private void dispatchMessage(DisputeMessage message) {
if (message instanceof OpenNewDisputeMessage)
onOpenNewDisputeMessage((OpenNewDisputeMessage) message);
else if (message instanceof PeerOpenedDisputeMessage)
onPeerOpenedDisputeMessage((PeerOpenedDisputeMessage) message);
else if (message instanceof DisputeMailMessage)
onDisputeMailMessage((DisputeMailMessage) message);
else if (message instanceof DisputeResultMessage)
onDisputeResultMessage((DisputeResultMessage) message);
else if (message instanceof PeerPublishedPayoutTxMessage)
onDisputedPayoutTxMessage((PeerPublishedPayoutTxMessage) message);
}
public void sendOpenNewDisputeMessage(Dispute dispute) {
if (!disputes.contains(dispute)) {
DisputeMailMessage disputeMailMessage = new DisputeMailMessage(dispute.getTradeId(),
keyRing.getPubKeyRing().hashCode(),
true,
"System message: " + (dispute.isSupportTicket() ?
"You opened a request for support."
: "You opened a request for a dispute.\n\n" + disputeInfo),
p2PService.getAddress());
disputeMailMessage.setIsSystemMessage(true);
dispute.addDisputeMessage(disputeMailMessage);
disputes.add(dispute);
disputesObservableList.add(dispute);
p2PService.sendEncryptedMailboxMessage(dispute.getContract().arbitratorAddress,
dispute.getArbitratorPubKeyRing(),
new OpenNewDisputeMessage(dispute, p2PService.getAddress()),
new SendMailboxMessageListener() {
@Override
public void onArrived() {
disputeMailMessage.setArrived(true);
}
@Override
public void onStoredInMailbox() {
disputeMailMessage.setStoredInMailbox(true);
}
@Override
public void onFault() {
log.error("sendEncryptedMessage failed");
}
}
);
} else {
log.warn("We got a dispute msg what we have already stored. TradeId = " + dispute.getTradeId());
}
}
// arbitrator sends that to trading peer when he received openDispute request
private void sendPeerOpenedDisputeMessage(Dispute disputeFromOpener) {
Contract contractFromOpener = disputeFromOpener.getContract();
PubKeyRing pubKeyRing = disputeFromOpener.isDisputeOpenerIsBuyer() ? contractFromOpener.getSellerPubKeyRing() : contractFromOpener.getBuyerPubKeyRing();
Dispute dispute = new Dispute(
disputeStorage,
disputeFromOpener.getTradeId(),
pubKeyRing.hashCode(),
!disputeFromOpener.isDisputeOpenerIsBuyer(),
!disputeFromOpener.isDisputeOpenerIsOfferer(),
pubKeyRing,
disputeFromOpener.getTradeDate(),
contractFromOpener,
disputeFromOpener.getContractHash(),
disputeFromOpener.getDepositTxSerialized(),
disputeFromOpener.getPayoutTxSerialized(),
disputeFromOpener.getDepositTxId(),
disputeFromOpener.getPayoutTxId(),
disputeFromOpener.getContractAsJson(),
disputeFromOpener.getOffererContractSignature(),
disputeFromOpener.getTakerContractSignature(),
disputeFromOpener.getArbitratorPubKeyRing(),
disputeFromOpener.isSupportTicket()
);
DisputeMailMessage disputeMailMessage = new DisputeMailMessage(dispute.getTradeId(),
keyRing.getPubKeyRing().hashCode(),
true,
"System message: " + (dispute.isSupportTicket() ?
"Your trading peer has requested support due technical problems. Please wait for further instructions."
: "Your trading peer has requested a dispute.\n\n" + disputeInfo),
p2PService.getAddress());
disputeMailMessage.setIsSystemMessage(true);
dispute.addDisputeMessage(disputeMailMessage);
disputes.add(dispute);
disputesObservableList.add(dispute);
// we mirrored dispute already!
Contract contract = dispute.getContract();
PubKeyRing peersPubKeyRing = dispute.isDisputeOpenerIsBuyer() ? contract.getBuyerPubKeyRing() : contract.getSellerPubKeyRing();
Address peerAddress = dispute.isDisputeOpenerIsBuyer() ? contract.getBuyerAddress() : contract.getSellerAddress();
log.trace("sendPeerOpenedDisputeMessage to peerAddress " + peerAddress);
p2PService.sendEncryptedMailboxMessage(peerAddress,
peersPubKeyRing,
new PeerOpenedDisputeMessage(dispute, p2PService.getAddress()),
new SendMailboxMessageListener() {
@Override
public void onArrived() {
disputeMailMessage.setArrived(true);
}
@Override
public void onStoredInMailbox() {
disputeMailMessage.setStoredInMailbox(true);
}
@Override
public void onFault() {
log.error("sendEncryptedMessage failed");
}
}
);
}
// traders send msg to the arbitrator or arbitrator to 1 trader (trader to trader is not allowed)
public DisputeMailMessage sendDisputeMailMessage(Dispute dispute, String text, ArrayList<DisputeMailMessage.Attachment> attachments) {
DisputeMailMessage disputeMailMessage = new DisputeMailMessage(dispute.getTradeId(),
dispute.getTraderPubKeyRing().hashCode(),
isTrader(dispute),
text,
p2PService.getAddress());
disputeMailMessage.addAllAttachments(attachments);
PubKeyRing receiverPubKeyRing = null;
Address peerAddress = null;
if (isTrader(dispute)) {
dispute.addDisputeMessage(disputeMailMessage);
receiverPubKeyRing = dispute.getArbitratorPubKeyRing();
peerAddress = dispute.getContract().arbitratorAddress;
} else if (isArbitrator(dispute)) {
if (!disputeMailMessage.isSystemMessage())
dispute.addDisputeMessage(disputeMailMessage);
receiverPubKeyRing = dispute.getTraderPubKeyRing();
Contract contract = dispute.getContract();
if (contract.getBuyerPubKeyRing().equals(receiverPubKeyRing))
peerAddress = contract.getBuyerAddress();
else
peerAddress = contract.getSellerAddress();
} else {
log.error("That must not happen. Trader cannot communicate to other trader.");
}
if (receiverPubKeyRing != null) {
log.trace("sendDisputeMailMessage to peerAddress " + peerAddress);
p2PService.sendEncryptedMailboxMessage(peerAddress,
receiverPubKeyRing,
disputeMailMessage,
new SendMailboxMessageListener() {
@Override
public void onArrived() {
disputeMailMessage.setArrived(true);
}
@Override
public void onStoredInMailbox() {
disputeMailMessage.setStoredInMailbox(true);
}
@Override
public void onFault() {
log.error("sendEncryptedMessage failed");
}
}
);
}
return disputeMailMessage;
}
// arbitrator send result to trader
public void sendDisputeResultMessage(DisputeResult disputeResult, Dispute dispute, String text) {
DisputeMailMessage disputeMailMessage = new DisputeMailMessage(dispute.getTradeId(),
dispute.getTraderPubKeyRing().hashCode(),
false,
text,
p2PService.getAddress());
dispute.addDisputeMessage(disputeMailMessage);
disputeResult.setResultMailMessage(disputeMailMessage);
Address peerAddress;
Contract contract = dispute.getContract();
if (contract.getBuyerPubKeyRing().equals(dispute.getTraderPubKeyRing()))
peerAddress = contract.getBuyerAddress();
else
peerAddress = contract.getSellerAddress();
p2PService.sendEncryptedMailboxMessage(peerAddress,
dispute.getTraderPubKeyRing(),
new DisputeResultMessage(disputeResult, p2PService.getAddress()),
new SendMailboxMessageListener() {
@Override
public void onArrived() {
disputeMailMessage.setArrived(true);
}
@Override
public void onStoredInMailbox() {
disputeMailMessage.setStoredInMailbox(true);
}
@Override
public void onFault() {
log.error("sendEncryptedMessage failed");
}
}
);
}
// winner (or buyer in case of 50/50) sends tx to other peer
private void sendPeerPublishedPayoutTxMessage(Transaction transaction, Dispute dispute, Contract contract) {
PubKeyRing peersPubKeyRing = dispute.isDisputeOpenerIsBuyer() ? contract.getSellerPubKeyRing() : contract.getBuyerPubKeyRing();
Address peerAddress = dispute.isDisputeOpenerIsBuyer() ? contract.getSellerAddress() : contract.getBuyerAddress();
log.trace("sendPeerPublishedPayoutTxMessage to peerAddress " + peerAddress);
p2PService.sendEncryptedMailboxMessage(peerAddress,
peersPubKeyRing,
new PeerPublishedPayoutTxMessage(transaction.bitcoinSerialize(), dispute.getTradeId(), p2PService.getAddress()),
new SendMailboxMessageListener() {
@Override
public void onArrived() {
}
@Override
public void onStoredInMailbox() {
}
@Override
public void onFault() {
log.error("sendEncryptedMessage failed");
}
}
);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Incoming message
///////////////////////////////////////////////////////////////////////////////////////////
// arbitrator receives that from trader who opens dispute
private void onOpenNewDisputeMessage(OpenNewDisputeMessage openNewDisputeMessage) {
Dispute dispute = openNewDisputeMessage.dispute;
if (isArbitrator(dispute)) {
if (!disputes.contains(dispute)) {
dispute.setStorage(getDisputeStorage());
disputes.add(dispute);
disputesObservableList.add(dispute);
sendPeerOpenedDisputeMessage(dispute);
} else {
log.warn("We got a dispute msg what we have already stored. TradeId = " + dispute.getTradeId());
}
} else {
log.error("Trader received openNewDisputeMessage. That must never happen.");
}
}
// not dispute requester receives that from arbitrator
private void onPeerOpenedDisputeMessage(PeerOpenedDisputeMessage peerOpenedDisputeMessage) {
Dispute dispute = peerOpenedDisputeMessage.dispute;
if (!isArbitrator(dispute)) {
Optional<Trade> tradeOptional = tradeManager.getTradeById(dispute.getTradeId());
if (tradeOptional.isPresent())
tradeOptional.get().setDisputeState(Trade.DisputeState.DISPUTE_STARTED_BY_PEER);
if (!disputes.contains(dispute)) {
dispute.setStorage(getDisputeStorage());
disputes.add(dispute);
disputesObservableList.add(dispute);
} else {
log.warn("We got a dispute msg what we have already stored. TradeId = " + dispute.getTradeId());
}
} else {
log.error("Arbitrator received peerOpenedDisputeMessage. That must never happen.");
}
}
// a trader can receive a msg from the arbitrator or the arbitrator form a trader. Trader to trader is not allowed.
private void onDisputeMailMessage(DisputeMailMessage disputeMailMessage) {
log.debug("onDisputeMailMessage " + disputeMailMessage);
Optional<Dispute> disputeOptional = findDispute(disputeMailMessage.getTradeId(), disputeMailMessage.getTraderId());
if (disputeOptional.isPresent()) {
Dispute dispute = disputeOptional.get();
if (!dispute.getDisputeMailMessagesAsObservableList().contains(disputeMailMessage))
dispute.addDisputeMessage(disputeMailMessage);
else
log.warn("We got a dispute mail msg what we have already stored. TradeId = " + disputeMailMessage.getTradeId());
} else {
log.warn("We got a dispute mail msg but we don't have a matching dispute. TradeId = " + disputeMailMessage.getTradeId());
}
}
// We get that message at both peers. The dispute object is in context of the trader
private void onDisputeResultMessage(DisputeResultMessage disputeResultMessage) {
DisputeResult disputeResult = disputeResultMessage.disputeResult;
if (!isArbitrator(disputeResult)) {
Optional<Dispute> disputeOptional = findDispute(disputeResult.tradeId, disputeResult.traderId);
if (disputeOptional.isPresent()) {
Dispute dispute = disputeOptional.get();
DisputeMailMessage disputeMailMessage = disputeResult.getResultMailMessage();
if (!dispute.getDisputeMailMessagesAsObservableList().contains(disputeMailMessage))
dispute.addDisputeMessage(disputeMailMessage);
else
log.warn("We got a dispute mail msg what we have already stored. TradeId = " + disputeMailMessage.getTradeId());
dispute.setIsClosed(true);
if (tradeManager.getTradeById(dispute.getTradeId()).isPresent())
tradeManager.closeDisputedTrade(dispute.getTradeId());
else {
Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(dispute.getTradeId());
if (openOfferOptional.isPresent())
openOfferManager.closeOpenOffer(openOfferOptional.get().getOffer());
}
if (dispute.disputeResultProperty().get() == null) {
dispute.setDisputeResult(disputeResult);
// We need to avoid publishing the tx from both traders as it would create problems with zero confirmation withdrawals
// There would be different transactions if both sign and publish (signers: once buyer+arb, once seller+arb)
// The tx publisher is the winner or in case both get 50% the buyer, as the buyer has more inventive to publish the tx as he receives
// more BTC as he has deposited
final Contract contract = dispute.getContract();
boolean isBuyer = keyRing.getPubKeyRing().equals(contract.getBuyerPubKeyRing());
if ((isBuyer && disputeResult.getWinner() == DisputeResult.Winner.BUYER)
|| (!isBuyer && disputeResult.getWinner() == DisputeResult.Winner.SELLER)
|| (isBuyer && disputeResult.getWinner() == DisputeResult.Winner.STALE_MATE)) {
if (dispute.getDepositTxSerialized() != null) {
try {
log.debug("do payout Transaction ");
Transaction signedDisputedPayoutTx = tradeWalletService.signAndFinalizeDisputedPayoutTx(
dispute.getDepositTxSerialized(),
disputeResult.getArbitratorSignature(),
disputeResult.getBuyerPayoutAmount(),
disputeResult.getSellerPayoutAmount(),
disputeResult.getArbitratorPayoutAmount(),
contract.getBuyerPayoutAddressString(),
contract.getSellerPayoutAddressString(),
disputeResult.getArbitratorAddressAsString(),
walletService.getAddressEntryByOfferId(dispute.getTradeId()),
contract.getBuyerBtcPubKey(),
contract.getSellerBtcPubKey(),
disputeResult.getArbitratorPubKey()
);
Transaction committedDisputedPayoutTx = tradeWalletService.addTransactionToWallet(signedDisputedPayoutTx);
log.debug("broadcast committedDisputedPayoutTx");
tradeWalletService.broadcastTx(committedDisputedPayoutTx, new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("BroadcastTx succeeded. Transaction:" + transaction);
// after successful publish we send peer the tx
sendPeerPublishedPayoutTxMessage(transaction, dispute, contract);
}
@Override
public void onFailure(@NotNull Throwable t) {
// TODO error handling
log.error(t.getMessage());
}
});
} catch (AddressFormatException | WalletException | TransactionVerificationException e) {
e.printStackTrace();
}
} else {
log.warn("DepositTx is null. TradeId = " + disputeResult.tradeId);
}
}
} else {
log.warn("We got a dispute msg what we have already stored. TradeId = " + disputeResult.tradeId);
}
/* DisputeMailMessage disputeMailMessage = disputeResult.getResultMailMessage();
if (!dispute.getDisputeMailMessagesAsObservableList().contains(disputeMailMessage))
dispute.addDisputeMessage(disputeMailMessage);
else
log.warn("We got a dispute mail msg what we have already stored. TradeId = " + disputeMailMessage.getTradeId());*/
} else {
log.warn("We got a dispute result msg but we don't have a matching dispute. TradeId = " + disputeResult.tradeId);
}
} else {
log.error("Arbitrator received disputeResultMessage. That must never happen.");
}
}
// losing trader or in case of 50/50 the seller gets the tx sent from the winner or buyer
private void onDisputedPayoutTxMessage(PeerPublishedPayoutTxMessage peerPublishedPayoutTxMessage) {
tradeWalletService.addTransactionToWallet(peerPublishedPayoutTxMessage.transaction);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public Storage<DisputeList<Dispute>> getDisputeStorage() {
return disputeStorage;
}
public ObservableList<Dispute> getDisputesAsObservableList() {
return disputesObservableList;
}
public boolean isTrader(Dispute dispute) {
return keyRing.getPubKeyRing().equals(dispute.getTraderPubKeyRing());
}
private boolean isArbitrator(Dispute dispute) {
return keyRing.getPubKeyRing().equals(dispute.getArbitratorPubKeyRing());
}
private boolean isArbitrator(DisputeResult disputeResult) {
return walletService.getArbitratorAddressEntry().getAddressString().equals(disputeResult.getArbitratorAddressAsString());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Utils
///////////////////////////////////////////////////////////////////////////////////////////
private Optional<Dispute> findDispute(String tradeId, int traderId) {
return disputes.stream().filter(e -> e.getTradeId().equals(tradeId) && e.getTraderId() == traderId).findFirst();
}
public Optional<Dispute> findOwnDispute(String tradeId) {
return disputes.stream().filter(e -> e.getTradeId().equals(tradeId)).findFirst();
}
public List<Dispute> findDisputesByTradeId(String tradeId) {
return disputes.stream().filter(e -> e.getTradeId().equals(tradeId)).collect(Collectors.toList());
}
}

View file

@ -0,0 +1,265 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.messages.DisputeMailMessage;
import javafx.beans.property.*;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Date;
public class DisputeResult implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
transient private static final Logger log = LoggerFactory.getLogger(DisputeResult.class);
public enum FeePaymentPolicy {
LOSER,
SPLIT,
WAIVE
}
public enum Winner {
BUYER,
SELLER,
STALE_MATE
}
public final String tradeId;
public final int traderId;
private FeePaymentPolicy feePaymentPolicy;
private boolean tamperProofEvidence;
private boolean idVerification;
private boolean screenCast;
private String summaryNotes;
private DisputeMailMessage resultMailMessage;
private byte[] arbitratorSignature;
private long buyerPayoutAmount;
private long sellerPayoutAmount;
private long arbitratorPayoutAmount;
private String arbitratorAddressAsString;
private byte[] arbitratorPubKey;
private long closeDate;
private Winner winner;
transient private BooleanProperty tamperProofEvidenceProperty = new SimpleBooleanProperty();
transient private BooleanProperty idVerificationProperty = new SimpleBooleanProperty();
transient private BooleanProperty screenCastProperty = new SimpleBooleanProperty();
transient private ObjectProperty<FeePaymentPolicy> feePaymentPolicyProperty = new SimpleObjectProperty<>();
transient private StringProperty summaryNotesProperty = new SimpleStringProperty();
public DisputeResult(String tradeId, int traderId) {
this.tradeId = tradeId;
this.traderId = traderId;
feePaymentPolicy = FeePaymentPolicy.LOSER;
init();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
try {
in.defaultReadObject();
init();
} catch (Throwable t) {
log.trace("Cannot be deserialized." + t.getMessage());
}
}
private void init() {
tamperProofEvidenceProperty = new SimpleBooleanProperty(tamperProofEvidence);
idVerificationProperty = new SimpleBooleanProperty(idVerification);
screenCastProperty = new SimpleBooleanProperty(screenCast);
feePaymentPolicyProperty = new SimpleObjectProperty<>(feePaymentPolicy);
summaryNotesProperty = new SimpleStringProperty(summaryNotes);
tamperProofEvidenceProperty.addListener((observable, oldValue, newValue) -> {
tamperProofEvidence = newValue;
});
idVerificationProperty.addListener((observable, oldValue, newValue) -> {
idVerification = newValue;
});
screenCastProperty.addListener((observable, oldValue, newValue) -> {
screenCast = newValue;
});
feePaymentPolicyProperty.addListener((observable, oldValue, newValue) -> {
feePaymentPolicy = newValue;
});
summaryNotesProperty.addListener((observable, oldValue, newValue) -> {
summaryNotes = newValue;
});
}
public BooleanProperty tamperProofEvidenceProperty() {
return tamperProofEvidenceProperty;
}
public BooleanProperty idVerificationProperty() {
return idVerificationProperty;
}
public BooleanProperty screenCastProperty() {
return screenCastProperty;
}
public void setFeePaymentPolicy(FeePaymentPolicy feePaymentPolicy) {
this.feePaymentPolicy = feePaymentPolicy;
feePaymentPolicyProperty.set(feePaymentPolicy);
}
public ReadOnlyObjectProperty<FeePaymentPolicy> feePaymentPolicyProperty() {
return feePaymentPolicyProperty;
}
public FeePaymentPolicy getFeePaymentPolicy() {
return feePaymentPolicy;
}
public StringProperty summaryNotesProperty() {
return summaryNotesProperty;
}
public void setResultMailMessage(DisputeMailMessage resultMailMessage) {
this.resultMailMessage = resultMailMessage;
}
public DisputeMailMessage getResultMailMessage() {
return resultMailMessage;
}
public void setArbitratorSignature(byte[] arbitratorSignature) {
this.arbitratorSignature = arbitratorSignature;
}
public byte[] getArbitratorSignature() {
return arbitratorSignature;
}
public void setBuyerPayoutAmount(Coin buyerPayoutAmount) {
this.buyerPayoutAmount = buyerPayoutAmount.value;
}
public Coin getBuyerPayoutAmount() {
return Coin.valueOf(buyerPayoutAmount);
}
public void setSellerPayoutAmount(Coin sellerPayoutAmount) {
this.sellerPayoutAmount = sellerPayoutAmount.value;
}
public Coin getSellerPayoutAmount() {
return Coin.valueOf(sellerPayoutAmount);
}
public void setArbitratorPayoutAmount(Coin arbitratorPayoutAmount) {
this.arbitratorPayoutAmount = arbitratorPayoutAmount.value;
}
public Coin getArbitratorPayoutAmount() {
return Coin.valueOf(arbitratorPayoutAmount);
}
public void setArbitratorAddressAsString(String arbitratorAddressAsString) {
this.arbitratorAddressAsString = arbitratorAddressAsString;
}
public String getArbitratorAddressAsString() {
return arbitratorAddressAsString;
}
public void setArbitratorPubKey(byte[] arbitratorPubKey) {
this.arbitratorPubKey = arbitratorPubKey;
}
public byte[] getArbitratorPubKey() {
return arbitratorPubKey;
}
public void setCloseDate(Date closeDate) {
this.closeDate = closeDate.getTime();
}
public Date getCloseDate() {
return new Date(closeDate);
}
public void setWinner(Winner winner) {
this.winner = winner;
}
public Winner getWinner() {
return winner;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DisputeResult)) return false;
DisputeResult that = (DisputeResult) o;
if (traderId != that.traderId) return false;
if (tamperProofEvidence != that.tamperProofEvidence) return false;
if (idVerification != that.idVerification) return false;
if (screenCast != that.screenCast) return false;
if (buyerPayoutAmount != that.buyerPayoutAmount) return false;
if (sellerPayoutAmount != that.sellerPayoutAmount) return false;
if (arbitratorPayoutAmount != that.arbitratorPayoutAmount) return false;
if (closeDate != that.closeDate) return false;
if (tradeId != null ? !tradeId.equals(that.tradeId) : that.tradeId != null) return false;
if (feePaymentPolicy != that.feePaymentPolicy) return false;
if (summaryNotes != null ? !summaryNotes.equals(that.summaryNotes) : that.summaryNotes != null) return false;
if (resultMailMessage != null ? !resultMailMessage.equals(that.resultMailMessage) : that.resultMailMessage != null)
return false;
if (!Arrays.equals(arbitratorSignature, that.arbitratorSignature)) return false;
if (arbitratorAddressAsString != null ? !arbitratorAddressAsString.equals(that.arbitratorAddressAsString) : that.arbitratorAddressAsString != null)
return false;
if (!Arrays.equals(arbitratorPubKey, that.arbitratorPubKey)) return false;
return winner == that.winner;
}
@Override
public int hashCode() {
int result = tradeId != null ? tradeId.hashCode() : 0;
result = 31 * result + traderId;
result = 31 * result + (feePaymentPolicy != null ? feePaymentPolicy.hashCode() : 0);
result = 31 * result + (tamperProofEvidence ? 1 : 0);
result = 31 * result + (idVerification ? 1 : 0);
result = 31 * result + (screenCast ? 1 : 0);
result = 31 * result + (summaryNotes != null ? summaryNotes.hashCode() : 0);
result = 31 * result + (resultMailMessage != null ? resultMailMessage.hashCode() : 0);
result = 31 * result + (arbitratorSignature != null ? Arrays.hashCode(arbitratorSignature) : 0);
result = 31 * result + (int) (buyerPayoutAmount ^ (buyerPayoutAmount >>> 32));
result = 31 * result + (int) (sellerPayoutAmount ^ (sellerPayoutAmount >>> 32));
result = 31 * result + (int) (arbitratorPayoutAmount ^ (arbitratorPayoutAmount >>> 32));
result = 31 * result + (arbitratorAddressAsString != null ? arbitratorAddressAsString.hashCode() : 0);
result = 31 * result + (arbitratorPubKey != null ? Arrays.hashCode(arbitratorPubKey) : 0);
result = 31 * result + (int) (closeDate ^ (closeDate >>> 32));
result = 31 * result + (winner != null ? winner.hashCode() : 0);
return result;
}
}

View file

@ -0,0 +1,237 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration.messages;
import io.bitsquare.app.Version;
import io.bitsquare.p2p.Address;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
public class DisputeMailMessage implements DisputeMessage {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
transient private static final Logger log = LoggerFactory.getLogger(DisputeMailMessage.class);
private final long date;
private final String tradeId;
private final int traderId;
private final boolean senderIsTrader;
private final String message;
private final List<Attachment> attachments = new ArrayList<>();
private boolean arrived;
private boolean storedInMailbox;
private boolean isSystemMessage;
private final Address myAddress;
transient private BooleanProperty arrivedProperty = new SimpleBooleanProperty();
transient private BooleanProperty storedInMailboxProperty = new SimpleBooleanProperty();
public DisputeMailMessage(String tradeId, int traderId, boolean senderIsTrader, String message, Address myAddress) {
this.tradeId = tradeId;
this.traderId = traderId;
this.senderIsTrader = senderIsTrader;
this.message = message;
this.myAddress = myAddress;
date = new Date().getTime();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
try {
in.defaultReadObject();
arrivedProperty = new SimpleBooleanProperty(arrived);
storedInMailboxProperty = new SimpleBooleanProperty(storedInMailbox);
} catch (Throwable t) {
log.trace("Cannot be deserialized." + t.getMessage());
}
}
@Override
public Address getSenderAddress() {
return myAddress;
}
public void addAttachment(Attachment attachment) {
attachments.add(attachment);
}
public void addAllAttachments(List<Attachment> attachments) {
this.attachments.addAll(attachments);
}
public void setArrived(boolean arrived) {
this.arrived = arrived;
this.arrivedProperty.set(arrived);
}
public void setStoredInMailbox(boolean storedInMailbox) {
this.storedInMailbox = storedInMailbox;
this.storedInMailboxProperty.set(storedInMailbox);
}
public Date getDate() {
return new Date(date);
}
public boolean isSenderIsTrader() {
return senderIsTrader;
}
public String getMessage() {
return message;
}
public int getTraderId() {
return traderId;
}
public BooleanProperty arrivedProperty() {
return arrivedProperty;
}
public BooleanProperty storedInMailboxProperty() {
return storedInMailboxProperty;
}
public List<Attachment> getAttachments() {
return attachments;
}
public String getTradeId() {
return tradeId;
}
public boolean isSystemMessage() {
return isSystemMessage;
}
public void setIsSystemMessage(boolean isSystemMessage) {
this.isSystemMessage = isSystemMessage;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DisputeMailMessage)) return false;
DisputeMailMessage that = (DisputeMailMessage) o;
if (date != that.date) return false;
if (traderId != that.traderId) return false;
if (senderIsTrader != that.senderIsTrader) return false;
if (arrived != that.arrived) return false;
if (storedInMailbox != that.storedInMailbox) return false;
if (isSystemMessage != that.isSystemMessage) return false;
if (tradeId != null ? !tradeId.equals(that.tradeId) : that.tradeId != null) return false;
if (message != null ? !message.equals(that.message) : that.message != null) return false;
if (attachments != null ? !attachments.equals(that.attachments) : that.attachments != null) return false;
return !(myAddress != null ? !myAddress.equals(that.myAddress) : that.myAddress != null);
}
@Override
public int hashCode() {
int result = (int) (date ^ (date >>> 32));
result = 31 * result + (tradeId != null ? tradeId.hashCode() : 0);
result = 31 * result + traderId;
result = 31 * result + (senderIsTrader ? 1 : 0);
result = 31 * result + (message != null ? message.hashCode() : 0);
result = 31 * result + (attachments != null ? attachments.hashCode() : 0);
result = 31 * result + (arrived ? 1 : 0);
result = 31 * result + (storedInMailbox ? 1 : 0);
result = 31 * result + (isSystemMessage ? 1 : 0);
result = 31 * result + (myAddress != null ? myAddress.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "DisputeMailMessage{" +
"date=" + date +
", tradeId='" + tradeId + '\'' +
", traderId='" + traderId + '\'' +
", senderIsTrader=" + senderIsTrader +
", message='" + message + '\'' +
", attachments=" + attachments +
'}';
}
///////////////////////////////////////////////////////////////////////////////////////////
// Static classes
///////////////////////////////////////////////////////////////////////////////////////////
public static class Attachment implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
transient private static final Logger log = LoggerFactory.getLogger(Attachment.class);
private final byte[] bytes;
private final String fileName;
public Attachment(String fileName, byte[] bytes) {
this.fileName = fileName;
this.bytes = bytes;
}
public byte[] getBytes() {
return bytes;
}
public String getFileName() {
return fileName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Attachment)) return false;
Attachment that = (Attachment) o;
if (!Arrays.equals(bytes, that.bytes)) return false;
return !(fileName != null ? !fileName.equals(that.fileName) : that.fileName != null);
}
@Override
public int hashCode() {
int result = bytes != null ? Arrays.hashCode(bytes) : 0;
result = 31 * result + (fileName != null ? fileName.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Attachment{" +
"description=" + fileName +
", data=" + Arrays.toString(bytes) +
'}';
}
}
}

View file

@ -0,0 +1,23 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration.messages;
import io.bitsquare.p2p.messaging.MailboxMessage;
public interface DisputeMessage extends MailboxMessage {
}

View file

@ -0,0 +1,60 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration.messages;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.DisputeResult;
import io.bitsquare.p2p.Address;
public class DisputeResultMessage implements DisputeMessage {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
public final DisputeResult disputeResult;
private final Address myAddress;
public DisputeResultMessage(DisputeResult disputeResult, Address myAddress) {
this.disputeResult = disputeResult;
this.myAddress = myAddress;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DisputeResultMessage)) return false;
DisputeResultMessage that = (DisputeResultMessage) o;
if (disputeResult != null ? !disputeResult.equals(that.disputeResult) : that.disputeResult != null)
return false;
return !(myAddress != null ? !myAddress.equals(that.myAddress) : that.myAddress != null);
}
@Override
public int hashCode() {
int result = disputeResult != null ? disputeResult.hashCode() : 0;
result = 31 * result + (myAddress != null ? myAddress.hashCode() : 0);
return result;
}
@Override
public Address getSenderAddress() {
return myAddress;
}
}

View file

@ -0,0 +1,59 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration.messages;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.Dispute;
import io.bitsquare.p2p.Address;
public class OpenNewDisputeMessage implements DisputeMessage {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
public final Dispute dispute;
private final Address myAddress;
public OpenNewDisputeMessage(Dispute dispute, Address myAddress) {
this.dispute = dispute;
this.myAddress = myAddress;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof OpenNewDisputeMessage)) return false;
OpenNewDisputeMessage that = (OpenNewDisputeMessage) o;
if (dispute != null ? !dispute.equals(that.dispute) : that.dispute != null) return false;
return !(myAddress != null ? !myAddress.equals(that.myAddress) : that.myAddress != null);
}
@Override
public int hashCode() {
int result = dispute != null ? dispute.hashCode() : 0;
result = 31 * result + (myAddress != null ? myAddress.hashCode() : 0);
return result;
}
@Override
public Address getSenderAddress() {
return myAddress;
}
}

View file

@ -0,0 +1,58 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration.messages;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.Dispute;
import io.bitsquare.p2p.Address;
public class PeerOpenedDisputeMessage implements DisputeMessage {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
public final Dispute dispute;
private final Address myAddress;
public PeerOpenedDisputeMessage(Dispute dispute, Address myAddress) {
this.dispute = dispute;
this.myAddress = myAddress;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PeerOpenedDisputeMessage)) return false;
PeerOpenedDisputeMessage that = (PeerOpenedDisputeMessage) o;
if (dispute != null ? !dispute.equals(that.dispute) : that.dispute != null) return false;
return !(myAddress != null ? !myAddress.equals(that.myAddress) : that.myAddress != null);
}
@Override
public int hashCode() {
int result = dispute != null ? dispute.hashCode() : 0;
result = 31 * result + (myAddress != null ? myAddress.hashCode() : 0);
return result;
}
@Override
public Address getSenderAddress() {
return myAddress;
}
}

View file

@ -0,0 +1,65 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration.messages;
import io.bitsquare.app.Version;
import io.bitsquare.p2p.Address;
import java.util.Arrays;
public class PeerPublishedPayoutTxMessage implements DisputeMessage {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
public final byte[] transaction;
public final String tradeId;
private final Address myAddress;
public PeerPublishedPayoutTxMessage(byte[] transaction, String tradeId, Address myAddress) {
this.transaction = transaction;
this.tradeId = tradeId;
this.myAddress = myAddress;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PeerPublishedPayoutTxMessage)) return false;
PeerPublishedPayoutTxMessage that = (PeerPublishedPayoutTxMessage) o;
if (!Arrays.equals(transaction, that.transaction)) return false;
if (tradeId != null ? !tradeId.equals(that.tradeId) : that.tradeId != null) return false;
return !(myAddress != null ? !myAddress.equals(that.myAddress) : that.myAddress != null);
}
@Override
public int hashCode() {
int result = transaction != null ? Arrays.hashCode(transaction) : 0;
result = 31 * result + (tradeId != null ? tradeId.hashCode() : 0);
result = 31 * result + (myAddress != null ? myAddress.hashCode() : 0);
return result;
}
@Override
public Address getSenderAddress() {
return myAddress;
}
}

View file

@ -0,0 +1,40 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc.data;
import javax.annotation.Nullable;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
public class InputsAndChangeOutput {
public final List<RawInput> rawInputs;
// Is set to 0L in case we don't have an output
public final long changeOutputValue;
@Nullable
public final String changeOutputAddress;
public InputsAndChangeOutput(List<RawInput> rawInputs, long changeOutputValue, @Nullable String changeOutputAddress) {
checkArgument(!rawInputs.isEmpty(), "rawInputs.isEmpty()");
this.rawInputs = rawInputs;
this.changeOutputValue = changeOutputValue;
this.changeOutputAddress = changeOutputAddress;
}
}

View file

@ -0,0 +1,30 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc.data;
import java.util.List;
public class PreparedDepositTxAndOffererInputs {
public final List<RawInput> rawOffererInputs;
public final byte[] depositTransaction;
public PreparedDepositTxAndOffererInputs(List<RawInput> rawOffererInputs, byte[] depositTransaction) {
this.rawOffererInputs = rawOffererInputs;
this.depositTransaction = depositTransaction;
}
}

View file

@ -0,0 +1,59 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc.data;
import io.bitsquare.app.Version;
import java.io.Serializable;
import java.util.Arrays;
public class RawInput implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
public final long index;
public final byte[] parentTransaction;
public final long value;
public RawInput(long index, byte[] parentTransaction, long value) {
this.index = index;
this.parentTransaction = parentTransaction;
this.value = value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RawInput)) return false;
RawInput rawInput = (RawInput) o;
if (index != rawInput.index) return false;
if (value != rawInput.value) return false;
return Arrays.equals(parentTransaction, rawInput.parentTransaction);
}
@Override
public int hashCode() {
int result = (int) (index ^ (index >>> 32));
result = 31 * result + (parentTransaction != null ? Arrays.hashCode(parentTransaction) : 0);
result = 31 * result + (int) (value ^ (value >>> 32));
return result;
}
}

View file

@ -0,0 +1,36 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.locale;
import io.bitsquare.app.Version;
import java.io.Serializable;
public class CryptoCurrency extends TradeCurrency implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
public CryptoCurrency(String currencyCode, String name) {
super(currencyCode, name);
}
public CryptoCurrency(String currencyCode, String name, String symbol) {
super(currencyCode, name, symbol);
}
}

View file

@ -0,0 +1,54 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.locale;
import io.bitsquare.app.Version;
import io.bitsquare.user.Preferences;
import java.io.Serializable;
import java.util.Currency;
public class FiatCurrency extends TradeCurrency implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
private final Currency currency;
public FiatCurrency(String currencyCode) {
this(Currency.getInstance(currencyCode));
}
public FiatCurrency(Currency currency) {
super(currency.getCurrencyCode(), currency.getDisplayName(Preferences.getDefaultLocale()), currency.getSymbol());
this.currency = currency;
}
public Currency getCurrency() {
return currency;
}
@Override
public String toString() {
return "FiatCurrency{" +
"currency=" + currency +
", code='" + code + '\'' +
", name='" + name + '\'' +
", symbol='" + symbol + '\'' +
'}';
}
}

View file

@ -0,0 +1,89 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.locale;
import io.bitsquare.app.Version;
import java.io.Serializable;
public class TradeCurrency implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
protected final String code;
protected final String name;
protected String symbol;
public TradeCurrency(String code) {
this.code = code;
this.name = CurrencyUtil.getNameByCode(code);
}
protected TradeCurrency(String code, String name) {
this.code = code;
this.name = name;
}
public TradeCurrency(String code, String name, String symbol) {
this.code = code;
this.name = name;
this.symbol = symbol;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
public String getSymbol() {
return symbol;
}
public String getCodeAndName() {
return code + " (" + name + ")";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TradeCurrency)) return false;
TradeCurrency that = (TradeCurrency) o;
return !(getCode() != null ? !getCode().equals(that.getCode()) : that.getCode() != null);
}
@Override
public int hashCode() {
return getCode() != null ? getCode().hashCode() : 0;
}
@Override
public String toString() {
return "TradeCurrency{" +
"code='" + code + '\'' +
", name='" + name + '\'' +
", symbol='" + symbol + '\'' +
'}';
}
}

View file

@ -0,0 +1,43 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import io.bitsquare.locale.FiatCurrency;
import java.io.Serializable;
public class AliPayAccount extends PaymentAccount implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
public AliPayAccount() {
super(PaymentMethod.ALI_PAY);
setSingleTradeCurrency(new FiatCurrency("CNY"));
contractData = new AliPayAccountContractData(paymentMethod.getId(), id, paymentMethod.getMaxTradePeriod());
}
public void setAccountNr(String accountNr) {
((AliPayAccountContractData) contractData).setAccountNr(accountNr);
}
public String getAccountNr() {
return ((AliPayAccountContractData) contractData).getAccountNr();
}
}

View file

@ -0,0 +1,53 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import java.io.Serializable;
public class AliPayAccountContractData extends PaymentAccountContractData implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
private String accountNr;
public AliPayAccountContractData(String paymentMethod, String id, int maxTradePeriod) {
super(paymentMethod, id, maxTradePeriod);
}
public void setAccountNr(String accountNr) {
this.accountNr = accountNr;
}
public String getAccountNr() {
return accountNr;
}
@Override
public String getPaymentDetails() {
return "AliPay - Account nr.: " + accountNr;
}
@Override
public String toString() {
return "AliPayAccountContractData{" +
"accountNr='" + accountNr + '\'' +
'}';
}
}

View file

@ -0,0 +1,42 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import java.io.Serializable;
public class BlockChainAccount extends PaymentAccount implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
public BlockChainAccount() {
super(PaymentMethod.BLOCK_CHAINS);
contractData = new BlockChainAccountContractData(paymentMethod.getId(), id, paymentMethod.getMaxTradePeriod());
}
public void setAddress(String address) {
((BlockChainAccountContractData) contractData).setAddress(address);
}
public String getAddress() {
return ((BlockChainAccountContractData) contractData).getAddress();
}
}

View file

@ -0,0 +1,55 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import java.io.Serializable;
public class BlockChainAccountContractData extends PaymentAccountContractData implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
private String address;
private String paymentId;
public BlockChainAccountContractData(String paymentMethod, String id, int maxTradePeriod) {
super(paymentMethod, id, maxTradePeriod);
}
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
@Override
public String getPaymentDetails() {
return "Address: " + address;
}
public void setPaymentId(String paymentId) {
this.paymentId = paymentId;
}
public String getPaymentId() {
return paymentId;
}
}

View file

@ -0,0 +1,46 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import io.bitsquare.locale.CurrencyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
public class OKPayAccount extends PaymentAccount implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
private static final Logger log = LoggerFactory.getLogger(OKPayAccount.class);
public OKPayAccount() {
super(PaymentMethod.OK_PAY);
tradeCurrencies.addAll(CurrencyUtil.getAllOKPayCurrencies());
contractData = new OKPayAccountContractData(paymentMethod.getId(), id, paymentMethod.getMaxTradePeriod());
}
public void setAccountNr(String accountNr) {
((OKPayAccountContractData) contractData).setAccountNr(accountNr);
}
public String getAccountNr() {
return ((OKPayAccountContractData) contractData).getAccountNr();
}
}

View file

@ -0,0 +1,48 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import java.io.Serializable;
public class OKPayAccountContractData extends PaymentAccountContractData implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
private String accountNr;
public OKPayAccountContractData(String paymentMethod, String id, int maxTradePeriod) {
super(paymentMethod, id, maxTradePeriod);
}
public void setAccountNr(String accountNr) {
this.accountNr = accountNr;
}
public String getAccountNr() {
return accountNr;
}
@Override
public String getPaymentDetails() {
return "OKPay - Account nr.: " + accountNr;
}
}

View file

@ -0,0 +1,168 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import io.bitsquare.locale.Country;
import io.bitsquare.locale.TradeCurrency;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class PaymentAccount implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
private static final Logger log = LoggerFactory.getLogger(PaymentAccount.class);
protected final String id;
protected final PaymentMethod paymentMethod;
protected String accountName;
protected final List<TradeCurrency> tradeCurrencies = new ArrayList<>();
protected TradeCurrency selectedTradeCurrency;
@Nullable
protected Country country = null;
protected PaymentAccountContractData contractData;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public PaymentAccount(PaymentMethod paymentMethod) {
this.paymentMethod = paymentMethod;
id = UUID.randomUUID().toString();
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void addCurrency(TradeCurrency tradeCurrency) {
if (!tradeCurrencies.contains(tradeCurrency))
tradeCurrencies.add(tradeCurrency);
}
public void removeCurrency(TradeCurrency tradeCurrency) {
if (tradeCurrencies.contains(tradeCurrency))
tradeCurrencies.remove(tradeCurrency);
}
public boolean hasMultipleCurrencies() {
return tradeCurrencies.size() > 1;
}
public void setSingleTradeCurrency(TradeCurrency tradeCurrency) {
tradeCurrencies.clear();
tradeCurrencies.add(tradeCurrency);
setSelectedTradeCurrency(tradeCurrency);
}
public TradeCurrency getSingleTradeCurrency() {
if (!tradeCurrencies.isEmpty())
return tradeCurrencies.get(0);
else
return null;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter, Setter
///////////////////////////////////////////////////////////////////////////////////////////
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
@Nullable
public Country getCountry() {
return country;
}
public void setCountry(@Nullable Country country) {
this.country = country;
contractData.setCountryCode(country.code);
}
public void setSelectedTradeCurrency(TradeCurrency tradeCurrency) {
selectedTradeCurrency = tradeCurrency;
}
public TradeCurrency getSelectedTradeCurrency() {
return selectedTradeCurrency;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter
///////////////////////////////////////////////////////////////////////////////////////////
public String getId() {
return id;
}
public PaymentMethod getPaymentMethod() {
return paymentMethod;
}
public List<TradeCurrency> getTradeCurrencies() {
return tradeCurrencies;
}
public PaymentAccountContractData getContractData() {
return contractData;
}
public String getPaymentDetails() {
return contractData.getPaymentDetails();
}
public int getMaxTradePeriod() {
return contractData.getMaxTradePeriod();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Util
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public String toString() {
return contractData.toString() + '\'' +
"PaymentAccount{" +
"id='" + id + '\'' +
", paymentMethod=" + paymentMethod +
", accountName='" + accountName + '\'' +
", tradeCurrencies=" + tradeCurrencies +
", selectedTradeCurrency=" + selectedTradeCurrency +
", country=" + country +
", contractData=" + contractData +
'}';
}
}

View file

@ -0,0 +1,102 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import javax.annotation.Nullable;
import java.io.Serializable;
public abstract class PaymentAccountContractData implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
private final String paymentMethodName;
private final String id;
private final int maxTradePeriod;
@Nullable
private String countryCode;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public PaymentAccountContractData(String paymentMethodName, String id, int maxTradePeriod) {
this.paymentMethodName = paymentMethodName;
this.id = id;
this.maxTradePeriod = maxTradePeriod;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter, Setter
///////////////////////////////////////////////////////////////////////////////////////////
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
@Nullable
public String getCountryCode() {
return countryCode;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter
///////////////////////////////////////////////////////////////////////////////////////////
public String getId() {
return id;
}
public String getPaymentMethodName() {
return paymentMethodName;
}
abstract public String getPaymentDetails();
public int getMaxTradePeriod() {
return maxTradePeriod;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PaymentAccountContractData)) return false;
PaymentAccountContractData that = (PaymentAccountContractData) o;
if (maxTradePeriod != that.maxTradePeriod) return false;
if (paymentMethodName != null ? !paymentMethodName.equals(that.paymentMethodName) : that.paymentMethodName != null)
return false;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return !(countryCode != null ? !countryCode.equals(that.countryCode) : that.countryCode != null);
}
@Override
public int hashCode() {
int result = paymentMethodName != null ? paymentMethodName.hashCode() : 0;
result = 31 * result + (id != null ? id.hashCode() : 0);
result = 31 * result + maxTradePeriod;
result = 31 * result + (countryCode != null ? countryCode.hashCode() : 0);
return result;
}
}

View file

@ -0,0 +1,144 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
// Don't use Enum as it breaks serialisation when changing entries and we want to stay flexible here
public class PaymentMethod implements Serializable, Comparable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
protected final Logger log = LoggerFactory.getLogger(this.getClass());
// time in blocks (average 10 min for one block confirmation
private static final int HOUR = 6;
private static final int DAY = HOUR * 24;
public static final String OK_PAY_ID = "OK_PAY";
public static final String PERFECT_MONEY_ID = "PERFECT_MONEY";
public static final String SEPA_ID = "SEPA";
public static final String SWISH_ID = "SWISH";
public static final String ALI_PAY_ID = "ALI_PAY";
/* public static final String FED_WIRE="FED_WIRE";*/
/* public static final String TRANSFER_WISE="TRANSFER_WISE";*/
/* public static final String US_POSTAL_MONEY_ORDER="US_POSTAL_MONEY_ORDER";*/
public static final String BLOCK_CHAINS_ID = "BLOCK_CHAINS";
public static PaymentMethod OK_PAY;
public static PaymentMethod PERFECT_MONEY;
public static PaymentMethod SEPA;
public static PaymentMethod SWISH;
public static PaymentMethod ALI_PAY;
/* public static PaymentMethod FED_WIRE;*/
/* public static PaymentMethod TRANSFER_WISE;*/
/* public static PaymentMethod US_POSTAL_MONEY_ORDER;*/
public static PaymentMethod BLOCK_CHAINS;
public static final List<PaymentMethod> ALL_VALUES = new ArrayList<>(Arrays.asList(
OK_PAY = new PaymentMethod(OK_PAY_ID, 0, HOUR), // tx instant so min. wait time
PERFECT_MONEY = new PaymentMethod(PERFECT_MONEY_ID, 0, DAY),
SEPA = new PaymentMethod(SEPA_ID, 0, 8 * DAY), // sepa takes 1-3 business days. We use 8 days to include safety for holidays
SWISH = new PaymentMethod(SWISH_ID, 0, DAY),
ALI_PAY = new PaymentMethod(ALI_PAY_ID, 0, DAY),
/* FED_WIRE = new PaymentMethod(FED_WIRE_ID, 0, DAY),*/
/* TRANSFER_WISE = new PaymentMethod(TRANSFER_WISE_ID, 0, DAY),*/
/* US_POSTAL_MONEY_ORDER = new PaymentMethod(US_POSTAL_MONEY_ORDER_ID, 0, DAY),*/
BLOCK_CHAINS = new PaymentMethod(BLOCK_CHAINS_ID, 0, DAY)
));
private final String id;
private final long lockTime;
private final int maxTradePeriod;
/**
* @param id
* @param lockTime lock time when seller release BTC until the payout tx gets valid (bitcoin tx lockTime). Serves as protection
* against charge back risk. If Bank do the charge back quickly the Arbitrator and the seller can push another
* double spend tx to invalidate the time locked payout tx. For the moment we set all to 0 but will have it in
* place when needed.
* @param maxTradePeriod The min. period a trader need to wait until he gets displayed the contact form for opening a dispute.
*/
public PaymentMethod(String id, long lockTime, int maxTradePeriod) {
this.id = id;
this.lockTime = lockTime;
this.maxTradePeriod = maxTradePeriod;
}
public static PaymentMethod getPaymentMethodByName(String name) {
return ALL_VALUES.stream().filter(e -> e.getId().equals(name)).findFirst().get();
}
public String getId() {
return id;
}
public int getMaxTradePeriod() {
return maxTradePeriod;
}
public long getLockTime() {
return lockTime;
}
@Override
public int compareTo(@NotNull Object other) {
return this.id.compareTo(((PaymentMethod) other).id);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PaymentMethod)) return false;
PaymentMethod that = (PaymentMethod) o;
if (getLockTime() != that.getLockTime()) return false;
if (getMaxTradePeriod() != that.getMaxTradePeriod()) return false;
return !(getId() != null ? !getId().equals(that.getId()) : that.getId() != null);
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (int) (getLockTime() ^ (getLockTime() >>> 32));
result = 31 * result + getMaxTradePeriod();
return result;
}
@Override
public String toString() {
return "PaymentMethod{" +
"name='" + id + '\'' +
", lockTime=" + lockTime +
", waitPeriodForOpenDispute=" + maxTradePeriod +
'}';
}
}

View file

@ -0,0 +1,51 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import io.bitsquare.locale.FiatCurrency;
import java.io.Serializable;
public class PerfectMoneyAccount extends PaymentAccount implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
public PerfectMoneyAccount() {
super(PaymentMethod.PERFECT_MONEY);
setSingleTradeCurrency(new FiatCurrency("USD"));
contractData = new PerfectMoneyAccountContractData(paymentMethod.getId(), id, paymentMethod.getMaxTradePeriod());
}
public String getHolderName() {
return ((PerfectMoneyAccountContractData) contractData).getHolderName();
}
public void setHolderName(String holderName) {
((PerfectMoneyAccountContractData) contractData).setHolderName(holderName);
}
public void setAccountNr(String accountNr) {
((PerfectMoneyAccountContractData) contractData).setAccountNr(accountNr);
}
public String getAccountNr() {
return ((PerfectMoneyAccountContractData) contractData).getAccountNr();
}
}

View file

@ -0,0 +1,56 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import java.io.Serializable;
public class PerfectMoneyAccountContractData extends PaymentAccountContractData implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
private String holderName;
private String accountNr;
public PerfectMoneyAccountContractData(String paymentMethod, String id, int maxTradePeriod) {
super(paymentMethod, id, maxTradePeriod);
}
public String getHolderName() {
return holderName;
}
public void setHolderName(String holderName) {
this.holderName = holderName;
}
public void setAccountNr(String accountNr) {
this.accountNr = accountNr;
}
public String getAccountNr() {
return accountNr;
}
@Override
public String getPaymentDetails() {
return "PerfectMoney - Holder name: " + holderName + ", account nr.: " + accountNr;
}
}

View file

@ -0,0 +1,71 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import java.io.Serializable;
import java.util.List;
public class SepaAccount extends PaymentAccount implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
public SepaAccount() {
super(PaymentMethod.SEPA);
contractData = new SepaAccountContractData(paymentMethod.getId(), id, paymentMethod.getMaxTradePeriod());
}
public void setHolderName(String holderName) {
((SepaAccountContractData) contractData).setHolderName(holderName);
}
public String getHolderName() {
return ((SepaAccountContractData) contractData).getHolderName();
}
public void setIban(String iban) {
((SepaAccountContractData) contractData).setIban(iban);
}
public String getIban() {
return ((SepaAccountContractData) contractData).getIban();
}
public void setBic(String bic) {
((SepaAccountContractData) contractData).setBic(bic);
}
public String getBic() {
return ((SepaAccountContractData) contractData).getBic();
}
public List<String> getAcceptedCountryCodes() {
return ((SepaAccountContractData) contractData).getAcceptedCountryCodes();
}
public void addAcceptedCountry(String countryCode) {
((SepaAccountContractData) contractData).addAcceptedCountry(countryCode);
}
public void removeAcceptedCountry(String countryCode) {
((SepaAccountContractData) contractData).removeAcceptedCountry(countryCode);
}
}

View file

@ -0,0 +1,89 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import io.bitsquare.locale.CountryUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class SepaAccountContractData extends PaymentAccountContractData implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
transient private static final Logger log = LoggerFactory.getLogger(SepaAccountContractData.class);
private String holderName;
private String iban;
private String bic;
private Set<String> acceptedCountryCodes;
public SepaAccountContractData(String paymentMethod, String id, int maxTradePeriod) {
super(paymentMethod, id, maxTradePeriod);
acceptedCountryCodes = CountryUtil.getAllSepaCountries().stream().map(e -> e.code).collect(Collectors.toSet());
}
public void setHolderName(String holderName) {
this.holderName = holderName;
}
public String getHolderName() {
return holderName;
}
public void setIban(String iban) {
this.iban = iban;
}
public String getIban() {
return iban;
}
public void setBic(String bic) {
this.bic = bic;
}
public String getBic() {
return bic;
}
public void addAcceptedCountry(String countryCode) {
acceptedCountryCodes.add(countryCode);
}
public void removeAcceptedCountry(String countryCode) {
acceptedCountryCodes.remove(countryCode);
}
public List<String> getAcceptedCountryCodes() {
List<String> sortedList = new ArrayList<>(acceptedCountryCodes);
sortedList.sort((a, b) -> a.compareTo(b));
return sortedList;
}
@Override
public String getPaymentDetails() {
return "SEPA - Holder name: " + holderName + ", IBAN: " + iban + ", BIC: " + bic + ", country code: " + getCountryCode();
}
}

View file

@ -0,0 +1,51 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import io.bitsquare.locale.FiatCurrency;
import java.io.Serializable;
public class SwishAccount extends PaymentAccount implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
public SwishAccount() {
super(PaymentMethod.SWISH);
setSingleTradeCurrency(new FiatCurrency("SEK"));
contractData = new SwishAccountContractData(paymentMethod.getId(), id, paymentMethod.getMaxTradePeriod());
}
public void setMobileNr(String mobileNr) {
((SwishAccountContractData) contractData).setMobileNr(mobileNr);
}
public String getMobileNr() {
return ((SwishAccountContractData) contractData).getMobileNr();
}
public void setHolderName(String holderName) {
((SwishAccountContractData) contractData).setHolderName(holderName);
}
public String getHolderName() {
return ((SwishAccountContractData) contractData).getHolderName();
}
}

View file

@ -0,0 +1,56 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment;
import io.bitsquare.app.Version;
import java.io.Serializable;
public class SwishAccountContractData extends PaymentAccountContractData implements Serializable {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
private String mobileNr;
private String holderName;
public SwishAccountContractData(String paymentMethod, String id, int maxTradePeriod) {
super(paymentMethod, id, maxTradePeriod);
}
public void setMobileNr(String mobileNr) {
this.mobileNr = mobileNr;
}
public String getMobileNr() {
return mobileNr;
}
public String getHolderName() {
return holderName;
}
public void setHolderName(String holderName) {
this.holderName = holderName;
}
@Override
public String getPaymentDetails() {
return "Swish - Holder name: " + holderName + ", mobile nr.: " + mobileNr;
}
}

View file

@ -0,0 +1,97 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment.unused;
import io.bitsquare.app.Version;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
// US only
public class FedWireAccount extends PaymentAccount implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
private static final Logger log = LoggerFactory.getLogger(FedWireAccount.class);
private String holderName;
private String holderState;
private String holderZIP;
private String holderStreet;
private String holderCity;
private String holderSSN; // Optional? social security Nr only Arizona and Oklahoma?
private String accountNr;
private String bankCode;// SWIFT Code/BIC/RoutingNr/ABA (ABA for UD domestic)
private String bankName;
private String bankState;
private String bankZIP;
private String bankStreet;
private String bankCity;
private FedWireAccount() {
super(PaymentMethod.SEPA);
}
public String getHolderName() {
return holderName;
}
public void setHolderName(String holderName) {
this.holderName = holderName;
}
public String getAccountNr() {
return accountNr;
}
public void setAccountNr(String accountNr) {
this.accountNr = accountNr;
}
public String getBankCode() {
return bankCode;
}
public void setBankCode(String bankCode) {
this.bankCode = bankCode;
}
@Override
public String getPaymentDetails() {
return "{accountName='" + accountName + '\'' +
'}';
}
@Override
public String toString() {
return "SepaAccount{" +
"accountName='" + accountName + '\'' +
", id='" + id + '\'' +
", paymentMethod=" + paymentMethod +
", holderName='" + holderName + '\'' +
", accountNr='" + accountNr + '\'' +
", bankCode='" + bankCode + '\'' +
", country=" + country +
", tradeCurrencies='" + getTradeCurrencies() + '\'' +
", selectedTradeCurrency=" + selectedTradeCurrency +
'}';
}
}

View file

@ -0,0 +1,87 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment.unused;
import io.bitsquare.app.Version;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
public class TransferWiseAccount extends PaymentAccount implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
private static final Logger log = LoggerFactory.getLogger(TransferWiseAccount.class);
private String holderName;
private String iban;
private String bic;
private TransferWiseAccount() {
super(PaymentMethod.SEPA);
}
public String getHolderName() {
return holderName;
}
public void setHolderName(String holderName) {
this.holderName = holderName;
}
public String getIban() {
return iban;
}
public void setIban(String iban) {
this.iban = iban;
}
public String getBic() {
return bic;
}
public void setBic(String bic) {
this.bic = bic;
}
@Override
public String getPaymentDetails() {
return "TransferWise{accountName='" + accountName + '\'' +
'}';
}
@Override
public String toString() {
return "TransferWiseAccount{" +
"accountName='" + accountName + '\'' +
", id='" + id + '\'' +
", paymentMethod=" + paymentMethod +
", holderName='" + holderName + '\'' +
", iban='" + iban + '\'' +
", bic='" + bic + '\'' +
", country=" + country +
", tradeCurrencies='" + getTradeCurrencies() + '\'' +
", selectedTradeCurrency=" + selectedTradeCurrency +
'}';
}
}

View file

@ -0,0 +1,86 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.payment.unused;
import io.bitsquare.app.Version;
import io.bitsquare.payment.PaymentAccount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
public class USPostalMoneyOrderAccount extends PaymentAccount implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
private static final Logger log = LoggerFactory.getLogger(USPostalMoneyOrderAccount.class);
private String holderName;
private String iban;
private String bic;
private USPostalMoneyOrderAccount() {
super(null /*PaymentMethod.US_POSTAL_MONEY_ORDER*/);
}
public String getHolderName() {
return holderName;
}
public void setHolderName(String holderName) {
this.holderName = holderName;
}
public String getIban() {
return iban;
}
public void setIban(String iban) {
this.iban = iban;
}
public String getBic() {
return bic;
}
public void setBic(String bic) {
this.bic = bic;
}
@Override
public String getPaymentDetails() {
return "{accountName='" + accountName + '\'' +
'}';
}
@Override
public String toString() {
return "USPostalMoneyOrderAccount{" +
"accountName='" + accountName + '\'' +
", id='" + id + '\'' +
", paymentMethod=" + paymentMethod +
", holderName='" + holderName + '\'' +
", iban='" + iban + '\'' +
", bic='" + bic + '\'' +
", country=" + country +
", tradeCurrencies='" + getTradeCurrencies() + '\'' +
", selectedTradeCurrency=" + selectedTradeCurrency +
'}';
}
}

View file

@ -0,0 +1,25 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.handlers;
import io.bitsquare.trade.Trade;
public interface TradeResultHandler {
void handleResult(Trade trade);
}

View file

@ -0,0 +1,47 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade;
import io.bitsquare.p2p.Address;
import io.bitsquare.trade.offer.Offer;
import org.bitcoinj.core.Sha256Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
public class ArbitrationSelectionRule {
private static final Logger log = LoggerFactory.getLogger(ArbitrationSelectionRule.class);
public static Address select(List<Address> acceptedArbitratorAddresses, Offer offer) {
List<Address> candidates = new ArrayList<>();
for (Address offerArbitratorAddress : offer.getArbitratorAddresses()) {
candidates.addAll(acceptedArbitratorAddresses.stream().filter(offerArbitratorAddress::equals).collect(Collectors.toList()));
}
checkArgument(candidates.size() > 0, "candidates.size() <= 0");
int index = Math.abs(Sha256Hash.hash(offer.getId().getBytes()).hashCode()) % candidates.size();
Address selectedArbitrator = candidates.get(index);
log.debug("selectedArbitrator " + selectedArbitrator);
return selectedArbitrator;
}
}

View file

@ -0,0 +1,75 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.buyer;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs;
import io.bitsquare.common.crypto.CryptoUtil;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
public class CreateAndSignDepositTxAsBuyer extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateAndSignDepositTxAsBuyer.class);
public CreateAndSignDepositTxAsBuyer(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
Coin buyerInputAmount = FeePolicy.SECURITY_DEPOSIT.add(FeePolicy.TX_FEE);
Coin msOutputAmount = buyerInputAmount.add(FeePolicy.SECURITY_DEPOSIT).add(trade.getTradeAmount());
log.debug("getContractAsJson");
log.debug("----------");
log.debug(trade.getContractAsJson());
log.debug("----------");
byte[] contractHash = CryptoUtil.getHash(trade.getContractAsJson());
trade.setContractHash(contractHash);
PreparedDepositTxAndOffererInputs result = processModel.getTradeWalletService().offererCreatesAndSignsDepositTx(
true,
contractHash,
buyerInputAmount,
msOutputAmount,
processModel.tradingPeer.getRawInputs(),
processModel.tradingPeer.getChangeOutputValue(),
processModel.tradingPeer.getChangeOutputAddress(),
processModel.getAddressEntry(),
processModel.getTradeWalletPubKey(),
processModel.tradingPeer.getTradeWalletPubKey(),
processModel.getArbitratorPubKey(trade.getArbitratorAddress()));
processModel.setPreparedDepositTx(result.depositTransaction);
processModel.setRawInputs(result.rawOffererInputs);
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,51 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.buyer;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.data.InputsAndChangeOutput;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateDepositTxInputsAsBuyer extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateDepositTxInputsAsBuyer.class);
public CreateDepositTxInputsAsBuyer(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
Coin takerInputAmount = FeePolicy.SECURITY_DEPOSIT.add(FeePolicy.TX_FEE);
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(takerInputAmount, processModel.getAddressEntry());
processModel.setRawInputs(result.rawInputs);
processModel.setChangeOutputValue(result.changeOutputValue);
processModel.setChangeOutputAddress(result.changeOutputAddress);
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,76 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.buyer;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.common.crypto.CryptoUtil;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Transaction;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
public class SignAndPublishDepositTxAsBuyer extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTxAsBuyer.class);
public SignAndPublishDepositTxAsBuyer(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
byte[] contractHash = CryptoUtil.getHash(trade.getContractAsJson());
trade.setContractHash(contractHash);
processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(
false,
contractHash,
processModel.getPreparedDepositTx(),
processModel.getRawInputs(),
processModel.tradingPeer.getRawInputs(),
processModel.getTradeWalletPubKey(),
processModel.tradingPeer.getTradeWalletPubKey(),
processModel.getArbitratorPubKey(trade.getArbitratorAddress()),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.trace("takerSignAndPublishTx succeeded " + transaction);
trade.setDepositTx(transaction);
trade.setTakeOfferDate(new Date());
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
complete();
}
@Override
public void onFailure(@NotNull Throwable t) {
failed(t);
}
});
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,48 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.offerer;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AddDepositTxToWallet extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(AddDepositTxToWallet.class);
public AddDepositTxToWallet(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
// To access tx confidence we need to add that tx into our wallet.
Transaction depositTx = processModel.getTradeWalletService().addTransactionToWallet(trade.getDepositTx());
// update with full tx
trade.setDepositTx(depositTx);
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,89 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.offerer;
import io.bitsquare.common.crypto.CryptoUtil;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.p2p.Address;
import io.bitsquare.payment.PaymentAccountContractData;
import io.bitsquare.trade.BuyerAsOffererTrade;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.TradingPeer;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
public class CreateAndSignContract extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateAndSignContract.class);
public CreateAndSignContract(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
checkNotNull(processModel.getTakeOfferFeeTxId(), "processModel.getTakeOfferFeeTxId() must not be null");
TradingPeer taker = processModel.tradingPeer;
PaymentAccountContractData offererPaymentAccountContractData = processModel.getPaymentAccountContractData(trade);
PaymentAccountContractData takerPaymentAccountContractData = taker.getPaymentAccountContractData();
boolean isBuyerOffererOrSellerTaker = trade instanceof BuyerAsOffererTrade;
Address buyerAddress = isBuyerOffererOrSellerTaker ? processModel.getMyAddress() : processModel.getTempTradingPeerAddress();
Address sellerAddress = isBuyerOffererOrSellerTaker ? processModel.getTempTradingPeerAddress() : processModel.getMyAddress();
log.debug("isBuyerOffererOrSellerTaker " + isBuyerOffererOrSellerTaker);
log.debug("buyerAddress " + buyerAddress);
log.debug("sellerAddress " + sellerAddress);
Contract contract = new Contract(
processModel.getOffer(),
trade.getTradeAmount(),
processModel.getTakeOfferFeeTxId(),
buyerAddress,
sellerAddress,
trade.getArbitratorAddress(),
isBuyerOffererOrSellerTaker,
processModel.getAccountId(),
taker.getAccountId(),
offererPaymentAccountContractData,
takerPaymentAccountContractData,
processModel.getPubKeyRing(),
taker.getPubKeyRing(),
processModel.getAddressEntry().getAddressString(),
taker.getPayoutAddressString(),
processModel.getTradeWalletPubKey(),
taker.getTradeWalletPubKey()
);
String contractAsJson = Utilities.objectToJson(contract);
String signature = CryptoUtil.signMessage(processModel.getKeyRing().getMsgSignatureKeyPair().getPrivate(), contractAsJson);
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setOffererContractSignature(signature);
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,46 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.offerer;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoadTakeOfferFeeTx extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(LoadTakeOfferFeeTx.class);
public LoadTakeOfferFeeTx(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
// TODO impl. not completed
//processModel.getWalletService().findTxInBlockChain(processModel.getTakeOfferFeeTxId());
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,65 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.offerer;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.checkTradeId;
public class ProcessDepositTxPublishedMessage extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessDepositTxPublishedMessage.class);
public ProcessDepositTxPublishedMessage(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
log.debug("current trade state " + trade.getState());
DepositTxPublishedMessage message = (DepositTxPublishedMessage) processModel.getTradeMessage();
checkTradeId(processModel.getId(), message);
checkNotNull(message);
checkArgument(message.depositTx != null);
trade.setDepositTx(processModel.getWalletService().getTransactionFromSerializedTx(message.depositTx));
trade.setState(Trade.State.DEPOSIT_PUBLISHED_MSG_RECEIVED);
trade.setTakeOfferDate(new Date());
if (trade instanceof OffererTrade)
processModel.getOpenOfferManager().closeOpenOffer(trade.getOffer());
// update to the latest peer address of our peer if the message is correct
trade.setTradingPeerAddress(processModel.getTempTradingPeerAddress());
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,90 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.offerer;
import io.bitsquare.common.crypto.CryptoUtil;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.payment.BlockChainAccountContractData;
import io.bitsquare.payment.PaymentAccountContractData;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.messages.PayDepositRequest;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.checkTradeId;
import static io.bitsquare.util.Validator.nonEmptyStringOf;
public class ProcessPayDepositRequest extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessPayDepositRequest.class);
public ProcessPayDepositRequest(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
log.debug("current trade state " + trade.getState());
PayDepositRequest payDepositRequest = (PayDepositRequest) processModel.getTradeMessage();
checkTradeId(processModel.getId(), payDepositRequest);
checkNotNull(payDepositRequest);
processModel.tradingPeer.setRawInputs(checkNotNull(payDepositRequest.rawInputs));
checkArgument(payDepositRequest.rawInputs.size() > 0);
processModel.tradingPeer.setChangeOutputValue(payDepositRequest.changeOutputValue);
if (payDepositRequest.changeOutputAddress != null)
processModel.tradingPeer.setChangeOutputAddress(payDepositRequest.changeOutputAddress);
processModel.tradingPeer.setTradeWalletPubKey(checkNotNull(payDepositRequest.takerTradeWalletPubKey));
processModel.tradingPeer.setPayoutAddressString(nonEmptyStringOf(payDepositRequest.takerPayoutAddressString));
processModel.tradingPeer.setPubKeyRing(checkNotNull(payDepositRequest.takerPubKeyRing));
PaymentAccountContractData paymentAccountContractData = checkNotNull(payDepositRequest.takerPaymentAccountContractData);
processModel.tradingPeer.setPaymentAccountContractData(paymentAccountContractData);
// We apply the payment ID in case its a cryptoNote coin. It is created form the hash of the trade ID
if (paymentAccountContractData instanceof BlockChainAccountContractData &&
CurrencyUtil.isCryptoNoteCoin(processModel.getOffer().getCurrencyCode())) {
String paymentId = CryptoUtil.getHashAsHex(trade.getId()).substring(0, 32);
((BlockChainAccountContractData) paymentAccountContractData).setPaymentId(paymentId);
}
processModel.tradingPeer.setAccountId(nonEmptyStringOf(payDepositRequest.takerAccountId));
processModel.setTakeOfferFeeTxId(nonEmptyStringOf(payDepositRequest.takeOfferFeeTxId));
processModel.setTakerAcceptedArbitratorAddresses(checkNotNull(payDepositRequest.acceptedArbitratorAddresses));
if (payDepositRequest.acceptedArbitratorAddresses.size() < 1)
failed("acceptedArbitratorNames size must be at least 1");
trade.setArbitratorAddress(checkNotNull(payDepositRequest.arbitratorAddress));
checkArgument(payDepositRequest.tradeAmount > 0);
trade.setTradeAmount(Coin.valueOf(payDepositRequest.tradeAmount));
// update to the latest peer address of our peer if the payDepositRequest is correct
trade.setTradingPeerAddress(processModel.getTempTradingPeerAddress());
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,76 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.offerer;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.messaging.SendMailMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.messages.PublishDepositTxRequest;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendPublishDepositTxRequest extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SendPublishDepositTxRequest.class);
public SendPublishDepositTxRequest(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
trade.setState(Trade.State.DEPOSIT_PUBLISH_REQUESTED);
PublishDepositTxRequest tradeMessage = new PublishDepositTxRequest(
processModel.getId(),
processModel.getPaymentAccountContractData(trade),
processModel.getAccountId(),
processModel.getTradeWalletPubKey(),
trade.getContractAsJson(),
trade.getOffererContractSignature(),
processModel.getAddressEntry().getAddressString(),
processModel.getPreparedDepositTx(),
processModel.getRawInputs(),
trade.getOpenDisputeTimeAsBlockHeight(),
trade.getCheckPaymentTimeAsBlockHeight()
);
processModel.getP2PService().sendEncryptedMailMessage(
trade.getTradingPeerAddress(),
processModel.tradingPeer.getPubKeyRing(),
tradeMessage,
new SendMailMessageListener() {
@Override
public void onArrived() {
log.trace("Message arrived at peer.");
complete();
}
@Override
public void onFault() {
appendToErrorMessage("PublishDepositTxRequest sending failed");
failed();
}
}
);
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,108 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.offerer;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.OffererTrade;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// The buyer waits for the msg from the seller that he has published the deposit tx.
// In error case he might not get that msg so we check additionally the balance of our inputs, if it is zero, it means the deposit
// is already published. We set then the DEPOSIT_LOCKED state, so the user get informed that he is already in the critical state and need
// to request support.
public class SetupDepositBalanceListener extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SetupDepositBalanceListener.class);
private Subscription tradeStateSubscription;
private BalanceListener balanceListener;
public SetupDepositBalanceListener(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
WalletService walletService = processModel.getWalletService();
Address address = walletService.getAddressEntryByOfferId(trade.getId()).getAddress();
balanceListener = walletService.addBalanceListener(new BalanceListener(address) {
@Override
public void onBalanceChanged(Coin balance) {
updateBalance(balance);
}
});
walletService.addBalanceListener(balanceListener);
tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), newValue -> {
log.debug("tradeStateSubscription newValue " + newValue);
if (newValue == Trade.State.DEPOSIT_PUBLISHED_MSG_RECEIVED
|| newValue == Trade.State.DEPOSIT_SEEN_IN_NETWORK) {
walletService.removeBalanceListener(balanceListener);
log.debug(" UserThread.execute(this::unSubscribe);");
// TODO is that allowed?
UserThread.execute(this::unSubscribe);
}
});
updateBalance(walletService.getBalanceForAddress(address));
// we complete immediately, our object stays alive because the balanceListener is stored in the WalletService
complete();
} catch (Throwable t) {
failed(t);
}
}
private void unSubscribe() {
//TODO investigate, seems to not get called sometimes
log.debug("unSubscribe tradeStateSubscription");
tradeStateSubscription.unsubscribe();
}
private void updateBalance(Coin balance) {
log.debug("updateBalance " + balance.toFriendlyString());
log.debug("pre tradeState " + trade.getState().toString());
Trade.State tradeState = trade.getState();
if (balance.compareTo(Coin.ZERO) == 0) {
if (trade instanceof OffererTrade) {
processModel.getOpenOfferManager().closeOpenOffer(trade.getOffer());
if (tradeState == Trade.State.DEPOSIT_PUBLISH_REQUESTED) {
trade.setState(Trade.State.DEPOSIT_SEEN_IN_NETWORK);
} else if (tradeState.getPhase() == Trade.Phase.PREPARATION) {
processModel.getTradeManager().removePreparedTrade(trade);
} else if (tradeState.getPhase().ordinal() < Trade.Phase.DEPOSIT_PAID.ordinal()) {
processModel.getTradeManager().addTradeToFailedTrades(trade);
}
}
}
log.debug("tradeState " + trade.getState().toString());
}
}

View file

@ -0,0 +1,48 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.offerer;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.ArbitrationSelectionRule;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyArbitrationSelection extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(VerifyArbitrationSelection.class);
public VerifyArbitrationSelection(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
if (trade.getArbitratorAddress().equals(ArbitrationSelectionRule.select(processModel.getTakerAcceptedArbitratorAddresses(),
processModel.getOffer())))
complete();
else
failed("Arbitrator selection verification failed");
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,70 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.seller;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs;
import io.bitsquare.common.crypto.CryptoUtil;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
public class CreateAndSignDepositTxAsSeller extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateAndSignDepositTxAsSeller.class);
public CreateAndSignDepositTxAsSeller(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
Coin sellerInputAmount = FeePolicy.SECURITY_DEPOSIT.add(FeePolicy.TX_FEE).add(trade.getTradeAmount());
Coin msOutputAmount = sellerInputAmount.add(FeePolicy.SECURITY_DEPOSIT);
byte[] contractHash = CryptoUtil.getHash(trade.getContractAsJson());
trade.setContractHash(contractHash);
PreparedDepositTxAndOffererInputs result = processModel.getTradeWalletService().offererCreatesAndSignsDepositTx(
false,
contractHash,
sellerInputAmount,
msOutputAmount,
processModel.tradingPeer.getRawInputs(),
processModel.tradingPeer.getChangeOutputValue(),
processModel.tradingPeer.getChangeOutputAddress(),
processModel.getAddressEntry(),
processModel.tradingPeer.getTradeWalletPubKey(),
processModel.getTradeWalletPubKey(),
processModel.getArbitratorPubKey(trade.getArbitratorAddress()));
processModel.setPreparedDepositTx(result.depositTransaction);
processModel.setRawInputs(result.rawOffererInputs);
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,57 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.seller;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.data.InputsAndChangeOutput;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CreateDepositTxInputsAsSeller extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(CreateDepositTxInputsAsSeller.class);
public CreateDepositTxInputsAsSeller(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
if (trade.getTradeAmount() != null) {
Coin takerInputAmount = FeePolicy.SECURITY_DEPOSIT.add(FeePolicy.TX_FEE).add(trade.getTradeAmount());
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(takerInputAmount, processModel
.getAddressEntry());
processModel.setRawInputs(result.rawInputs);
processModel.setChangeOutputValue(result.changeOutputValue);
processModel.setChangeOutputAddress(result.changeOutputAddress);
complete();
} else {
failed("trade.getTradeAmount() = null");
}
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,79 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.seller;
import com.google.common.util.concurrent.FutureCallback;
import io.bitsquare.common.crypto.CryptoUtil;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Transaction;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
public class SignAndPublishDepositTxAsSeller extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTxAsSeller.class);
public SignAndPublishDepositTxAsSeller(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
log.debug("getContractAsJson");
log.debug("----------");
log.debug(trade.getContractAsJson());
log.debug("----------");
byte[] contractHash = CryptoUtil.getHash(trade.getContractAsJson());
trade.setContractHash(contractHash);
processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(
true,
contractHash,
processModel.getPreparedDepositTx(),
processModel.tradingPeer.getRawInputs(),
processModel.getRawInputs(),
processModel.tradingPeer.getTradeWalletPubKey(),
processModel.getTradeWalletPubKey(),
processModel.getArbitratorPubKey(trade.getArbitratorAddress()),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.trace("takerSignAndPublishTx succeeded " + transaction);
trade.setDepositTx(transaction);
trade.setTakeOfferDate(new Date());
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
complete();
}
@Override
public void onFailure(@NotNull Throwable t) {
failed(t);
}
});
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,50 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.shared;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InitWaitPeriodForOpenDispute extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(InitWaitPeriodForOpenDispute.class);
public InitWaitPeriodForOpenDispute(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
int openDisputeTimeAsBlockHeight = processModel.getTradeWalletService().getLastBlockSeenHeight()
+ trade.getOffer().getPaymentMethod().getMaxTradePeriod();
trade.setOpenDisputeTimeAsBlockHeight(openDisputeTimeAsBlockHeight);
int checkPaymentTimeAsBlockHeight = processModel.getTradeWalletService().getLastBlockSeenHeight()
+ trade.getOffer().getPaymentMethod().getMaxTradePeriod() / 2;
trade.setCheckPaymentTimeAsBlockHeight(checkPaymentTimeAsBlockHeight);
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,67 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.shared;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
public class SignPayoutTx extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SignPayoutTx.class);
public SignPayoutTx(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not be null");
Coin sellerPayoutAmount = FeePolicy.SECURITY_DEPOSIT;
Coin buyerPayoutAmount = sellerPayoutAmount.add(trade.getTradeAmount());
long lockTimeAsBlockHeight = processModel.getTradeWalletService().getLastBlockSeenHeight() + trade.getOffer().getPaymentMethod().getLockTime();
trade.setLockTimeAsBlockHeight(lockTimeAsBlockHeight);
byte[] payoutTxSignature = processModel.getTradeWalletService().sellerSignsPayoutTx(
trade.getDepositTx(),
buyerPayoutAmount,
sellerPayoutAmount,
processModel.tradingPeer.getPayoutAddressString(),
processModel.getAddressEntry(),
lockTimeAsBlockHeight,
processModel.tradingPeer.getTradeWalletPubKey(),
processModel.getTradeWalletPubKey(),
processModel.getArbitratorPubKey(trade.getArbitratorAddress()));
processModel.setPayoutTxSignature(payoutTxSignature);
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,46 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.taker;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoadCreateOfferFeeTx extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(LoadCreateOfferFeeTx.class);
public LoadCreateOfferFeeTx(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
// TODO impl. not completed
///processModel.getWalletService().findTxInBlockChain(trade.getOffer().getOfferFeePaymentTxID());
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,89 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.taker;
import io.bitsquare.common.crypto.CryptoUtil;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.payment.BlockChainAccountContractData;
import io.bitsquare.payment.PaymentAccountContractData;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.messages.PublishDepositTxRequest;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.bitsquare.util.Validator.checkTradeId;
import static io.bitsquare.util.Validator.nonEmptyStringOf;
public class ProcessPublishDepositTxRequest extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(ProcessPublishDepositTxRequest.class);
public ProcessPublishDepositTxRequest(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
log.debug("current trade state " + trade.getState());
PublishDepositTxRequest publishDepositTxRequest = (PublishDepositTxRequest) processModel.getTradeMessage();
checkTradeId(processModel.getId(), publishDepositTxRequest);
checkNotNull(publishDepositTxRequest);
PaymentAccountContractData paymentAccountContractData = checkNotNull(publishDepositTxRequest.offererPaymentAccountContractData);
processModel.tradingPeer.setPaymentAccountContractData(paymentAccountContractData);
// We apply the payment ID in case its a cryptoNote coin. It is created form the hash of the trade ID
if (paymentAccountContractData instanceof BlockChainAccountContractData &&
CurrencyUtil.isCryptoNoteCoin(processModel.getOffer().getCurrencyCode())) {
String paymentId = CryptoUtil.getHashAsHex(trade.getId()).substring(0, 32);
((BlockChainAccountContractData) paymentAccountContractData).setPaymentId(paymentId);
}
processModel.tradingPeer.setAccountId(nonEmptyStringOf(publishDepositTxRequest.offererAccountId));
processModel.tradingPeer.setTradeWalletPubKey(checkNotNull(publishDepositTxRequest.offererTradeWalletPubKey));
processModel.tradingPeer.setContractAsJson(nonEmptyStringOf(publishDepositTxRequest.offererContractAsJson));
processModel.tradingPeer.setContractSignature(nonEmptyStringOf(publishDepositTxRequest.offererContractSignature));
processModel.tradingPeer.setPayoutAddressString(nonEmptyStringOf(publishDepositTxRequest.offererPayoutAddressString));
processModel.tradingPeer.setRawInputs(checkNotNull(publishDepositTxRequest.offererInputs));
processModel.setPreparedDepositTx(checkNotNull(publishDepositTxRequest.preparedDepositTx));
checkArgument(publishDepositTxRequest.offererInputs.size() > 0);
if (publishDepositTxRequest.openDisputeTimeAsBlockHeight != 0) {
trade.setOpenDisputeTimeAsBlockHeight(publishDepositTxRequest.openDisputeTimeAsBlockHeight);
} else {
failed("waitPeriodForOpenDisputeAsBlockHeight = 0");
}
if (publishDepositTxRequest.checkPaymentTimeAsBlockHeight != 0) {
trade.setCheckPaymentTimeAsBlockHeight(publishDepositTxRequest.checkPaymentTimeAsBlockHeight);
} else {
failed("notificationTimeAsBlockHeight = 0");
}
// update to the latest peer address of our peer if the message is correct
trade.setTradingPeerAddress(processModel.getTempTradingPeerAddress());
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,46 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.taker;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.ArbitrationSelectionRule;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SelectArbitrator extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SelectArbitrator.class);
public SelectArbitrator(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
trade.setArbitratorAddress(ArbitrationSelectionRule.select(processModel.getUser().getAcceptedArbitratorAddresses(), processModel.getOffer()));
complete();
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,80 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.taker;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.messaging.SendMailboxMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendDepositTxPublishedMessage extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SendDepositTxPublishedMessage.class);
public SendDepositTxPublishedMessage(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
if (trade.getDepositTx() != null) {
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(processModel.getId(),
trade.getDepositTx().bitcoinSerialize(),
processModel.getMyAddress());
processModel.getP2PService().sendEncryptedMailboxMessage(
trade.getTradingPeerAddress(),
processModel.tradingPeer.getPubKeyRing(),
tradeMessage,
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.trace("Message arrived at peer.");
trade.setState(Trade.State.DEPOSIT_PUBLISHED_MSG_SENT);
complete();
}
@Override
public void onStoredInMailbox() {
log.trace("Message stored in mailbox.");
trade.setState(Trade.State.DEPOSIT_PUBLISHED_MSG_SENT);
complete();
}
@Override
public void onFault() {
appendToErrorMessage("DepositTxPublishedMessage sending failed");
failed();
}
}
);
} else {
log.error("trade.getDepositTx() = " + trade.getDepositTx());
failed("DepositTx is null");
}
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,89 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.taker;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.p2p.messaging.SendMailboxMessageListener;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.messages.PayDepositRequest;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SendPayDepositRequest extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(SendPayDepositRequest.class);
public SendPayDepositRequest(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
if (processModel.getTakeOfferFeeTx() != null) {
PayDepositRequest payDepositRequest = new PayDepositRequest(
processModel.getMyAddress(),
processModel.getId(),
trade.getTradeAmount().value,
processModel.getRawInputs(),
processModel.getChangeOutputValue(),
processModel.getChangeOutputAddress(),
processModel.getTradeWalletPubKey(),
processModel.getAddressEntry().getAddressString(),
processModel.getPubKeyRing(),
processModel.getPaymentAccountContractData(trade),
processModel.getAccountId(),
processModel.getTakeOfferFeeTx().getHashAsString(),
processModel.getUser().getAcceptedArbitratorAddresses(),
trade.getArbitratorAddress()
);
processModel.getP2PService().sendEncryptedMailboxMessage(
trade.getTradingPeerAddress(),
processModel.tradingPeer.getPubKeyRing(),
payDepositRequest,
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.trace("Message arrived at peer.");
complete();
}
@Override
public void onStoredInMailbox() {
log.trace("Message stored in mailbox.");
complete();
}
@Override
public void onFault() {
appendToErrorMessage("PayDepositRequest sending failed");
failed();
}
}
);
} else {
log.error("processModel.getTakeOfferFeeTx() = " + processModel.getTakeOfferFeeTx());
failed("TakeOfferFeeTx is null");
}
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,98 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.trade.tasks.taker;
import io.bitsquare.common.crypto.CryptoUtil;
import io.bitsquare.common.taskrunner.TaskRunner;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.p2p.Address;
import io.bitsquare.payment.PaymentAccountContractData;
import io.bitsquare.trade.Contract;
import io.bitsquare.trade.SellerAsTakerTrade;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.protocol.trade.TradingPeer;
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VerifyAndSignContract extends TradeTask {
private static final Logger log = LoggerFactory.getLogger(VerifyAndSignContract.class);
public VerifyAndSignContract(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
}
@Override
protected void run() {
try {
runInterceptHook();
if (processModel.getTakeOfferFeeTx() != null) {
TradingPeer offerer = processModel.tradingPeer;
PaymentAccountContractData offererPaymentAccountContractData = offerer.getPaymentAccountContractData();
PaymentAccountContractData takerPaymentAccountContractData = processModel.getPaymentAccountContractData(trade);
boolean isBuyerOffererOrSellerTaker = trade instanceof SellerAsTakerTrade;
Address buyerAddress = isBuyerOffererOrSellerTaker ? processModel.getTempTradingPeerAddress() : processModel.getMyAddress();
Address sellerAddress = isBuyerOffererOrSellerTaker ? processModel.getMyAddress() : processModel.getTempTradingPeerAddress();
log.debug("isBuyerOffererOrSellerTaker " + isBuyerOffererOrSellerTaker);
log.debug("buyerAddress " + buyerAddress);
log.debug("sellerAddress " + sellerAddress);
Contract contract = new Contract(
processModel.getOffer(),
trade.getTradeAmount(),
processModel.getTakeOfferFeeTx().getHashAsString(),
buyerAddress,
sellerAddress,
trade.getArbitratorAddress(),
isBuyerOffererOrSellerTaker,
offerer.getAccountId(),
processModel.getAccountId(),
offererPaymentAccountContractData,
takerPaymentAccountContractData,
offerer.getPubKeyRing(),
processModel.getPubKeyRing(),
offerer.getPayoutAddressString(),
processModel.getAddressEntry().getAddressString(),
offerer.getTradeWalletPubKey(),
processModel.getTradeWalletPubKey()
);
String contractAsJson = Utilities.objectToJson(contract);
String signature = CryptoUtil.signMessage(processModel.getKeyRing().getMsgSignatureKeyPair().getPrivate(), contractAsJson);
trade.setContract(contract);
trade.setContractAsJson(contractAsJson);
trade.setTakerContractSignature(signature);
try {
CryptoUtil.verifyMessage(offerer.getPubKeyRing().getMsgSignaturePubKey(),
contractAsJson,
offerer.getContractSignature());
} catch (Throwable t) {
failed("Signature verification failed. " + t.getMessage());
}
complete();
} else {
failed("processModel.getTakeOfferFeeTx() = null");
}
} catch (Throwable t) {
failed(t);
}
}
}

View file

@ -0,0 +1,41 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.user;
import io.bitsquare.app.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
public class BlockChainExplorer implements Serializable {
// That object is saved to disc. We need to take care of changes to not break deserialization.
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
private static final Logger log = LoggerFactory.getLogger(BlockChainExplorer.class);
public final String name;
public final String txUrl;
public final String addressUrl;
public BlockChainExplorer(String name, String txUrl, String addressUrl) {
this.name = name;
this.txUrl = txUrl;
this.addressUrl = addressUrl;
}
}

View file

@ -0,0 +1,27 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.user;
public class PopupId {
// We don't use an enum because it would break updates if we add a new item in a new version
public static String SEC_DEPOSIT = "SEC_DEPOSIT";
public static String TRADE_WALLET = "TRADE_WALLET";
}

View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{15} - %msg %xEx%n</pattern>
</encoder>
</appender>
<root level="TRACE">
<appender-ref ref="CONSOLE_APPENDER"/>
</root>
<logger name="io.bitsquare" level="TRACE"/>
<logger name="com.msopentech.thali.toronionproxy.OnionProxyManagerEventHandler" level="WARN"/>
<logger name="io.bitsquare.btc.AddressBasedCoinSelector" level="OFF"/>
<logger name="io.bitsquare.gui.util.Profiler" level="ERROR"/>
<logger name="io.bitsquare.locale.BSResources" level="ERROR"/>
<logger name="io.bitsquare.temp.storage.RemoteStorage" level="WARN"/>
<logger name="io.bitsquare.storage.FileManager" level="WARN"/>
<logger name="org.bitcoinj" level="WARN"/>
<logger name="org.bitcoinj.core.BitcoinSerializer" level="WARN"/>
<logger name="org.bitcoinj.core.Peer" level="WARN"/>
<!--
<logger name="com.vinumeris.updatefx" level="OFF"/>
<logger name="io.netty" level="OFF"/>
<logger name="org.bitcoinj.core.BitcoinSerializer" level="ERROR"/>
<logger name="org.bitcoinj.core.Peer" level="ERROR"/>-->
<!-- <logger name="net.tomp2p.message.Encoder" level="WARN"/>
<logger name="net.tomp2p.message.Decoder" level="WARN"/>
<logger name="net.tomp2p.message.MessageHeaderCodec" level="WARN"/>
<logger name="io.netty.util" level="WARN"/>
<logger name="io.netty.channel" level="WARN"/>
<logger name="io.netty.buffer" level="WARN"/>-->
<!-- <logger name="org.bitcoinj.core.BitcoinSerializer" level="WARN"/>
<logger name="org.bitcoinj.core.AbstractBlockChain" level="WARN"/>
<logger name="org.bitcoinj.wallet.DeterministicKeyChain" level="WARN"/>-->
<!-- <logger name="io.bitsquare.btc.WalletService" level="WARN"/>-->
<!--
<logger name="org.bitcoinj.core.Wallet" level="OFF"/>
<logger name="org.bitcoinj.core.MemoryPool" level="OFF"/>
<logger name="org.bitcoinj.net.discovery.DnsDiscovery" level="OFF"/>
<logger name="org.bitcoinj.core.DownloadListener" level="OFF"/>
<logger name="org.bitcoinj.core.TransactionOutput" level="OFF"/>
<logger name="org.bitcoinj.core.BitcoinSerializer" level="OFF"/>
<logger name="org.bitcoinj.core.Peer" level="OFF"/>
<logger name="org.bitcoinj.core.PeerGroup" level="OFF"/>
<logger name="org.bitcoinj.core.PeerSocketHandler" level="OFF"/>
<logger name="org.bitcoinj.net.NioClientManager" level="OFF"/>
<logger name="org.bitcoinj.net.ConnectionHandler" level="OFF"/>
-->
</configuration>

View file

@ -0,0 +1,41 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.common.model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class ActivatableDataModel implements Activatable, DataModel {
protected final Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public final void _activate() {
this.activate();
}
protected void activate() {
}
@Override
public final void _deactivate() {
this.deactivate();
}
protected void deactivate() {
}
}

View file

@ -0,0 +1,41 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.common.model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class ActivatableViewModel implements Activatable, ViewModel {
protected final Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public final void _activate() {
this.activate();
}
protected void activate() {
}
@Override
public final void _deactivate() {
this.deactivate();
}
protected void deactivate() {
}
}

View file

@ -0,0 +1,172 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components;
import io.bitsquare.gui.util.validation.InputValidator;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.stage.Window;
import org.controlsfx.control.PopOver;
public class PasswordTextField extends PasswordField {
private final Effect invalidEffect = new DropShadow(BlurType.THREE_PASS_BOX, Color.RED, 4, 0.0, 0, 0);
private final ObjectProperty<InputValidator.ValidationResult> validationResult = new SimpleObjectProperty<>
(new InputValidator.ValidationResult(true));
private static PopOver errorMessageDisplay;
private Region layoutReference = this;
public InputValidator getValidator() {
return validator;
}
public void setValidator(InputValidator validator) {
this.validator = validator;
}
private InputValidator validator;
///////////////////////////////////////////////////////////////////////////////////////////
// Static
///////////////////////////////////////////////////////////////////////////////////////////
private static void hideErrorMessageDisplay() {
if (errorMessageDisplay != null)
errorMessageDisplay.hide();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public PasswordTextField() {
super();
validationResult.addListener((ov, oldValue, newValue) -> {
if (newValue != null) {
setEffect(newValue.isValid ? null : invalidEffect);
if (newValue.isValid)
hideErrorMessageDisplay();
else
applyErrorMessage(newValue);
}
});
sceneProperty().addListener((ov, oldValue, newValue) -> {
// we got removed from the scene so hide the popup (if open)
if (newValue == null)
hideErrorMessageDisplay();
});
focusedProperty().addListener((o, oldValue, newValue) -> {
if (oldValue && !newValue && validator != null)
validationResult.set(validator.validate(getText()));
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////////////////////////////
public void resetValidation() {
setEffect(null);
hideErrorMessageDisplay();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
/**
* @param layoutReference The node used as reference for positioning. If not set explicitly the
* ValidatingTextField instance is used.
*/
public void setLayoutReference(Region layoutReference) {
this.layoutReference = layoutReference;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public ObjectProperty<InputValidator.ValidationResult> validationResultProperty() {
return validationResult;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
private void applyErrorMessage(InputValidator.ValidationResult validationResult) {
if (errorMessageDisplay != null)
errorMessageDisplay.hide();
if (!validationResult.isValid) {
createErrorPopOver(validationResult.errorMessage);
if (getScene() != null)
errorMessageDisplay.show(getScene().getWindow(), getErrorPopupPosition().getX(),
getErrorPopupPosition().getY());
if (errorMessageDisplay != null)
errorMessageDisplay.setDetached(false);
}
}
private Point2D getErrorPopupPosition() {
Window window = getScene().getWindow();
Point2D point;
point = layoutReference.localToScene(0, 0);
double x = Math.floor(point.getX() + window.getX() + layoutReference.getWidth() + 20 - getPadding().getLeft() -
getPadding().getRight());
double y = Math.floor(point.getY() + window.getY() + getHeight() / 2 - getPadding().getTop() - getPadding()
.getBottom());
return new Point2D(x, y);
}
private static void createErrorPopOver(String errorMessage) {
Label errorLabel = new Label(errorMessage);
errorLabel.setId("validation-error");
errorLabel.setPadding(new Insets(0, 10, 0, 10));
errorLabel.setOnMouseClicked(e -> hideErrorMessageDisplay());
errorMessageDisplay = new PopOver(errorLabel);
errorMessageDisplay.setDetachable(true);
errorMessageDisplay.setDetachedTitle("Close");
errorMessageDisplay.setArrowIndent(5);
}
}

View file

@ -0,0 +1,84 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
public class TableGroupHeadline extends Pane {
private final Label label;
private final StringProperty text = new SimpleStringProperty();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public TableGroupHeadline() {
this("");
}
public TableGroupHeadline(String title) {
text.set(title);
GridPane.setMargin(this, new Insets(-10, -10, -10, -10));
GridPane.setColumnSpan(this, 2);
Pane bg = new StackPane();
bg.setId("table-group-headline");
bg.prefWidthProperty().bind(widthProperty());
bg.prefHeightProperty().bind(heightProperty());
label = new Label();
label.textProperty().bind(text);
label.setLayoutX(8);
label.setLayoutY(-8);
label.setPadding(new Insets(0, 7, 0, 5));
setActive();
getChildren().addAll(bg, label);
}
public void setInactive() {
setId("titled-group-bg");
label.setId("titled-group-bg-label");
}
private void setActive() {
setId("titled-group-bg-active");
label.setId("titled-group-bg-label-active");
}
public String getText() {
return text.get();
}
public StringProperty textProperty() {
return text;
}
public void setText(String text) {
this.text.set(text);
}
}

View file

@ -0,0 +1,98 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.paymentmethods;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.util.Layout;
import io.bitsquare.gui.util.validation.AliPayValidator;
import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.locale.BSResources;
import io.bitsquare.payment.AliPayAccount;
import io.bitsquare.payment.AliPayAccountContractData;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentAccountContractData;
import javafx.scene.layout.GridPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.gui.util.FormBuilder.*;
public class AliPayForm extends PaymentMethodForm {
private static final Logger log = LoggerFactory.getLogger(AliPayForm.class);
private final AliPayAccount aliPayAccount;
private final AliPayValidator aliPayValidator;
private InputTextField accountNrInputTextField;
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(paymentAccountContractData.getPaymentMethodName()));
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account nr.:", ((AliPayAccountContractData) paymentAccountContractData).getAccountNr());
addAllowedPeriod(gridPane, ++gridRow, paymentAccountContractData);
return gridRow;
}
public AliPayForm(PaymentAccount paymentAccount, AliPayValidator aliPayValidator, InputValidator inputValidator, GridPane gridPane, int gridRow) {
super(paymentAccount, inputValidator, gridPane, gridRow);
this.aliPayAccount = (AliPayAccount) paymentAccount;
this.aliPayValidator = aliPayValidator;
}
@Override
public void addFormForAddAccount() {
gridRowFrom = gridRow + 1;
accountNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account nr.:").second;
accountNrInputTextField.setValidator(aliPayValidator);
accountNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
aliPayAccount.setAccountNr(newValue);
updateFromInputs();
});
addLabelTextField(gridPane, ++gridRow, "Currency:", aliPayAccount.getSingleTradeCurrency().getCodeAndName());
addAllowedPeriod();
addAccountNameTextFieldWithAutoFillCheckBox();
}
@Override
protected void autoFillNameTextField() {
if (autoFillCheckBox != null && autoFillCheckBox.isSelected()) {
String accountNr = accountNrInputTextField.getText();
accountNr = accountNr.substring(0, Math.min(5, accountNr.length())) + "...";
String method = BSResources.get(paymentAccount.getPaymentMethod().getId());
accountNameTextField.setText(method.concat(", ").concat(accountNr));
}
}
@Override
public void addFormForDisplayAccount() {
gridRowFrom = gridRow;
addLabelTextField(gridPane, gridRow, "Account name:", aliPayAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(aliPayAccount.getPaymentMethod().getId()));
addLabelTextField(gridPane, ++gridRow, "Account nr.:", aliPayAccount.getAccountNr());
addLabelTextField(gridPane, ++gridRow, "Currency:", aliPayAccount.getSingleTradeCurrency().getCodeAndName());
addAllowedPeriod();
}
@Override
public void updateAllInputsValid() {
allInputsValid.set(isAccountNameValid()
&& aliPayValidator.validate(aliPayAccount.getAccountNr()).isValid
&& aliPayAccount.getTradeCurrencies().size() > 0);
}
}

View file

@ -0,0 +1,135 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.paymentmethods;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.util.Layout;
import io.bitsquare.gui.util.validation.AltCoinAddressValidator;
import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.payment.BlockChainAccount;
import io.bitsquare.payment.BlockChainAccountContractData;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentAccountContractData;
import javafx.collections.FXCollections;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.GridPane;
import javafx.util.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.gui.util.FormBuilder.*;
public class BlockChainForm extends PaymentMethodForm {
private static final Logger log = LoggerFactory.getLogger(BlockChainForm.class);
private final BlockChainAccount blockChainAccount;
private final AltCoinAddressValidator altCoinAddressValidator;
private InputTextField addressInputTextField;
private ComboBox<TradeCurrency> currencyComboBox;
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(paymentAccountContractData.getPaymentMethodName()));
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Address:", ((BlockChainAccountContractData) paymentAccountContractData).getAddress());
if (paymentAccountContractData instanceof BlockChainAccountContractData &&
((BlockChainAccountContractData) paymentAccountContractData).getPaymentId() != null)
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Payment ID:", ((BlockChainAccountContractData) paymentAccountContractData).getPaymentId());
addAllowedPeriod(gridPane, ++gridRow, paymentAccountContractData);
return gridRow;
}
public BlockChainForm(PaymentAccount paymentAccount, AltCoinAddressValidator altCoinAddressValidator, InputValidator inputValidator, GridPane gridPane,
int gridRow) {
super(paymentAccount, inputValidator, gridPane, gridRow);
this.blockChainAccount = (BlockChainAccount) paymentAccount;
this.altCoinAddressValidator = altCoinAddressValidator;
}
@Override
public void addFormForAddAccount() {
gridRowFrom = gridRow + 1;
addTradeCurrencyComboBox();
currencyComboBox.setPrefWidth(250);
addressInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Address:").second;
addressInputTextField.setValidator(altCoinAddressValidator);
addressInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
blockChainAccount.setAddress(newValue);
updateFromInputs();
});
addAllowedPeriod();
addAccountNameTextFieldWithAutoFillCheckBox();
}
@Override
protected void autoFillNameTextField() {
if (autoFillCheckBox != null && autoFillCheckBox.isSelected()) {
String method = BSResources.get(paymentAccount.getPaymentMethod().getId());
String address = addressInputTextField.getText();
address = address.substring(0, Math.min(9, address.length())) + "...";
String currency = paymentAccount.getSingleTradeCurrency() != null ? paymentAccount.getSingleTradeCurrency().getCode() : "?";
accountNameTextField.setText(method.concat(", ").concat(currency).concat(", ").concat(address));
}
}
@Override
public void addFormForDisplayAccount() {
gridRowFrom = gridRow;
addLabelTextField(gridPane, gridRow, "Account name:", blockChainAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(blockChainAccount.getPaymentMethod().getId()));
addLabelTextField(gridPane, ++gridRow, "Address:", blockChainAccount.getAddress());
addLabelTextField(gridPane, ++gridRow, "Crypto currency:", blockChainAccount.getSingleTradeCurrency().getCodeAndName());
addAllowedPeriod();
}
@Override
public void updateAllInputsValid() {
allInputsValid.set(isAccountNameValid()
&& altCoinAddressValidator.validate(blockChainAccount.getAddress()).isValid
&& blockChainAccount.getSingleTradeCurrency() != null);
}
@Override
protected void addTradeCurrencyComboBox() {
currencyComboBox = addLabelComboBox(gridPane, ++gridRow, "Crypto currency:").second;
currencyComboBox.setPromptText("Select crypto currency");
currencyComboBox.setItems(FXCollections.observableArrayList(CurrencyUtil.getSortedCryptoCurrencies()));
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 20));
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
@Override
public String toString(TradeCurrency tradeCurrency) {
return tradeCurrency.getCodeAndName();
}
@Override
public TradeCurrency fromString(String s) {
return null;
}
});
currencyComboBox.setOnAction(e -> {
paymentAccount.setSingleTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem());
updateFromInputs();
});
}
}

View file

@ -0,0 +1,140 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.paymentmethods;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.util.Layout;
import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.gui.util.validation.OKPayValidator;
import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.payment.OKPayAccount;
import io.bitsquare.payment.OKPayAccountContractData;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentAccountContractData;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.gui.util.FormBuilder.*;
public class OKPayForm extends PaymentMethodForm {
private static final Logger log = LoggerFactory.getLogger(OKPayForm.class);
private final OKPayAccount okPayAccount;
private final OKPayValidator okPayValidator;
private InputTextField accountNrInputTextField;
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(paymentAccountContractData.getPaymentMethodName()));
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account nr.:", ((OKPayAccountContractData) paymentAccountContractData).getAccountNr());
addAllowedPeriod(gridPane, ++gridRow, paymentAccountContractData);
return gridRow;
}
public OKPayForm(PaymentAccount paymentAccount, OKPayValidator okPayValidator, InputValidator inputValidator, GridPane gridPane, int gridRow) {
super(paymentAccount, inputValidator, gridPane, gridRow);
this.okPayAccount = (OKPayAccount) paymentAccount;
this.okPayValidator = okPayValidator;
}
@Override
public void addFormForAddAccount() {
gridRowFrom = gridRow + 1;
accountNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account nr.:").second;
accountNrInputTextField.setValidator(okPayValidator);
accountNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
okPayAccount.setAccountNr(newValue);
updateFromInputs();
});
addCurrenciesGrid(true);
addAllowedPeriod();
addAccountNameTextFieldWithAutoFillCheckBox();
}
private void addCurrenciesGrid(boolean isEditable) {
Label label = addLabel(gridPane, ++gridRow, "Supported OKPay currencies:", 0);
GridPane.setValignment(label, VPos.TOP);
FlowPane flowPane = new FlowPane();
flowPane.setPadding(new Insets(10, 10, 10, 10));
flowPane.setVgap(10);
flowPane.setHgap(10);
if (isEditable)
flowPane.setId("flowpane-checkboxes-bg");
else
flowPane.setId("flowpane-checkboxes-non-editable-bg");
CurrencyUtil.getAllOKPayCurrencies().stream().forEach(e ->
{
CheckBox checkBox = new CheckBox(e.getCode());
checkBox.setMouseTransparent(!isEditable);
checkBox.setSelected(okPayAccount.getTradeCurrencies().contains(e));
checkBox.setMinWidth(60);
checkBox.setMaxWidth(checkBox.getMinWidth());
checkBox.setOnAction(event -> {
if (checkBox.isSelected())
okPayAccount.addCurrency(e);
else
okPayAccount.removeCurrency(e);
updateAllInputsValid();
});
flowPane.getChildren().add(checkBox);
});
GridPane.setRowIndex(flowPane, gridRow);
GridPane.setColumnIndex(flowPane, 1);
gridPane.getChildren().add(flowPane);
}
@Override
protected void autoFillNameTextField() {
if (autoFillCheckBox != null && autoFillCheckBox.isSelected()) {
String accountNr = accountNrInputTextField.getText();
accountNr = accountNr.substring(0, Math.min(5, accountNr.length())) + "...";
String method = BSResources.get(paymentAccount.getPaymentMethod().getId());
accountNameTextField.setText(method.concat(", ").concat(accountNr));
}
}
@Override
public void addFormForDisplayAccount() {
gridRowFrom = gridRow;
addLabelTextField(gridPane, gridRow, "Account name:", okPayAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(okPayAccount.getPaymentMethod().getId()));
addLabelTextField(gridPane, ++gridRow, "Account nr.:", okPayAccount.getAccountNr());
addAllowedPeriod();
addCurrenciesGrid(false);
}
@Override
public void updateAllInputsValid() {
allInputsValid.set(isAccountNameValid()
&& okPayValidator.validate(okPayAccount.getAccountNr()).isValid
&& okPayAccount.getTradeCurrencies().size() > 0);
}
}

View file

@ -0,0 +1,154 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.paymentmethods;
import io.bitsquare.common.util.Tuple3;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentAccountContractData;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.util.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.gui.util.FormBuilder.*;
public abstract class PaymentMethodForm {
private static final Logger log = LoggerFactory.getLogger(PaymentMethodForm.class);
protected final PaymentAccount paymentAccount;
protected final InputValidator inputValidator;
protected final GridPane gridPane;
protected int gridRow;
protected final BooleanProperty allInputsValid = new SimpleBooleanProperty();
protected int gridRowFrom;
protected InputTextField accountNameTextField;
protected CheckBox autoFillCheckBox;
private ComboBox<TradeCurrency> currencyComboBox;
public PaymentMethodForm(PaymentAccount paymentAccount, InputValidator inputValidator, GridPane gridPane, int gridRow) {
this.paymentAccount = paymentAccount;
this.inputValidator = inputValidator;
this.gridPane = gridPane;
this.gridRow = gridRow;
}
protected void addTradeCurrencyComboBox() {
currencyComboBox = addLabelComboBox(gridPane, ++gridRow, "Currency:").second;
currencyComboBox.setPromptText("Select currency");
currencyComboBox.setItems(FXCollections.observableArrayList(CurrencyUtil.getAllSortedCurrencies()));
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
@Override
public String toString(TradeCurrency tradeCurrency) {
return tradeCurrency.getCodeAndName();
}
@Override
public TradeCurrency fromString(String s) {
return null;
}
});
currencyComboBox.setOnAction(e -> {
paymentAccount.setSingleTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem());
updateFromInputs();
});
}
protected void addAccountNameTextFieldWithAutoFillCheckBox() {
Tuple3<Label, InputTextField, CheckBox> tuple = addLabelInputTextFieldCheckBox(gridPane, ++gridRow, "Account name:", "Auto-fill");
accountNameTextField = tuple.second;
accountNameTextField.setPrefWidth(250);
accountNameTextField.setEditable(false);
accountNameTextField.setValidator(inputValidator);
accountNameTextField.textProperty().addListener((ov, oldValue, newValue) -> {
paymentAccount.setAccountName(newValue);
updateAllInputsValid();
});
autoFillCheckBox = tuple.third;
autoFillCheckBox.setSelected(true);
autoFillCheckBox.setOnAction(e -> {
accountNameTextField.setEditable(!autoFillCheckBox.isSelected());
autoFillNameTextField();
});
}
static void addAllowedPeriod(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
long hours = paymentAccountContractData.getMaxTradePeriod() / 6;
String displayText = hours + " hours";
if (hours == 24)
displayText = "1 day";
if (hours > 24)
displayText = hours / 24 + " days";
addLabelTextField(gridPane, gridRow, "Max. allowed trade period:", displayText);
}
protected void addAllowedPeriod() {
long hours = paymentAccount.getPaymentMethod().getMaxTradePeriod() / 6;
String displayText = hours + " hours";
if (hours == 24)
displayText = "1 day";
if (hours > 24)
displayText = hours / 24 + " days";
addLabelTextField(gridPane, ++gridRow, "Max. allowed trade period:", displayText);
}
abstract protected void autoFillNameTextField();
abstract public void addFormForAddAccount();
abstract public void addFormForDisplayAccount();
protected abstract void updateAllInputsValid();
public void updateFromInputs() {
autoFillNameTextField();
updateAllInputsValid();
}
public boolean isAccountNameValid() {
return inputValidator.validate(paymentAccount.getAccountName()).isValid;
}
public int getGridRow() {
return gridRow;
}
public int getRowSpan() {
return gridRow - gridRowFrom + 1;
}
public PaymentAccount getPaymentAccount() {
return paymentAccount;
}
public BooleanProperty allInputsValidProperty() {
return allInputsValid;
}
}

View file

@ -0,0 +1,109 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.paymentmethods;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.util.Layout;
import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.gui.util.validation.PerfectMoneyValidator;
import io.bitsquare.locale.BSResources;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentAccountContractData;
import io.bitsquare.payment.PerfectMoneyAccount;
import io.bitsquare.payment.PerfectMoneyAccountContractData;
import javafx.scene.layout.GridPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.gui.util.FormBuilder.*;
public class PerfectMoneyForm extends PaymentMethodForm {
private static final Logger log = LoggerFactory.getLogger(PerfectMoneyForm.class);
private final PerfectMoneyAccount perfectMoneyAccount;
private final PerfectMoneyValidator perfectMoneyValidator;
private InputTextField accountNrInputTextField;
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(paymentAccountContractData.getPaymentMethodName()));
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account holder name:", ((PerfectMoneyAccountContractData) paymentAccountContractData)
.getHolderName());
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account nr.:", ((PerfectMoneyAccountContractData) paymentAccountContractData).getAccountNr());
addAllowedPeriod(gridPane, ++gridRow, paymentAccountContractData);
return gridRow;
}
public PerfectMoneyForm(PaymentAccount paymentAccount, PerfectMoneyValidator perfectMoneyValidator, InputValidator inputValidator, GridPane gridPane, int
gridRow) {
super(paymentAccount, inputValidator, gridPane, gridRow);
this.perfectMoneyAccount = (PerfectMoneyAccount) paymentAccount;
this.perfectMoneyValidator = perfectMoneyValidator;
}
@Override
public void addFormForAddAccount() {
gridRowFrom = gridRow + 1;
InputTextField holderNameInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account holder name:").second;
holderNameInputTextField.setValidator(inputValidator);
holderNameInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
perfectMoneyAccount.setHolderName(newValue);
updateFromInputs();
});
accountNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account nr.:").second;
accountNrInputTextField.setValidator(perfectMoneyValidator);
accountNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
perfectMoneyAccount.setAccountNr(newValue);
updateFromInputs();
});
addLabelTextField(gridPane, ++gridRow, "Currency:", perfectMoneyAccount.getSingleTradeCurrency().getCodeAndName());
addAllowedPeriod();
addAccountNameTextFieldWithAutoFillCheckBox();
}
@Override
protected void autoFillNameTextField() {
if (autoFillCheckBox != null && autoFillCheckBox.isSelected()) {
String accountNr = accountNrInputTextField.getText();
accountNr = accountNr.substring(0, Math.min(5, accountNr.length())) + "...";
String method = BSResources.get(paymentAccount.getPaymentMethod().getId());
accountNameTextField.setText(method.concat(", ").concat(accountNr));
}
}
@Override
public void addFormForDisplayAccount() {
gridRowFrom = gridRow;
addLabelTextField(gridPane, gridRow, "Account name:", perfectMoneyAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(perfectMoneyAccount.getPaymentMethod().getId()));
addLabelTextField(gridPane, ++gridRow, "Account holder name:", perfectMoneyAccount.getHolderName());
addLabelTextField(gridPane, ++gridRow, "Account nr.:", perfectMoneyAccount.getAccountNr());
addLabelTextField(gridPane, ++gridRow, "Currency:", perfectMoneyAccount.getSingleTradeCurrency().getCodeAndName());
addAllowedPeriod();
}
@Override
public void updateAllInputsValid() {
allInputsValid.set(isAccountNameValid()
&& perfectMoneyValidator.validate(perfectMoneyAccount.getAccountNr()).isValid
&& perfectMoneyAccount.getTradeCurrencies().size() > 0);
}
}

View file

@ -0,0 +1,252 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.paymentmethods;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.util.Layout;
import io.bitsquare.gui.util.validation.BICValidator;
import io.bitsquare.gui.util.validation.IBANValidator;
import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.locale.*;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentAccountContractData;
import io.bitsquare.payment.SepaAccount;
import io.bitsquare.payment.SepaAccountContractData;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.util.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import static io.bitsquare.gui.util.FormBuilder.*;
public class SepaForm extends PaymentMethodForm {
private static final Logger log = LoggerFactory.getLogger(SepaForm.class);
private final SepaAccount sepaAccount;
private final IBANValidator ibanValidator;
private final BICValidator bicValidator;
private InputTextField ibanInputTextField;
private InputTextField bicInputTextField;
private TextField currencyTextField;
private List<CheckBox> euroCountryCheckBoxes = new ArrayList<>();
private List<CheckBox> nonEuroCountryCheckBoxes = new ArrayList<>();
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(paymentAccountContractData.getPaymentMethodName()));
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account holder name:", ((SepaAccountContractData) paymentAccountContractData).getHolderName());
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "IBAN:", ((SepaAccountContractData) paymentAccountContractData).getIban());
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "BIC/SWIFT:", ((SepaAccountContractData) paymentAccountContractData).getBic());
addAllowedPeriod(gridPane, ++gridRow, paymentAccountContractData);
return gridRow;
}
public SepaForm(PaymentAccount paymentAccount, IBANValidator ibanValidator, BICValidator bicValidator, InputValidator inputValidator,
GridPane gridPane, int gridRow) {
super(paymentAccount, inputValidator, gridPane, gridRow);
this.sepaAccount = (SepaAccount) paymentAccount;
this.ibanValidator = ibanValidator;
this.bicValidator = bicValidator;
}
@Override
public void addFormForAddAccount() {
gridRowFrom = gridRow + 1;
InputTextField holderNameInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account holder name:").second;
holderNameInputTextField.setValidator(inputValidator);
holderNameInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
sepaAccount.setHolderName(newValue);
updateFromInputs();
});
ibanInputTextField = addLabelInputTextField(gridPane, ++gridRow, "IBAN:").second;
ibanInputTextField.setValidator(ibanValidator);
ibanInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
sepaAccount.setIban(newValue);
updateFromInputs();
});
bicInputTextField = addLabelInputTextField(gridPane, ++gridRow, "BIC/SWIFT:").second;
bicInputTextField.setValidator(bicValidator);
bicInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
sepaAccount.setBic(newValue);
updateFromInputs();
});
Tuple2<Label, ComboBox> tuple2 = addLabelComboBox(gridPane, ++gridRow, "Country of Bank:");
ComboBox<Country> countryComboBox = tuple2.second;
countryComboBox.setPromptText("Select country of Bank");
countryComboBox.setConverter(new StringConverter<Country>() {
@Override
public String toString(Country country) {
return country.code + " (" + country.name + ")";
}
@Override
public Country fromString(String s) {
return null;
}
});
countryComboBox.setOnAction(e -> {
Country selectedItem = countryComboBox.getSelectionModel().getSelectedItem();
sepaAccount.setCountry(selectedItem);
TradeCurrency currency = CurrencyUtil.getCurrencyByCountryCode(selectedItem.code);
sepaAccount.setSingleTradeCurrency(currency);
currencyTextField.setText(currency.getCodeAndName());
updateCountriesSelection(true, euroCountryCheckBoxes);
updateCountriesSelection(true, nonEuroCountryCheckBoxes);
updateFromInputs();
});
currencyTextField = addLabelTextField(gridPane, ++gridRow, "Currency:").second;
addEuroCountriesGrid(true);
addNonEuroCountriesGrid(true);
addAllowedPeriod();
addAccountNameTextFieldWithAutoFillCheckBox();
countryComboBox.setItems(FXCollections.observableArrayList(CountryUtil.getAllSepaCountries()));
Country country = CountryUtil.getDefaultCountry();
countryComboBox.getSelectionModel().select(country);
sepaAccount.setCountry(country);
TradeCurrency currency = CurrencyUtil.getCurrencyByCountryCode(country.code);
sepaAccount.setSingleTradeCurrency(currency);
currencyTextField.setText(currency.getCodeAndName());
updateFromInputs();
}
private void addEuroCountriesGrid(boolean isEditable) {
addCountriesGrid(isEditable, "Accept taker countries (Euro):", euroCountryCheckBoxes, CountryUtil.getAllSepaEuroCountries());
}
private void addNonEuroCountriesGrid(boolean isEditable) {
addCountriesGrid(isEditable, "Accepted taker countries (non-Euro):", nonEuroCountryCheckBoxes, CountryUtil.getAllSepaNonEuroCountries());
}
private void addCountriesGrid(boolean isEditable, String title, List<CheckBox> checkBoxList, List<Country> dataProvider) {
Label label = addLabel(gridPane, ++gridRow, title, 0);
GridPane.setValignment(label, VPos.TOP);
FlowPane flowPane = new FlowPane();
flowPane.setPadding(new Insets(10, 10, 10, 10));
flowPane.setVgap(10);
flowPane.setHgap(10);
if (isEditable)
flowPane.setId("flowpane-checkboxes-bg");
else
flowPane.setId("flowpane-checkboxes-non-editable-bg");
dataProvider.stream().forEach(country ->
{
final String countryCode = country.code;
CheckBox checkBox = new CheckBox(countryCode);
checkBox.setUserData(countryCode);
checkBoxList.add(checkBox);
checkBox.setMouseTransparent(!isEditable);
checkBox.setMinWidth(45);
checkBox.setMaxWidth(checkBox.getMinWidth());
checkBox.setTooltip(new Tooltip(country.name));
checkBox.setOnAction(event -> {
if (checkBox.isSelected())
sepaAccount.addAcceptedCountry(countryCode);
else
sepaAccount.removeAcceptedCountry(countryCode);
updateAllInputsValid();
});
flowPane.getChildren().add(checkBox);
});
updateCountriesSelection(isEditable, checkBoxList);
GridPane.setRowIndex(flowPane, gridRow);
GridPane.setColumnIndex(flowPane, 1);
gridPane.getChildren().add(flowPane);
}
private void updateCountriesSelection(boolean isEditable, List<CheckBox> checkBoxList) {
checkBoxList.stream().forEach(checkBox -> {
String countryCode = (String) checkBox.getUserData();
TradeCurrency selectedCurrency = sepaAccount.getSelectedTradeCurrency();
if (selectedCurrency == null)
selectedCurrency = CurrencyUtil.getCurrencyByCountryCode(CountryUtil.getDefaultCountry().code);
boolean selected;
if (isEditable) {
selected = CurrencyUtil.getCurrencyByCountryCode(countryCode).getCode().equals(selectedCurrency.getCode());
if (selected)
sepaAccount.addAcceptedCountry(countryCode);
else
sepaAccount.removeAcceptedCountry(countryCode);
} else {
selected = sepaAccount.getAcceptedCountryCodes().contains(countryCode);
}
checkBox.setSelected(selected);
});
}
@Override
protected void autoFillNameTextField() {
if (autoFillCheckBox != null && autoFillCheckBox.isSelected()) {
String iban = ibanInputTextField.getText();
if (iban.length() > 5)
iban = "..." + iban.substring(iban.length() - 5, iban.length());
String method = BSResources.get(paymentAccount.getPaymentMethod().getId());
String country = paymentAccount.getCountry() != null ? paymentAccount.getCountry().code : "?";
String currency = paymentAccount.getSingleTradeCurrency() != null ? paymentAccount.getSingleTradeCurrency().getCode() : "?";
accountNameTextField.setText(method.concat(", ").concat(currency).concat(", ").concat(country).concat(", ").concat(iban));
}
}
@Override
public void updateAllInputsValid() {
allInputsValid.set(isAccountNameValid()
&& bicValidator.validate(sepaAccount.getBic()).isValid
&& ibanValidator.validate(sepaAccount.getIban()).isValid
&& inputValidator.validate(sepaAccount.getHolderName()).isValid
&& sepaAccount.getAcceptedCountryCodes().size() > 0
&& sepaAccount.getSingleTradeCurrency() != null
&& sepaAccount.getCountry() != null);
}
@Override
public void addFormForDisplayAccount() {
gridRowFrom = gridRow;
addLabelTextField(gridPane, gridRow, "Account name:", sepaAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(sepaAccount.getPaymentMethod().getId()));
addLabelTextField(gridPane, ++gridRow, "Account holder name:", sepaAccount.getHolderName());
addLabelTextField(gridPane, ++gridRow, "IBAN:", sepaAccount.getIban());
addLabelTextField(gridPane, ++gridRow, "BIC/SWIFT:", sepaAccount.getBic());
addLabelTextField(gridPane, ++gridRow, "Location of Bank:", sepaAccount.getCountry().name);
addLabelTextField(gridPane, ++gridRow, "Currency:", sepaAccount.getSingleTradeCurrency().getCodeAndName());
addAllowedPeriod();
addEuroCountriesGrid(false);
addNonEuroCountriesGrid(false);
}
}

View file

@ -0,0 +1,108 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.components.paymentmethods;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.util.Layout;
import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.gui.util.validation.SwishValidator;
import io.bitsquare.locale.BSResources;
import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentAccountContractData;
import io.bitsquare.payment.SwishAccount;
import io.bitsquare.payment.SwishAccountContractData;
import javafx.scene.layout.GridPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.bitsquare.gui.util.FormBuilder.addLabelInputTextField;
import static io.bitsquare.gui.util.FormBuilder.addLabelTextField;
public class SwishForm extends PaymentMethodForm {
private static final Logger log = LoggerFactory.getLogger(SwishForm.class);
private final SwishAccount swishAccount;
private final SwishValidator swishValidator;
private InputTextField mobileNrInputTextField;
public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) {
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(paymentAccountContractData.getPaymentMethodName()));
addLabelTextField(gridPane, ++gridRow, "Account holder name:", ((SwishAccountContractData) paymentAccountContractData).getHolderName());
addLabelTextField(gridPane, ++gridRow, "Mobile nr.:", ((SwishAccountContractData) paymentAccountContractData).getMobileNr());
addAllowedPeriod(gridPane, ++gridRow, paymentAccountContractData);
return gridRow;
}
public SwishForm(PaymentAccount paymentAccount, SwishValidator swishValidator, InputValidator inputValidator, GridPane gridPane, int gridRow) {
super(paymentAccount, inputValidator, gridPane, gridRow);
this.swishAccount = (SwishAccount) paymentAccount;
this.swishValidator = swishValidator;
}
@Override
public void addFormForAddAccount() {
gridRowFrom = gridRow + 1;
InputTextField holderNameInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account holder name:").second;
holderNameInputTextField.setValidator(inputValidator);
holderNameInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
swishAccount.setHolderName(newValue);
updateFromInputs();
});
mobileNrInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Mobile nr.:").second;
mobileNrInputTextField.setValidator(swishValidator);
mobileNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
swishAccount.setMobileNr(newValue);
updateFromInputs();
});
addLabelTextField(gridPane, ++gridRow, "Currency:", swishAccount.getSingleTradeCurrency().getCodeAndName());
addAllowedPeriod();
addAccountNameTextFieldWithAutoFillCheckBox();
}
@Override
protected void autoFillNameTextField() {
if (autoFillCheckBox != null && autoFillCheckBox.isSelected()) {
String mobileNr = mobileNrInputTextField.getText();
mobileNr = mobileNr.substring(0, Math.min(5, mobileNr.length())) + "...";
String method = BSResources.get(paymentAccount.getPaymentMethod().getId());
accountNameTextField.setText(method.concat(", ").concat(mobileNr));
}
}
@Override
public void addFormForDisplayAccount() {
gridRowFrom = gridRow;
addLabelTextField(gridPane, gridRow, "Account name:", swishAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(swishAccount.getPaymentMethod().getId()));
addLabelTextField(gridPane, ++gridRow, "Account holder name:", swishAccount.getHolderName());
addLabelTextField(gridPane, ++gridRow, "Mobile nr.:", swishAccount.getMobileNr());
addLabelTextField(gridPane, ++gridRow, "Currency:", swishAccount.getSingleTradeCurrency().getCodeAndName());
addAllowedPeriod();
}
@Override
public void updateAllInputsValid() {
allInputsValid.set(isAccountNameValid()
&& swishValidator.validate(swishAccount.getMobileNr()).isValid
&& inputValidator.validate(swishAccount.getHolderName()).isValid
&& swishAccount.getTradeCurrencies().size() > 0);
}
}

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ This file is part of Bitsquare.
~
~ Bitsquare 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.
~
~ Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
-->
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="root" fx:controller="io.bitsquare.gui.main.account.arbitratorregistration.ArbitratorRegistrationView"
spacing="10"
xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets bottom="0.0" left="10.0" right="10.0" top="0.0"/>
</padding>
</VBox>

View file

@ -0,0 +1,232 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.account.arbitratorregistration;
import io.bitsquare.app.BitsquareApp;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.common.view.ActivatableViewAndModel;
import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.popups.Popup;
import io.bitsquare.gui.util.FormBuilder;
import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.gui.util.Layout;
import io.bitsquare.locale.LanguageUtil;
import javafx.beans.value.ChangeListener;
import javafx.collections.ListChangeListener;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.util.Callback;
import javafx.util.StringConverter;
import javax.inject.Inject;
import static io.bitsquare.gui.util.FormBuilder.*;
@FxmlView
public class ArbitratorRegistrationView extends ActivatableViewAndModel<VBox, ArbitratorRegistrationViewModel> {
private TextField pubKeyTextField;
private ListView<String> languagesListView;
private ComboBox<String> languageComboBox;
private int gridRow = 0;
private Button registerButton;
private Button revokeButton;
private ChangeListener<Arbitrator> arbitratorChangeListener;
private EnterPrivKeyPopup enterPrivKeyPopup;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private ArbitratorRegistrationView(ArbitratorRegistrationViewModel model) {
super(model);
}
@Override
public void initialize() {
buildUI();
languageComboBox.setItems(model.allLanguageCodes);
arbitratorChangeListener = (observable, oldValue, arbitrator) -> updateLanguageList();
}
@Override
protected void activate() {
}
@Override
protected void deactivate() {
}
public void onTabSelection(boolean isSelectedTab) {
if (isSelectedTab) {
model.myArbitratorProperty.addListener(arbitratorChangeListener);
updateLanguageList();
if (model.registrationPubKeyAsHex.get() == null && enterPrivKeyPopup == null) {
enterPrivKeyPopup = new EnterPrivKeyPopup();
enterPrivKeyPopup.onClose(() -> enterPrivKeyPopup = null)
.onKey(privKey -> model.setPrivKeyAndCheckPubKey(privKey))
.width(700)
.show();
}
} else {
model.myArbitratorProperty.removeListener(arbitratorChangeListener);
}
}
private void updateLanguageList() {
languagesListView.setItems(model.languageCodes);
languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2);
languagesListView.getItems().addListener((ListChangeListener<String>)
c -> languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2));
}
private void buildUI() {
GridPane gridPane = new GridPane();
gridPane.setPadding(new Insets(30, 25, -1, 25));
gridPane.setHgap(5);
gridPane.setVgap(5);
ColumnConstraints columnConstraints1 = new ColumnConstraints();
columnConstraints1.setHalignment(HPos.RIGHT);
columnConstraints1.setHgrow(Priority.SOMETIMES);
columnConstraints1.setMinWidth(200);
ColumnConstraints columnConstraints2 = new ColumnConstraints();
columnConstraints2.setHgrow(Priority.ALWAYS);
gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2);
root.getChildren().add(gridPane);
addTitledGroupBg(gridPane, gridRow, 3, "Arbitrator registration");
pubKeyTextField = FormBuilder.addLabelTextField(gridPane, gridRow, "Public key:",
model.registrationPubKeyAsHex.get(), Layout.FIRST_ROW_DISTANCE).second;
if (BitsquareApp.DEV_MODE)
pubKeyTextField.setText("6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a");
pubKeyTextField.textProperty().bind(model.registrationPubKeyAsHex);
Tuple2<Label, ListView> tuple = addLabelListView(gridPane, ++gridRow, "Your languages:");
GridPane.setValignment(tuple.first, VPos.TOP);
languagesListView = tuple.second;
languagesListView.disableProperty().bind(model.registrationEditDisabled);
languagesListView.setMinHeight(3 * Layout.LIST_ROW_HEIGHT + 2);
languagesListView.setMaxHeight(6 * Layout.LIST_ROW_HEIGHT + 2);
languagesListView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
@Override
public ListCell<String> call(ListView<String> list) {
return new ListCell<String>() {
final Label label = new Label();
final ImageView icon = ImageUtil.getImageViewById(ImageUtil.REMOVE_ICON);
final Button removeButton = new Button("", icon);
final AnchorPane pane = new AnchorPane(label, removeButton);
{
label.setLayoutY(5);
removeButton.setId("icon-button");
AnchorPane.setRightAnchor(removeButton, 0d);
}
@Override
public void updateItem(final String item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
label.setText(LanguageUtil.getDisplayName(item));
removeButton.setOnAction(e -> onRemoveLanguage(item));
setGraphic(pane);
} else {
setGraphic(null);
}
}
};
}
});
languageComboBox = addLabelComboBox(gridPane, ++gridRow).second;
languageComboBox.disableProperty().bind(model.registrationEditDisabled);
languageComboBox.setPromptText("Add language");
languageComboBox.setConverter(new StringConverter<String>() {
@Override
public String toString(String code) {
return LanguageUtil.getDisplayName(code);
}
@Override
public String fromString(String s) {
return null;
}
});
languageComboBox.setOnAction(e -> onAddLanguage());
registerButton = addButtonAfterGroup(gridPane, ++gridRow, "Register arbitrator");
registerButton.disableProperty().bind(model.registrationEditDisabled);
registerButton.setOnAction(e -> onRegister());
revokeButton = addButton(gridPane, ++gridRow, "Revoke registration");
revokeButton.setDefaultButton(false);
revokeButton.disableProperty().bind(model.revokeButtonDisabled);
revokeButton.setOnAction(e -> onRevoke());
addTitledGroupBg(gridPane, ++gridRow, 2, "Information", Layout.GROUP_DISTANCE);
Label infoLabel = addMultilineLabel(gridPane, gridRow);
GridPane.setMargin(infoLabel, new Insets(Layout.FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0));
infoLabel.setText("Please not that you need to stay available for 15 days after revoking as there might be trades which are using you as " +
"arbitrator. The max. allowed trader period is 8 days and the dispute process might take up to 7 days.");
}
///////////////////////////////////////////////////////////////////////////////////////////
// UI actions
///////////////////////////////////////////////////////////////////////////////////////////
private void onAddLanguage() {
model.onAddLanguage(languageComboBox.getSelectionModel().getSelectedItem());
UserThread.execute(() -> languageComboBox.getSelectionModel().clearSelection());
}
private void onRemoveLanguage(String locale) {
model.onRemoveLanguage(locale);
if (languagesListView.getItems().size() == 0) {
new Popup().warning("You need to set at least 1 language.\nWe added the default language for you.").show();
model.onAddLanguage(LanguageUtil.getDefaultLanguageLocaleAsCode());
}
}
private void onRevoke() {
model.onRevoke(
() -> new Popup().information("You have successfully removed your arbitrator from the P2P network.").show(),
(errorMessage) -> new Popup().error("Could not remove arbitrator.\nError message: " + errorMessage).show());
}
private void onRegister() {
model.onRegister(
() -> new Popup().information("You have successfully registered your arbitrator to the P2P network.").show(),
(errorMessage) -> new Popup().error("Could not register arbitrator.\nError message: " + errorMessage).show());
}
}

View file

@ -0,0 +1,186 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.account.arbitratorregistration;
import com.google.inject.Inject;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.gui.common.model.ActivatableViewModel;
import io.bitsquare.locale.LanguageUtil;
import io.bitsquare.p2p.Address;
import io.bitsquare.p2p.P2PService;
import io.bitsquare.user.User;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableList;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Utils;
import java.util.ArrayList;
import java.util.Date;
class ArbitratorRegistrationViewModel extends ActivatableViewModel {
private final ArbitratorManager arbitratorManager;
private P2PService p2PService;
private final WalletService walletService;
private final KeyRing keyRing;
final BooleanProperty registrationEditDisabled = new SimpleBooleanProperty(true);
final BooleanProperty revokeButtonDisabled = new SimpleBooleanProperty(true);
final ObjectProperty<Arbitrator> myArbitratorProperty = new SimpleObjectProperty<>();
final ObservableList<String> languageCodes = FXCollections.observableArrayList(LanguageUtil.getDefaultLanguageLocaleAsCode());
final ObservableList<String> allLanguageCodes = FXCollections.observableArrayList(LanguageUtil.getAllLanguageCodes());
private boolean allDataValid;
private final MapChangeListener<Address, Arbitrator> arbitratorMapChangeListener;
private ECKey registrationKey;
StringProperty registrationPubKeyAsHex = new SimpleStringProperty();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public ArbitratorRegistrationViewModel(ArbitratorManager arbitratorManager,
User user,
P2PService p2PService,
WalletService walletService,
KeyRing keyRing) {
this.arbitratorManager = arbitratorManager;
this.p2PService = p2PService;
this.walletService = walletService;
this.keyRing = keyRing;
arbitratorMapChangeListener = new MapChangeListener<Address, Arbitrator>() {
@Override
public void onChanged(Change<? extends Address, ? extends Arbitrator> change) {
Arbitrator myRegisteredArbitrator = user.getRegisteredArbitrator();
myArbitratorProperty.set(myRegisteredArbitrator);
// We don't reset the languages in case of revokation, as its likely that the arbitrator will use the same again when he re-activate
// registration later
if (myRegisteredArbitrator != null)
languageCodes.setAll(myRegisteredArbitrator.getLanguageCodes());
updateDisableStates();
}
};
}
@Override
protected void activate() {
arbitratorManager.getArbitratorsObservableMap().addListener(arbitratorMapChangeListener);
updateDisableStates();
}
@Override
protected void deactivate() {
arbitratorManager.getArbitratorsObservableMap().removeListener(arbitratorMapChangeListener);
}
///////////////////////////////////////////////////////////////////////////////////////////
// UI actions
///////////////////////////////////////////////////////////////////////////////////////////
void onAddLanguage(String code) {
if (code != null && !languageCodes.contains(code))
languageCodes.add(code);
updateDisableStates();
}
void onRemoveLanguage(String code) {
if (code != null && languageCodes.contains(code))
languageCodes.remove(code);
updateDisableStates();
}
boolean setPrivKeyAndCheckPubKey(String privKeyString) {
ECKey _registrationKey = arbitratorManager.getRegistrationKey(privKeyString);
if (_registrationKey != null) {
String _registrationPubKeyAsHex = Utils.HEX.encode(_registrationKey.getPubKey());
boolean isKeyValid = arbitratorManager.isPublicKeyInList(_registrationPubKeyAsHex);
if (isKeyValid) {
registrationKey = _registrationKey;
registrationPubKeyAsHex.set(_registrationPubKeyAsHex);
}
updateDisableStates();
return isKeyValid;
} else {
updateDisableStates();
return false;
}
}
void onRegister(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
updateDisableStates();
if (allDataValid) {
AddressEntry arbitratorDepositAddressEntry = walletService.getArbitratorAddressEntry();
String registrationSignature = arbitratorManager.signStorageSignaturePubKey(registrationKey);
Arbitrator arbitrator = new Arbitrator(
p2PService.getAddress(),
arbitratorDepositAddressEntry.getPubKey(),
arbitratorDepositAddressEntry.getAddressString(),
keyRing.getPubKeyRing(),
new ArrayList<>(languageCodes),
new Date(),
registrationKey.getPubKey(),
registrationSignature
);
if (arbitrator != null) {
arbitratorManager.addArbitrator(arbitrator,
() -> {
updateDisableStates();
resultHandler.handleResult();
},
(errorMessage) -> {
updateDisableStates();
errorMessageHandler.handleErrorMessage(errorMessage);
});
}
}
}
void onRevoke(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
arbitratorManager.removeArbitrator(
() -> {
updateDisableStates();
resultHandler.handleResult();
},
(errorMessage) -> {
updateDisableStates();
errorMessageHandler.handleErrorMessage(errorMessage);
});
}
private void updateDisableStates() {
allDataValid = languageCodes != null && languageCodes.size() > 0 && registrationKey != null && registrationPubKeyAsHex.get() != null;
registrationEditDisabled.set(!allDataValid || myArbitratorProperty.get() != null);
revokeButtonDisabled.set(!allDataValid || myArbitratorProperty.get() == null);
}
}

View file

@ -0,0 +1,130 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.account.arbitratorregistration;
import io.bitsquare.app.BitsquareApp;
import io.bitsquare.gui.components.InputTextField;
import io.bitsquare.gui.popups.Popup;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import java.util.Optional;
public class EnterPrivKeyPopup extends Popup {
private Button unlockButton;
private InputTextField keyInputTextField;
private PrivKeyHandler privKeyHandler;
///////////////////////////////////////////////////////////////////////////////////////////
// Interface
///////////////////////////////////////////////////////////////////////////////////////////
public interface PrivKeyHandler {
boolean checkKey(String privKey);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public API
///////////////////////////////////////////////////////////////////////////////////////////
public EnterPrivKeyPopup() {
}
public EnterPrivKeyPopup show() {
if (gridPane != null) {
rowIndex = -1;
gridPane.getChildren().clear();
}
if (headLine == null)
headLine = "Registration open for invited arbitrators only";
createGridPane();
addHeadLine();
addInputFields();
addButtons();
createPopup();
return this;
}
public EnterPrivKeyPopup onClose(Runnable closeHandler) {
this.closeHandlerOptional = Optional.of(closeHandler);
return this;
}
public EnterPrivKeyPopup onKey(PrivKeyHandler privKeyHandler) {
this.privKeyHandler = privKeyHandler;
return this;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
private void addInputFields() {
Label label = new Label("Enter private key:");
label.setWrapText(true);
GridPane.setMargin(label, new Insets(3, 0, 0, 0));
GridPane.setRowIndex(label, ++rowIndex);
keyInputTextField = new InputTextField();
//TODO change when testing is done
if (BitsquareApp.DEV_MODE)
keyInputTextField.setText("6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a");
GridPane.setMargin(keyInputTextField, new Insets(3, 0, 0, 0));
GridPane.setRowIndex(keyInputTextField, rowIndex);
GridPane.setColumnIndex(keyInputTextField, 1);
keyInputTextField.textProperty().addListener((observable, oldValue, newValue) -> {
unlockButton.setDisable(newValue.length() == 0);
});
gridPane.getChildren().addAll(label, keyInputTextField);
}
private void addButtons() {
unlockButton = new Button("Unlock");
unlockButton.setDefaultButton(true);
unlockButton.setDisable(keyInputTextField.getText().length() == 0);
unlockButton.setOnAction(e -> {
if (privKeyHandler.checkKey(keyInputTextField.getText()))
hide();
else
new Popup().warning("The key you entered was not correct.").width(300).onClose(() -> blurAgain()).show();
});
Button cancelButton = new Button("Close");
cancelButton.setOnAction(event -> {
hide();
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
});
HBox hBox = new HBox();
hBox.setSpacing(10);
GridPane.setRowIndex(hBox, ++rowIndex);
GridPane.setColumnIndex(hBox, 1);
hBox.getChildren().addAll(unlockButton, cancelButton);
gridPane.getChildren().add(hBox);
}
}

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