package io.emax.cosigner.ethereum.token.cli;
import io.emax.cosigner.api.currency.Wallet.Recipient;
import io.emax.cosigner.common.ByteUtilities;
import io.emax.cosigner.ethereum.core.EthereumResource;
import io.emax.cosigner.ethereum.core.gethrpc.EthereumRpc;
import io.emax.cosigner.ethereum.core.gethrpc.RawTransaction;
import io.emax.cosigner.ethereum.token.TokenConfiguration;
import io.emax.cosigner.ethereum.token.TokenMonitor;
import io.emax.cosigner.ethereum.token.TokenWallet;
import io.emax.cosigner.ethereum.token.gethrpc.tokencontract.TokenContract;
import io.emax.cosigner.ethereum.token.gethrpc.tokencontract.v1.TokenContractParametersV1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
/**
* Command line option for running the library.
*
* @author Tom
*/
public class Application {
/**
* Command line interface that provides basic access to wallet.
*
* @param args Commands, run with none to see usage.
* @throws InterruptedException Monitor and transaction usage requires time to load data, sleep
* throws this exception.
*/
public static void main(String[] args) throws InterruptedException, IOException {
if (args.length < 1) {
System.out.println("Usage: <interfaceMethod> <argument> <argument> ...");
System.out.println("Available methods:");
System.out.println("\tgetNewAddress(String accountName)");
System.out.println("\tgetDeterministicAddresses(String accountName)");
System.out
.println("\tgetMultiSigAddress(String address1, String address2, ..., accountName)");
System.out.println("\tgetBalance(String address)");
System.out.println("\tgetPendingBalance(String address)");
System.out.println("\tgetTotalBalances()");
System.out.println("\tcreateTransaction(String fromAddress1, String fromAddress2,"
+ " ..., String toAddress, Decimal amount)");
System.out.println("\tsignTransaction(String transaction, String address)");
System.out.println("\tsignTransactionWithKey(String transaction, String address)");
System.out.println("\tsendTransaction(String transaction)");
System.out.println("\tmonitor(String address)");
System.out.println("\tlistTxs(String address, int resultSize, int skipNumber)");
System.out.println("\tgetTx(String txid)");
System.out.println("\tgeneratePrivateKey()");
System.out.println("\tgenerateAddressFromKey(privateKey)");
System.out.println("\tgenerateTokens(String recipient, Long tokens)");
System.out.println("\tdestroyTokens(String sender, Long tokens)");
System.out.println("\tdeposit(String recipient, Long tokens)");
System.out.println("\treconcile(String affectedAddress, Long tokenChange)");
System.out.println("\tsetTokenContract()");
System.out.println("\tGenerateContracts(String currency, bool apply)");
return;
}
TokenConfiguration config = new TokenConfiguration("EUR");
TokenWallet wallet = new TokenWallet(config);
TokenMonitor monitor = new TokenMonitor(wallet);
String accountName = "";
String address = "";
String transaction = "";
LinkedList<String> addressList = new LinkedList<>();
BigDecimal amount = BigDecimal.ZERO;
Long longVal = 0L;
Boolean boolVal = false;
RawTransaction tx = null;
int resultSize = 0;
int skipNumber = 0;
switch (args[0]) {
case "getNewAddress":
if (args.length >= 2) {
accountName = args[1];
}
System.out.println(wallet.createAddress(accountName));
break;
case "getDeterministicAddresses":
if (args.length >= 2) {
accountName = args[1];
}
wallet.getAddresses(accountName).forEach(System.out::println);
break;
case "getMultiSigAddress":
if (args.length >= 2) {
accountName = args[args.length - 1];
}
addressList.addAll(Arrays.asList(args).subList(1, args.length - 1));
System.out.println(wallet.getMultiSigAddress(addressList, accountName));
break;
case "getBalance":
if (args.length >= 2) {
accountName = args[1];
}
System.out.println(wallet.getBalance(accountName));
break;
case "getPendingBalance":
if (args.length >= 2) {
accountName = args[1];
}
System.out.println(wallet.getPendingBalance(accountName));
break;
case "getTotalBalances":
System.out.println(wallet.getTotalBalances());
break;
case "createTransaction":
if (args.length >= 2) {
amount = new BigDecimal(args[args.length - 1]);
}
if (args.length >= 3) {
accountName = args[args.length - 2];
}
addressList.addAll(Arrays.asList(args).subList(1, args.length - 2));
Recipient recipient = new Recipient();
recipient.setAmount(amount);
recipient.setRecipientAddress(accountName);
System.out
.println(wallet.createTransaction(addressList, Collections.singletonList(recipient)));
break;
case "signTransaction":
if (args.length == 4) {
accountName = args[3];
}
if (args.length >= 3) {
address = args[2];
}
if (args.length >= 2) {
transaction = args[1];
}
if (args.length < 4) {
System.out.println(wallet.signTransaction(transaction, address));
} else {
System.out.println(wallet.signTransaction(transaction, address, accountName));
}
break;
case "signTransactionWithKey":
if (args.length >= 3) {
address = args[2];
}
if (args.length >= 2) {
transaction = args[1];
}
System.out.print("Private Key: ");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String key = reader.readLine();
System.out.println(wallet.signTransaction(transaction, address, key));
break;
case "sendTransaction":
if (args.length >= 2) {
transaction = args[1];
}
System.out.println(wallet.sendTransaction(transaction));
break;
case "monitor":
if (args.length >= 2) {
accountName = args[1];
}
System.out.println("*This is a testing function*");
System.out.println("*It will pause for several minutes to evaluate the network,"
+ " a full run can take 8+ minutes*");
System.out.println("Adding " + accountName + " to monitor...");
monitor.addAddresses(Collections.singletonList(accountName));
System.out.println("Initial values...");
monitor.getBalances().forEach(
(balanceAddress, balance) -> System.out.println(balanceAddress + ": " + balance));
System.out.println("2 minute sleep to load...");
Thread.sleep(1000 * 120L);
monitor.getBalances().forEach(
(balanceAddress, balance) -> System.out.println(balanceAddress + ": " + balance));
monitor.getObservableBalances().subscribe(balanceMap -> {
System.out.println("Observable updated:");
balanceMap.forEach(
(balanceAddress, balance) -> System.out.println(balanceAddress + ": " + balance));
});
System.out.println("60 second sleep...");
Thread.sleep(60 * 1000L);
System.out.println("60 second sleep...");
Thread.sleep(60 * 1000L);
System.out.println("60 second sleep...");
Thread.sleep(60 * 1000L);
System.out.println("60 second sleep...");
Thread.sleep(60 * 1000L);
System.out.println("60 second sleep...");
Thread.sleep(60 * 1000L);
System.out.println("60 second sleep...");
Thread.sleep(60 * 1000L);
break;
case "listTxs":
if (args.length >= 2) {
accountName = args[1];
}
if (args.length >= 3) {
resultSize = Integer.parseInt(args[2]);
}
if (args.length >= 4) {
skipNumber = Integer.parseInt(args[3]);
}
Arrays.asList(wallet.getTransactions(accountName, resultSize, skipNumber))
.forEach(System.out::println);
break;
case "getTx":
if (args.length >= 2) {
accountName = args[1];
}
System.out.println(wallet.getTransaction(accountName));
break;
case "generatePrivateKey":
System.out.println(wallet.generatePrivateKey());
break;
case "generateAddressFromKey":
if (args.length >= 2) {
accountName = args[1];
}
System.out.println(wallet.createAddressFromKey(accountName, true));
break;
case "generateTokens":
if (args.length >= 2) {
accountName = args[1];
}
if (args.length >= 3) {
longVal = new BigInteger(args[2]).longValue();
}
System.out.println(wallet.generateTokens(accountName, longVal));
break;
case "destroyTokens":
if (args.length >= 2) {
accountName = args[1];
}
if (args.length >= 3) {
longVal = new BigInteger(args[2]).longValue();
}
System.out.println(wallet.destroyTokens(accountName, longVal));
break;
case "deposit":
if (args.length >= 2) {
accountName = args[1];
}
if (args.length >= 3) {
longVal = new BigInteger(args[2]).longValue();
}
tx = RawTransaction.createTransaction(config, config.getTokenContractAddress(), null,
new TokenContract().getContractParameters()
.deposit(config, accountName, BigInteger.valueOf(longVal)));
System.out.println(ByteUtilities.toHexString(tx.encode()));
break;
case "reconcile":
if (args.length >= 2) {
accountName = args[1];
}
if (args.length >= 3) {
longVal = new BigInteger(args[2]).longValue();
}
HashMap<String, BigInteger> balanceChanges = new HashMap<>();
balanceChanges.put(accountName, BigInteger.valueOf(longVal));
System.out.println(wallet.reconcile(balanceChanges));
break;
case "setTokenContract":
TokenContractParametersV1 contractInterface = new TokenContractParametersV1();
EthereumRpc ethereumRpc = EthereumResource.getResource().getGethRpc();
Long nonce = contractInterface.getNonce(ethereumRpc, config.getAdminContractAddress());
tx = RawTransaction.createTransaction(config, config.getAdminContractAddress(), null,
contractInterface
.setTokenChild(nonce, config.getTokenContractAddress(), new LinkedList<>(),
new LinkedList<>(), new LinkedList<>()));
System.out.println(ByteUtilities.toHexString(tx.encode()));
break;
case "GenerateContracts":
if (args.length >= 2) {
accountName = args[1];
}
boolVal = false;
if (args.length >= 3) {
boolVal = Boolean.valueOf(args[2]);
}
config = new TokenConfiguration(accountName);
wallet = new TokenWallet(config);
config.generateNewContract(boolVal);
wallet.setupTokenContract();
break;
default:
System.out.println("Method not valid or not supported yet");
}
}
}