@@ -168,11 +168,12 @@ public class DeroWallet implements IWallet | |||
public Tx.InPayment getTransferByHash(String txHash) throws RequestException | |||
{ | |||
JSONObject json = request(json("get_transfer_by_txid", new MapBuilder<String, Object>().put("txid", txHash).get())); | |||
if (!json.has("payments")) { | |||
return null; | |||
} | |||
JSONObject result = json.getJSONObject("payments"); | |||
System.out.println("PAYMENTS: " + result.toString()); | |||
return new Tx.InPayment(result.getInt("block_height"), result.getString("tx_hash"), Helper.toBigDecimal(result.getBigInteger("amount"), SCALE), (byte) result.getInt("unlock_time"), result.getString("payment_id")); | |||
} | |||
@@ -130,6 +130,16 @@ public class ArangoDatabaseService | |||
return doc.getUnconfirmedBalance(); | |||
} | |||
public User getUser(String userId) | |||
{ | |||
return users.getDocument(userId, User.class); | |||
} | |||
public void updateUser(User user) | |||
{ | |||
users.updateDocument(user.getKey(), user); | |||
} | |||
public String getAddress(String key) | |||
{ | |||
@@ -243,6 +253,22 @@ public class ArangoDatabaseService | |||
public boolean existTx(String txHash) | |||
{ | |||
//return first("FOR tx IN txs FILTER tx._key == @hash LIMIT 1 RETURN tx._key", String.class, new MapBuilder<String, Object>().put("hash", txHash).get()) != null; | |||
return txs.documentExists(txHash); | |||
} | |||
public Transaction getTx(String txHash) | |||
{ | |||
return txs.getDocument(txHash, Transaction.class); | |||
} | |||
public String getUserIdFromPaymentId(String paymentId) | |||
{ | |||
return first("FOR u IN users FILTER u.paymentId == @paymentId LIMIT 1 RETURN u._key", String.class, new MapBuilder<String, Object>().put("paymentId", paymentId).get()); | |||
} | |||
public boolean hasWithdrawAddress(String userId) | |||
{ | |||
return first("RETURN DOCUMENT(CONCAT('users/', @userId).withdrawAddress != null", boolean.class, new MapBuilder<String, Object>().put("userId", userId).get()); | |||
} | |||
} |
@@ -21,10 +21,13 @@ import com.google.inject.Singleton; | |||
import fr.slixe.dero4j.Daemon; | |||
import fr.slixe.tipbot.command.BalanceCommand; | |||
import fr.slixe.tipbot.command.CommandException; | |||
import fr.slixe.tipbot.command.DepositCommand; | |||
import fr.slixe.tipbot.command.HelpCommand; | |||
import fr.slixe.tipbot.command.InfoCommand; | |||
import fr.slixe.tipbot.command.TipCommand; | |||
import fr.slixe.tipbot.command.WithdrawAddressCommand; | |||
import fr.slixe.tipbot.command.WithdrawCommand; | |||
import fr.slixe.tipbot.command.WithdrawMaxCommand; | |||
import fr.slixe.tipbot.task.VerifyTask; | |||
import fr.slixe.tipbot.task.WalletTask; | |||
import net.dv8tion.jda.core.entities.MessageEmbed; | |||
@@ -32,7 +35,7 @@ import net.dv8tion.jda.core.entities.PrivateChannel; | |||
@Singleton | |||
@Include(commands = { TipCommand.class, BalanceCommand.class, WithdrawCommand.class, InfoCommand.class, | |||
HelpCommand.class }) | |||
HelpCommand.class, WithdrawMaxCommand.class, DepositCommand.class, WithdrawAddressCommand.class }) | |||
@org.krobot.Bot(author = "Slixe", name = "Dero TipBot", version = "0.0.1") | |||
public class TipBot extends KrobotModule { | |||
@@ -12,6 +12,7 @@ public class User | |||
private String paymentId; | |||
private BigDecimal balance; | |||
private BigDecimal unconfirmedBalance; | |||
private String withdrawAddress; | |||
public User() {} | |||
@@ -84,4 +85,14 @@ public class User | |||
{ | |||
this.unconfirmedBalance = balance; | |||
} | |||
public String getWithdrawAddress() | |||
{ | |||
return this.withdrawAddress; | |||
} | |||
public void setWithdrawAddress(String withdrawAddress) | |||
{ | |||
this.withdrawAddress = withdrawAddress; | |||
} | |||
} |
@@ -47,7 +47,7 @@ public class Wallet { | |||
log.info("Trying to start DERO Wallet..."); | |||
String path = this.config.at("wallet.launchPath"); | |||
File walletFile = new File(path); | |||
if (!walletFile.exists()) | |||
{ | |||
log.error(String.format("Error! Please verify your config, wallet file not found at '%s'.", path)); | |||
@@ -1,5 +1,7 @@ | |||
package fr.slixe.tipbot.command; | |||
import java.math.BigDecimal; | |||
import org.krobot.MessageContext; | |||
import org.krobot.command.ArgumentMap; | |||
import org.krobot.command.Command; | |||
@@ -8,6 +10,7 @@ import org.krobot.command.CommandHandler; | |||
import com.google.inject.Inject; | |||
import fr.slixe.tipbot.TipBot; | |||
import fr.slixe.tipbot.User; | |||
import fr.slixe.tipbot.Wallet; | |||
import net.dv8tion.jda.core.entities.MessageChannel; | |||
import net.dv8tion.jda.core.entities.PrivateChannel; | |||
@@ -25,8 +28,10 @@ public class BalanceCommand implements CommandHandler { | |||
public Object handle(MessageContext ctx, ArgumentMap args) throws Exception | |||
{ | |||
String id = ctx.getUser().getId(); | |||
String funds = wallet.getFunds(id).toString(); | |||
String unconfirmedFunds = wallet.getUnconfirmedFunds(id).toString(); | |||
User user = wallet.getDB().getUser(id); | |||
BigDecimal funds = user.getBalance(); | |||
BigDecimal unconfirmedFunds = user.getUnconfirmedBalance(); | |||
MessageChannel chan = ctx.getChannel(); | |||
@@ -34,14 +39,20 @@ public class BalanceCommand implements CommandHandler { | |||
{ | |||
chan = ctx.getUser().openPrivateChannel().complete(); | |||
} | |||
if (funds.equals("0") || funds.equals("0E-12")) //dirty i know :/ | |||
/*if (funds.equals("0") || funds.equals("0E-12")) //dirty i know :/ | |||
funds = "0.000000000000"; | |||
if (unconfirmedFunds.equals("0") || unconfirmedFunds.equals("0E-12")) | |||
unconfirmedFunds = "0.000000000000"; | |||
unconfirmedFunds = "0.000000000000";*/ | |||
String address = wallet.getAddress(id); | |||
if (user.getWithdrawAddress() == null) | |||
address = "No deposit address until you've set a withdraw address."; | |||
chan.sendMessage(bot.dialog("Balance", String.format(bot.getMessage("balance"), funds, unconfirmedFunds, address))).queue(); | |||
chan.sendMessage(bot.dialog("Balance", String.format(bot.getMessage("balance"), funds, unconfirmedFunds, wallet.getAddress(id)))).queue(); | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,74 @@ | |||
package fr.slixe.tipbot.command; | |||
import org.krobot.MessageContext; | |||
import org.krobot.command.ArgumentMap; | |||
import org.krobot.command.Command; | |||
import org.krobot.command.CommandHandler; | |||
import com.google.inject.Inject; | |||
import fr.slixe.dero4j.structure.Tx.InPayment; | |||
import fr.slixe.tipbot.TipBot; | |||
import fr.slixe.tipbot.Transaction; | |||
import fr.slixe.tipbot.Wallet; | |||
import net.dv8tion.jda.core.entities.MessageChannel; | |||
import net.dv8tion.jda.core.entities.PrivateChannel; | |||
@Command(value = "deposit <txhash>", desc = "search your deposit", errorMP = true) | |||
public class DepositCommand implements CommandHandler { | |||
@Inject | |||
private Wallet wallet; | |||
@Inject | |||
private TipBot bot; | |||
@Override | |||
public Object handle(MessageContext ctx, ArgumentMap args) throws Exception | |||
{ | |||
MessageChannel chan = ctx.getChannel(); | |||
if (!(chan instanceof PrivateChannel)) | |||
{ | |||
chan = ctx.getUser().openPrivateChannel().complete(); | |||
} | |||
String txHash = args.get("txhash"); | |||
Transaction tx; | |||
StringBuilder builder = new StringBuilder(); | |||
if (wallet.getDB().existTx(txHash)) | |||
{ | |||
tx = wallet.getDB().getTx(txHash); | |||
builder.append("Transaction already exists.").append("\n\n"); | |||
} | |||
else | |||
{ | |||
InPayment payment = wallet.getApi().getTransferByHash(txHash); | |||
if (payment == null) | |||
{ | |||
throw new CommandException("This transaction hash does not exist!"); | |||
} | |||
String userId = wallet.getDB().getUserIdFromPaymentId(payment.getPaymentId()); | |||
tx = new Transaction(payment.getTxHash(), userId, payment.getBlockHeight(), payment.getAmount()); | |||
wallet.getDB().addTx(tx); | |||
wallet.addUnconfirmedFunds(userId, tx.getAmount()); | |||
builder.append("Transaction was added.").append("\n\n"); | |||
} | |||
builder.append("**Tx Hash:** ").append(tx.getHash()).append("\n"); | |||
builder.append("**Block Height:** ").append(tx.getBlockHeight()).append("\n"); | |||
builder.append("**Amount:** ").append(tx.getAmount()).append("\n"); | |||
builder.append("**Confirmations:** ").append(tx.getConfirmations()).append("\n"); | |||
chan.sendMessage(bot.dialog("Deposit", builder.toString())).queue(); | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,49 @@ | |||
package fr.slixe.tipbot.command; | |||
import org.krobot.MessageContext; | |||
import org.krobot.command.ArgumentMap; | |||
import org.krobot.command.Command; | |||
import org.krobot.command.CommandHandler; | |||
import com.google.inject.Inject; | |||
import fr.slixe.tipbot.ArangoDatabaseService; | |||
import fr.slixe.tipbot.TipBot; | |||
import fr.slixe.tipbot.User; | |||
import net.dv8tion.jda.core.entities.MessageChannel; | |||
import net.dv8tion.jda.core.entities.PrivateChannel; | |||
@Command(value = "withdraw-address <address>", desc = "set your default withdraw address", errorMP = true) | |||
public class WithdrawAddressCommand implements CommandHandler { | |||
@Inject | |||
private TipBot bot; | |||
@Inject | |||
private ArangoDatabaseService db; | |||
@Override | |||
public Object handle(MessageContext ctx, ArgumentMap args) throws Exception | |||
{ | |||
MessageChannel chan = ctx.getChannel(); | |||
if (!(chan instanceof PrivateChannel)) | |||
{ | |||
chan = ctx.getUser().openPrivateChannel().complete(); | |||
} | |||
String address = args.get("address"); | |||
//TODO verify validity of address | |||
//TODO update it directly | |||
User user = db.getUser(ctx.getUser().getId()); | |||
user.setWithdrawAddress(address); | |||
db.updateUser(user); | |||
chan.sendMessage(bot.dialog("Withdraw Address", "Your withdrawal address has been set!")).queue(); | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,72 @@ | |||
package fr.slixe.tipbot.command; | |||
import java.math.BigDecimal; | |||
import org.krobot.MessageContext; | |||
import org.krobot.command.ArgumentMap; | |||
import org.krobot.command.Command; | |||
import org.krobot.command.CommandHandler; | |||
import com.google.inject.Inject; | |||
import fr.slixe.dero4j.RequestException; | |||
import fr.slixe.tipbot.TipBot; | |||
import fr.slixe.tipbot.Wallet; | |||
import net.dv8tion.jda.core.entities.MessageChannel; | |||
import net.dv8tion.jda.core.entities.PrivateChannel; | |||
@Command(value = "withdraw-max <address>", desc = "withdraw all your coins", errorMP = true) | |||
public class WithdrawMaxCommand implements CommandHandler { | |||
@Inject | |||
private Wallet wallet; | |||
@Inject | |||
private TipBot bot; | |||
@Override | |||
public Object handle(MessageContext ctx, ArgumentMap args) throws Exception | |||
{ | |||
MessageChannel chan = ctx.getChannel(); | |||
if (!(chan instanceof PrivateChannel)) | |||
{ | |||
chan = ctx.getUser().openPrivateChannel().complete(); | |||
} | |||
String address = args.get("address"); | |||
String id = ctx.getUser().getId(); | |||
BigDecimal amount = wallet.getFunds(id); | |||
BigDecimal fee; | |||
try { | |||
fee = wallet.getApi().estimateFee(address, amount); | |||
} catch (RequestException e) | |||
{ | |||
e.printStackTrace(); | |||
throw new CommandException(e.getMessage()); | |||
} | |||
BigDecimal amountWithoutFee = amount.subtract(fee); | |||
if (amountWithoutFee.signum() != 1) | |||
{ | |||
throw new CommandException("Not enough funds!"); | |||
} | |||
String tx; | |||
try { | |||
tx = wallet.getApi().transfer(address, amountWithoutFee); | |||
} catch (RequestException e) { | |||
e.printStackTrace(); | |||
throw new CommandException(bot.getMessage("withdraw.err.transfer")); | |||
} | |||
wallet.removeFunds(id, amount); | |||
chan.sendMessage(bot.dialog("Withdraw", String.format("You've withdrawn %s **DERO** to:\n%s\n\n__**Tx hash**__:\n%s\n\n__**Fee**__: %s", amountWithoutFee, address, tx, fee))).queue(); | |||
return null; | |||
} | |||
} |
@@ -34,9 +34,12 @@ public class VerifyTask extends TimerTask { | |||
List<Transaction> txs = wallet.getDB().getUnconfirmedTxs(); | |||
log.info(String.format("%d unconfirmed transactions!", txs.size())); | |||
for (Transaction tx : txs) | |||
{ | |||
int diff = (int) (blockHeight - tx.getBlockHeight()); | |||
diff = diff > 20 ? 20 : diff; | |||
try { | |||
@@ -58,7 +61,7 @@ public class VerifyTask extends TimerTask { | |||
log.error(e.getMessage()); | |||
continue; | |||
} | |||
this.wallet.getDB().updateTx(tx.getHash(), diff); | |||
} | |||
} | |||