mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-05-20 15:30:36 -04:00
add missing files
This commit is contained in:
parent
c6ece486ed
commit
9ef8b42509
239 changed files with 20558 additions and 51 deletions
|
@ -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
28
common/pom.xml
Normal 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>
|
65
common/src/main/java/io/bitsquare/app/AppModule.java
Normal file
65
common/src/main/java/io/bitsquare/app/AppModule.java
Normal 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) {
|
||||||
|
}
|
||||||
|
}
|
19
common/src/main/java/io/bitsquare/app/ProgramArguments.java
Normal file
19
common/src/main/java/io/bitsquare/app/ProgramArguments.java
Normal 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);
|
||||||
|
}
|
45
common/src/main/java/io/bitsquare/app/Version.java
Normal file
45
common/src/main/java/io/bitsquare/app/Version.java
Normal 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;
|
||||||
|
|
||||||
|
}
|
81
common/src/main/java/io/bitsquare/common/ByteArrayUtils.java
Normal file
81
common/src/main/java/io/bitsquare/common/ByteArrayUtils.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
38
common/src/main/java/io/bitsquare/common/UserThread.java
Normal file
38
common/src/main/java/io/bitsquare/common/UserThread.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
34
common/src/main/java/io/bitsquare/common/util/Profiler.java
Normal file
34
common/src/main/java/io/bitsquare/common/util/Profiler.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
47
common/src/main/java/io/bitsquare/common/util/Tuple2.java
Normal file
47
common/src/main/java/io/bitsquare/common/util/Tuple2.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
51
common/src/main/java/io/bitsquare/common/util/Tuple3.java
Normal file
51
common/src/main/java/io/bitsquare/common/util/Tuple3.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
84
core/src/main/java/io/bitsquare/alert/Alert.java
Normal file
84
core/src/main/java/io/bitsquare/alert/Alert.java
Normal 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() + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
144
core/src/main/java/io/bitsquare/alert/AlertManager.java
Normal file
144
core/src/main/java/io/bitsquare/alert/AlertManager.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
core/src/main/java/io/bitsquare/alert/AlertModule.java
Normal file
38
core/src/main/java/io/bitsquare/alert/AlertModule.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
71
core/src/main/java/io/bitsquare/alert/AlertService.java
Normal file
71
core/src/main/java/io/bitsquare/alert/AlertService.java
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
354
core/src/main/java/io/bitsquare/arbitration/Dispute.java
Normal file
354
core/src/main/java/io/bitsquare/arbitration/Dispute.java
Normal 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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
93
core/src/main/java/io/bitsquare/arbitration/DisputeList.java
Normal file
93
core/src/main/java/io/bitsquare/arbitration/DisputeList.java
Normal 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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
608
core/src/main/java/io/bitsquare/arbitration/DisputeManager.java
Normal file
608
core/src/main/java/io/bitsquare/arbitration/DisputeManager.java
Normal 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
265
core/src/main/java/io/bitsquare/arbitration/DisputeResult.java
Normal file
265
core/src/main/java/io/bitsquare/arbitration/DisputeResult.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
59
core/src/main/java/io/bitsquare/btc/data/RawInput.java
Normal file
59
core/src/main/java/io/bitsquare/btc/data/RawInput.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
36
core/src/main/java/io/bitsquare/locale/CryptoCurrency.java
Normal file
36
core/src/main/java/io/bitsquare/locale/CryptoCurrency.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
54
core/src/main/java/io/bitsquare/locale/FiatCurrency.java
Normal file
54
core/src/main/java/io/bitsquare/locale/FiatCurrency.java
Normal 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 + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
89
core/src/main/java/io/bitsquare/locale/TradeCurrency.java
Normal file
89
core/src/main/java/io/bitsquare/locale/TradeCurrency.java
Normal 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 + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
43
core/src/main/java/io/bitsquare/payment/AliPayAccount.java
Normal file
43
core/src/main/java/io/bitsquare/payment/AliPayAccount.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
46
core/src/main/java/io/bitsquare/payment/OKPayAccount.java
Normal file
46
core/src/main/java/io/bitsquare/payment/OKPayAccount.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
168
core/src/main/java/io/bitsquare/payment/PaymentAccount.java
Normal file
168
core/src/main/java/io/bitsquare/payment/PaymentAccount.java
Normal 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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
144
core/src/main/java/io/bitsquare/payment/PaymentMethod.java
Normal file
144
core/src/main/java/io/bitsquare/payment/PaymentMethod.java
Normal 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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
core/src/main/java/io/bitsquare/payment/SepaAccount.java
Normal file
71
core/src/main/java/io/bitsquare/payment/SepaAccount.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
51
core/src/main/java/io/bitsquare/payment/SwishAccount.java
Normal file
51
core/src/main/java/io/bitsquare/payment/SwishAccount.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
core/src/main/java/io/bitsquare/user/BlockChainExplorer.java
Normal file
41
core/src/main/java/io/bitsquare/user/BlockChainExplorer.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
27
core/src/main/java/io/bitsquare/user/PopupId.java
Normal file
27
core/src/main/java/io/bitsquare/user/PopupId.java
Normal 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";
|
||||||
|
|
||||||
|
}
|
63
core/src/main/resources/logback.xml
Normal file
63
core/src/main/resources/logback.xml
Normal 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>
|
|
@ -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() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -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() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue