// Path: src/main/java/io/coinswap/client/Currency.java
// public class Currency {
//     private static final Logger log = LoggerFactory.getLogger(Currency.class);
//     private static final File checkpointDir = new File("./checkpoints");
// 
//     private static final int MIN_BROADCAST_CONNECTIONS = 5;
//     private static final int CONNECTIONS = 8;
// 
//     protected NetworkParameters params;
//     protected File directory;
//     protected WalletAppKit wallet;
//     protected String name, id, symbol;
//     protected String[] pairs;
//     protected int index;
//     protected boolean hashlock; // whether or not this coin can be used on the Alice-side of a swap
//     protected int confirmationDepth;
//     protected List<InetSocketAddress> connectPeers;
// 
//     private boolean setup;
//     private SettableFuture<Object> setupFuture;
// 
//     public Currency(NetworkParameters params, File directory,
//                 String name, String id, String symbol, String[] pairs,
//                 int index, boolean hashlock, int confirmationDepth) {
// 
//         this.params = params;
//         this.directory = directory;
//         this.name = name;
//         this.id = id;
//         this.symbol = symbol;
//         this.pairs = pairs;
//         this.index = index;
//         this.hashlock = hashlock;
//         this.confirmationDepth = confirmationDepth;
//         this.connectPeers = new ArrayList<InetSocketAddress>(0);
// 
//         setupFuture = SettableFuture.create();
// 
//         // create the AltcoinJ wallet to interface with the currency
//         wallet = new WalletAppKit(params, directory, name.toLowerCase()) {
//             @Override
//             protected void onSetupCompleted() {
//                 makeBackup();
// 
//                 peerGroup().setMaxConnections(CONNECTIONS);
//                 peerGroup().setMinBroadcastConnections(1); // only require 1 peer in case we are connected to local peer
//                 peerGroup().setFastCatchupTimeSecs(wallet.wallet().getEarliestKeyCreationTime());
// 
//                 // remove the re-add the wallet to the peergroup, so we will broadcast waiting transactions with the
//                 // peergroup settings set correctly
//                 peerGroup().removeWallet(wallet());
//                 peerGroup().addWallet(wallet());
// 
//                 for(InetSocketAddress peer : connectPeers) {
//                     peerGroup().connectTo(peer);
//                 }
// 
//                 setup = true;
//                 setupFuture.set(null);
//             }
//         };
//         wallet.setUserAgent(Main.APP_NAME, Main.APP_VERSION);
//         wallet.setBlockingStartup(false);
// 
//         // load a checkpoint file (if it exists) to speed up initial blockchain sync
//         InputStream checkpointStream = Main.class.getResourceAsStream("/checkpoints/"+name.toLowerCase()+".txt");
//         if(checkpointStream != null) {
//             wallet.setCheckpoints(checkpointStream);
//         } else {
//             log.info("No checkpoints found for " + name);
//         }
//     }
// 
//     public void broadcastTransaction(final Transaction tx) {
//         wallet.wallet().receivePending(tx, null);
// 
//         // broadcast even if we only have 1 peer (in case we are connected to localhost peer)
//         wallet.peerGroup().broadcastTransaction(tx, 1);
//         // also wait until we have MIN_BROADCAST_CONNECTIONS, then rebroadcast
//         wallet.peerGroup().broadcastTransaction(tx, MIN_BROADCAST_CONNECTIONS);
//     }
// 
//     public void start() {
//         wallet.startAsync();
//         wallet.awaitRunning();
//     }
// 
//     public void stop() {
//         wallet.stopAsync();
//         wallet.awaitTerminated();
//     }
// 
//     public void addConnectPeers(List<InetSocketAddress> peers) {
//         checkNotNull(peers);
//         this.connectPeers.addAll(peers);
//     }
// 
//     private void makeBackup() {
//         File backupDir = new File(directory, "backup");
//         if(!backupDir.exists()) {
//             boolean success = backupDir.mkdir();
//             if(!success) throw new RuntimeException();
//         }
// 
//         File backup = new File(backupDir, name.toLowerCase()+".wallet");
//         if(!backup.exists()) {
//             try {
//                 wallet.wallet().saveToFile(backup);
//             } catch(IOException e) {
//                 throw new RuntimeException();
//             }
//         }
//     }
// 
//     public String getId() { return id; }
// 
//     public int getIndex() { return index; }
// 
//     public boolean supportsHashlock() { return hashlock; }
// 
//     public int getConfirmationDepth() { return confirmationDepth; }
// 
//     public String[] getPairs() { return pairs; }
// 
//     public boolean isSetup() { return setup; }
// 
//     public WalletAppKit getWallet() { return wallet; }
// 
//     public NetworkParameters getParams() { return params; }
// 
//     public ListenableFuture<Object> getSetupFuture() { return setupFuture; }
// }


import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import io.coinswap.client.Currency;
import io.mappum.altcoinj.core.*;
import io.mappum.altcoinj.crypto.TransactionSignature;
import io.mappum.altcoinj.script.Script;
import io.mappum.altcoinj.script.ScriptBuilder;
import io.mappum.altcoinj.utils.Threading;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Base64;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static io.mappum.altcoinj.script.ScriptOpCodes.OP_NOP;
package io.coinswap.swap;




public abstract class AtomicSwapController {
    public static final int VERSION = 0;

    protected final AtomicSwap swap;
// Path: src/main/java/io/coinswap/client/Currency.java
// public class Currency {
//     private static final Logger log = LoggerFactory.getLogger(Currency.class);
//     private static final File checkpointDir = new File("./checkpoints");
// 
//     private static final int MIN_BROADCAST_CONNECTIONS = 5;
//     private static final int CONNECTIONS = 8;
// 
//     protected NetworkParameters params;
//     protected File directory;
//     protected WalletAppKit wallet;
//     protected String name, id, symbol;
//     protected String[] pairs;
//     protected int index;
//     protected boolean hashlock; // whether or not this coin can be used on the Alice-side of a swap
//     protected int confirmationDepth;
//     protected List<InetSocketAddress> connectPeers;
// 
//     private boolean setup;
//     private SettableFuture<Object> setupFuture;
// 
//     public Currency(NetworkParameters params, File directory,
//                 String name, String id, String symbol, String[] pairs,
//                 int index, boolean hashlock, int confirmationDepth) {
// 
//         this.params = params;
//         this.directory = directory;
//         this.name = name;
//         this.id = id;
//         this.symbol = symbol;
//         this.pairs = pairs;
//         this.index = index;
//         this.hashlock = hashlock;
//         this.confirmationDepth = confirmationDepth;
//         this.connectPeers = new ArrayList<InetSocketAddress>(0);
// 
//         setupFuture = SettableFuture.create();
// 
//         // create the AltcoinJ wallet to interface with the currency
//         wallet = new WalletAppKit(params, directory, name.toLowerCase()) {
//             @Override
//             protected void onSetupCompleted() {
//                 makeBackup();
// 
//                 peerGroup().setMaxConnections(CONNECTIONS);
//                 peerGroup().setMinBroadcastConnections(1); // only require 1 peer in case we are connected to local peer
//                 peerGroup().setFastCatchupTimeSecs(wallet.wallet().getEarliestKeyCreationTime());
// 
//                 // remove the re-add the wallet to the peergroup, so we will broadcast waiting transactions with the
//                 // peergroup settings set correctly
//                 peerGroup().removeWallet(wallet());
//                 peerGroup().addWallet(wallet());
// 
//                 for(InetSocketAddress peer : connectPeers) {
//                     peerGroup().connectTo(peer);
//                 }
// 
//                 setup = true;
//                 setupFuture.set(null);
//             }
//         };
//         wallet.setUserAgent(Main.APP_NAME, Main.APP_VERSION);
//         wallet.setBlockingStartup(false);
// 
//         // load a checkpoint file (if it exists) to speed up initial blockchain sync
//         InputStream checkpointStream = Main.class.getResourceAsStream("/checkpoints/"+name.toLowerCase()+".txt");
//         if(checkpointStream != null) {
//             wallet.setCheckpoints(checkpointStream);
//         } else {
//             log.info("No checkpoints found for " + name);
//         }
//     }
// 
//     public void broadcastTransaction(final Transaction tx) {
//         wallet.wallet().receivePending(tx, null);
// 
//         // broadcast even if we only have 1 peer (in case we are connected to localhost peer)
//         wallet.peerGroup().broadcastTransaction(tx, 1);
//         // also wait until we have MIN_BROADCAST_CONNECTIONS, then rebroadcast
//         wallet.peerGroup().broadcastTransaction(tx, MIN_BROADCAST_CONNECTIONS);
//     }
// 
//     public void start() {
//         wallet.startAsync();
//         wallet.awaitRunning();
//     }
// 
//     public void stop() {
//         wallet.stopAsync();
//         wallet.awaitTerminated();
//     }
// 
//     public void addConnectPeers(List<InetSocketAddress> peers) {
//         checkNotNull(peers);
//         this.connectPeers.addAll(peers);
//     }
// 
//     private void makeBackup() {
//         File backupDir = new File(directory, "backup");
//         if(!backupDir.exists()) {
//             boolean success = backupDir.mkdir();
//             if(!success) throw new RuntimeException();
//         }
// 
//         File backup = new File(backupDir, name.toLowerCase()+".wallet");
//         if(!backup.exists()) {
//             try {
//                 wallet.wallet().saveToFile(backup);
//             } catch(IOException e) {
//                 throw new RuntimeException();
//             }
//         }
//     }
// 
//     public String getId() { return id; }
// 
//     public int getIndex() { return index; }
// 
//     public boolean supportsHashlock() { return hashlock; }
// 
//     public int getConfirmationDepth() { return confirmationDepth; }
// 
//     public String[] getPairs() { return pairs; }
// 
//     public boolean isSetup() { return setup; }
// 
//     public WalletAppKit getWallet() { return wallet; }
// 
//     public NetworkParameters getParams() { return params; }
// 
//     public ListenableFuture<Object> getSetupFuture() { return setupFuture; }
// }


// Path: src/main/java/io/coinswap/swap/AtomicSwapController.java
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import io.coinswap.client.Currency;
import io.mappum.altcoinj.core.*;
import io.mappum.altcoinj.crypto.TransactionSignature;
import io.mappum.altcoinj.script.Script;
import io.mappum.altcoinj.script.ScriptBuilder;
import io.mappum.altcoinj.utils.Threading;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Base64;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static io.mappum.altcoinj.script.ScriptOpCodes.OP_NOP;

package io.coinswap.swap;




public abstract class AtomicSwapController {
    public static final int VERSION = 0;

    protected final AtomicSwap swap;
    protected Currency[] currencies;