forked from syvb/nimiq-tip-bot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
261 lines (252 loc) · 11.9 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
const logger = require("winston");
logger.info("Starting...");
const Nimiq = require("/usr/share/nimiq/app/lib/node.js");
const Buffer = require("buffer").Buffer;
const MnemonicPhrase = require("./phrases.js");
const AddressFinder = require("./getAddress.js");
const DiscordAuth = require("./discordAuth.json");
const Discord = require("discord.js");
const fs = require("fs");
var db = JSON.parse(fs.readFileSync("./db.json", "utf8"));
async function main() {
logger.remove(logger.transports.Console);
logger.add(logger.transports.Console, {
colorize: true
});
logger.level = "debug";
logger.verbose("Logging system ready.");
function saveDB(cb) {
fs.writeFile("db.json", JSON.stringify(db), function (err) {
if (err) throw err;
if (cb) cb();
});
}
if (!db.keyPairs) db.keyPairs = {};
if (!db.lastUserVerifies) db.lastUserVerifies = {};
if (!db.lastUserVerifies) db.lastUserVerifies = {};
if (!db.txFeeBalance) db.txFeeBalance = 76543;
Nimiq.GenesisConfig.main();
const privateKey = Buffer.from(MnemonicPhrase.mnemonicToKey(require("./privateKey.js")), "hex");
const key = new Nimiq.PrivateKey(privateKey);
const keyPair = Nimiq.KeyPair.derive(key);
const wallet = new Nimiq.Wallet(keyPair);
logger.verbose("Loaded private key.");
const consensus = await Nimiq.Consensus.light();
consensus.network.connect();
async function sendTo(address, amount) {
db.txFeeBalance -= 140;
saveDB();
logger.debug("Sent NIM to " + address)
var transaction = wallet.createTransaction(address, amount ? amount : 20000, 140, consensus.blockchain.head.height);
await consensus.mempool.pushTransaction(transaction);
}
consensus.on("established", async () => {
logger.verbose("Consensus established");
const bot = new Discord.Client();
var historyChannel;
bot.on("ready", function (evt) {
logger.info("Logged in to Discord.");
historyChannel = bot.channels.get("443512282664927233");
});
bot.on("message", async function (msg) {
if (db.blacklist.indexOf(msg.author.id) > -1) {
console.log("On blacklist, ", msg.author.id);
return;
}
logger.silly("Got message, " + msg.content);
var address = AddressFinder(msg.content);
msg.content = msg.content.toLowerCase();
if (msg.content.indexOf("!help") === 0) {
return msg.reply(`
Commands:
—
!tip nimiq address [tip amount]
Sends NIM, on chain, to that address. If you don't specify a tip amount, it defaults to 0.2 NIM.
—
!tip @discord_username [tip amount]
Sends NIM to that user’s tip balance, off-chain. If you don't specify a tip amount, it defaults to 0.2 NIM.
—
!balance
Shows you your tip balance
—
!withdraw nimiq address
Sends your entire tip balance to that address, on-chain.
—
!deposit
Gives you instructions on how to deposit.
—
You can send the commands by DMing <@441329117946707978>, or in any Discord server that has the bot on it.
This is a community run bot. It is not associated with the Nimiq Foundation, or the Nimiq Team. If you have any feedback, or questions, direct it to <@384847091924729856>, or post it in the bot's Discord server (<https://discord.gg/KFc8gK2>).
Need help? Contact <@384847091924729856>. Or, check out the #support channel in the example server - <https://discord.gg/KFc8gK2>.
`);
}
if (msg.content.indexOf("!balance") === 0) {
if (db.userBalances[msg.author.id]) {
return msg.reply("Your balance is " + parseFloat((db.userBalances[msg.author.id] / 100000).toFixed(5), 10) + " NIM.");
} else {
return msg.reply("You have no balance.");
}
return;
}
if (msg.content.indexOf("!txfeeinfo") === 0) {
return msg.reply("I have enough NIM to pay for " + Math.floor(db.txFeeBalance / 140) + " transactions.");
}
if (msg.content.indexOf("!withdraw") === 0) {
if (address) {
logger.debug("Parsed address, " + address);
if (db.txFeeBalance < 140) {
return msg.reply("Sorry, something very bad happened. I can't afford the transaction fee. Please try again, later.");
}
try {
const hexAddess = Nimiq.Address.fromUserFriendlyAddress(address.toUpperCase());
await sendTo(hexAddess, Math.floor(db.userBalances[msg.author.id]));
var sentAmount = Math.floor(db.userBalances[msg.author.id]);
db.userBalances[msg.author.id] = 0;
saveDB();
msg.reply("You have sent your balance to that address.");
if (msg.channel.type !== "dm") {
historyChannel.send("@" + msg.author.username + " tipped " + address.toUpperCase() + " " + (sentAmount * 100000) + " NIM.");
}
} catch (e) {console.log(e);}
}
return;
}
if (msg.content.indexOf("!deposit") === 0) {
if ((msg.content.indexOf("!depositforce") !== 0) && (msg.channel.type !== "dm")) {
return msg.reply("Deposits are not possible on a server for privacy and security reasons. To add funds to your account, please Direct Message me with !deposit.");
}
var keyPair = Nimiq.KeyPair.generate();
var walletAddress = Nimiq.Address.fromHash(keyPair.publicKey.hash()).toUserFriendlyAddress();
var verifyCode = (Date.now() - 1525605947934).toString(36) //Milliseconds since I wrote this line, in base36
+ Math.random().toString(36).split("0.")[1]; //A random number, in base36
db.keyPairs[verifyCode] = {
privateKey: keyPair.privateKey.toHex(),
user: msg.author.id,
used: false
};
db.lastUserVerifies[msg.author.id] = verifyCode;
saveDB();
msg.reply(
`**THIS IS A TIPBOT, NOT A WALLET!**
It is recommended **not to store large amounts of NIM** on this bot! You don't control the private key of your funds and they may be lost! If you wish to continue, send your NIM to`
);
msg.channel.send("``" + Nimiq.Address.fromHash(keyPair.publicKey.hash()).toUserFriendlyAddress() + "``"); +
msg.channel.send("After your funds have arrived (when the transaction is no longer \"pending\" in the safe), run");
msg.channel.send("``" + "!verify " + verifyCode + "``");
return;
}
if (msg.content.indexOf("!verify") === 0) {
msg.content = msg.content.trim();
var publicKey = msg.content.split("!verify")[1].trim();
if (!db.keyPairs[publicKey]) {
if (db.lastUserVerifies[msg.author.id]) {
if (publicKey === "") {
publicKey = db.lastUserVerifies[msg.author.id];
} else {
msg.reply("Sorry, it doesn't look like that !verify code exists. Did you mean: ");
return msg.channel.send("!verify " + db.lastUserVerifies[msg.author.id]);
}
} else {
return msg.reply("Sorry, it doesn't look like that !verify code exists. I also can't find any verifies in your history.");
}
}
var walletInfo = db.keyPairs[publicKey];
if (walletInfo.user !== msg.author.id) {
return msg.reply("Sorry, that address cannot be used by you.");
}
if (walletInfo.used) {
return msg.reply("Sorry, addresses can only be used once. However, you can message support (<@384847091924729856>), to have this resolved.");
}
var userKey = new Nimiq.PrivateKey(Buffer.from(walletInfo.privateKey, "hex"));
var userKeyPair = Nimiq.KeyPair.derive(userKey);
var userWallet = new Nimiq.Wallet(userKeyPair);
//console.log(Nimiq.Address.fromHash(userKeyPair.publicKey).toUserFriendlyAddress())
var balance = (await consensus.blockchain.accounts.get(userWallet.address)).balance;
console.log(balance + "!");
if (balance === 0) {
return msg.reply("No NIM was sent to that address.");
}
if (!db.userBalances[walletInfo.user]) db.userBalances[walletInfo.user] = 0;
db.userBalances[walletInfo.user] += balance;
db.keyPairs[publicKey].used = true;
db.lastUserVerifies[msg.author.id] = null;
//We don't need a transaction fee, because this will be this wallet's only transfer, ever.
var transaction = userWallet.createTransaction(wallet.address, balance, 0, consensus.blockchain.head.height);
await consensus.mempool.pushTransaction(transaction);
msg.reply("It worked! " + parseFloat((balance / 100000).toFixed(5), 10) + " NIM has been credited to your account. **DO NOT** reuse this address. Instead, request a new one with !deposit, if you want to deposit more.");
saveDB();
return;
}
if (msg.content.indexOf("!tip") !== 0) {
return;
}
var amountToSend = 20000;
try {
amountToSend = msg.content.match(/(\d|\.)*$/)[0].trim();
}
catch (e) {}
var dots = msg.content.match(/\./);
console.log(amountToSend);
if (dots && (dots.length > 2)) {
return msg.reply("I don't understand that number.");
}
if (amountToSend === "") {
amountToSend = 20000;
} else {
amountToSend = parseFloat(amountToSend, 10) * 100000;
}
amountToSend = Math.floor(amountToSend);
if (amountToSend === 0) {
msg.reply("You cannot send 0 NIM.");
return;
}
if (!db.userBalances[msg.author.id] || (db.userBalances[msg.author.id] < amountToSend)) {
return msg.reply("Sorry, you don't have enough balance with this tip-bot, to make that tip.");
}
console.log(msg.channel.type);
if (address) {
logger.debug("Parsed address, " + address);
try {
if (db.txFeeBalance < 140) {
return msg.reply("Sorry, something very bad happened. I can't afford the transaction fee. Please try again, later.");
}
const hexAddess = Nimiq.Address.fromUserFriendlyAddress(address.toUpperCase());
await sendTo(hexAddess, amountToSend);
db.userBalances[msg.author.id] -= amountToSend;
saveDB();
msg.channel.send("<@" + msg.author.id + "> tipped " + parseFloat((amountToSend / 100000).toFixed(5), 10) + " NIM to that address.");
if (msg.channel.type !== "dm") {
historyChannel.send("@" + msg.author.username + " tipped " + address.toUpperCase() + " " + parseFloat((amountToSend / 100000).toFixed(5), 10) + " NIM.");
}
} catch (e) {}
} else {
try {
var sendToUser = msg.content.match(/<@!?(\d*)>/)[1];
if ((sendToUser === "441329117946707978") || (sendToUser === "1")) {
db.txFeeBalance += amountToSend;
saveDB();
msg.reply("Adding that to the transaction fee paying pool. Because you tipped me, I'll use your funds to pay for transaction fees.");
}
db.userBalances[msg.author.id] -= amountToSend;
if (!db.userBalances[sendToUser]) db.userBalances[sendToUser] = 0;
db.userBalances[sendToUser] += amountToSend;
var sendToDUser = bot.users.get(sendToUser);
saveDB();
msg.channel.send("<@" + msg.author.id + "> tipped @" + sendToDUser.username + " " + parseFloat((amountToSend / 100000).toFixed(5), 10) + " NIM.");
if (msg.channel.type === "dm") {
sendToDUser.send("You got tipped " + parseFloat((amountToSend / 100000).toFixed(5)) + " NIM by " + bot.users.get(msg.author.id).username + ".");
} else {
setTimeout(function () {
historyChannel.send("@" + msg.author.username + " tipped @" + sendToDUser.username + " " + parseFloat((amountToSend / 100000).toFixed(5)) + " NIM.");
}, 7500);
}
} catch (e) {console.log("werid", e)}
}
});
bot.on("error", function (a) {logger.error("Discord error, ", a.toString());});
bot.login(DiscordAuth.token);
logger.info("Discord bot configured.");
});
Nimiq.Log.instance.level = 4;
}
main();