-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
336 lines (327 loc) · 15.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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
const logger = require("winston");
logger.info("Starting...");
//const Nimiq = require("../faucet/nimiq-faucet/server/nimiq/lib/node.js");
const Nimiq = require("@nimiq/core");
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");
const fetch = require("node-fetch");
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.");
var savingDB = false;
function saveDB(cb) {
if (savingDB) return;
savingDB = true;
fs.writeFile("db.json", JSON.stringify(db), function (err) {
savingDB = false;
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.nano();
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.relayTransaction(transaction);
}
var ready = false;
consensus.on("established", async () => {
logger.verbose("Consensus established");
const bot = new Discord.Client({ partials: ["CHANNEL"], disableMentions: "everyone", intents: ["GUILDS", "GUILD_WEBHOOKS", "GUILD_MESSAGES", "GUILD_MESSAGE_REACTIONS", "DIRECT_MESSAGES", "GUILD_MESSAGE_TYPING", "DIRECT_MESSAGE_TYPING", 1 << 15, 1 << 12, 1 << 9] });
var historyChannel;
bot.on("ready", function (evt) {
logger.info("Logged in to Discord.");
historyChannel = bot.channels.cache.get("443512282664927233");
});
if (ready) return;
ready = true;
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);
if (msg.content.indexOf("!") === 0) console.log("got msg", msg.content);
var address = AddressFinder(msg.content);
msg.content = msg.content.toLowerCase();
if (msg.content.indexOf("!github") === 0) {
return msg.reply(`Visit our GitHub page to contribute: https://github.com/Smittyvb/nimiq-tip-bot
`);
}
if (msg.content.indexOf("!help") === 0) {
return msg.author.send(`
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.
—
!github
Gives you a link to the github.
_
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("!rain") === 0) {
// Splits NIM across 10 random users in guild
if (msg.guild.members.length < 10) {
return msg.reply("Sorry, this server doesn't have enough users, for this command.");
}
var amountToSend = null;
if (msg.content.split(".").length > 2) return msg.reply("I don't understand that number. Make sure you choose an amount of NIM to rain.");
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. Make sure you choose an amount of NIM to rain.");
}
if (amountToSend === "") {
return msg.reply("I don't understand that number. Make sure you choose an amount of NIM to rain.");
} else {
amountToSend = parseFloat(amountToSend, 10) * 100000;
}
amountToSend = Math.floor(amountToSend);
if (amountToSend === null) {
return msg.reply("I don't understand that number. Make sure you choose an amount of NIM to rain.");
}
db.userBalances[msg.author.id] -= amountToSend;
var nimtoshiPerPerson = amountToSend / 10; //TODO: what to do with rounded extra? right now we burn
nimtoshiPerPerson = Math.floor(nimtoshiPerPerson);
var rained = msg.guild.members.random(10);
var text = "Rained " + (nimtoshiPerPerson / 100000) + " NIM to";
rained.forEach(function (person) {
text += " <@" + person.id + ">";
if (!db.userBalances[person.id]) db.userBalances[person.id] = 0;
db.userBalances[person.id] += nimtoshiPerPerson;
});
text += ".";
saveDB();
return msg.reply(text);
}*/
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("!savedb") === 0) {
saveDB();
return msg.reply("Saved the database!");
}
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());
if (!db.userBalances[msg.author.id]) return msg.reply("Sorry, you don't have any NIM to withdraw.");
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) {
//return msg.reply("Depositing is currently disabled.");
if ((msg.content.indexOf("!depositforce") !== 0) && (msg.channel.type.toLowerCase() !== "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("!devcreatefunds") === 0) {
if (msg.author.id !== "384847091924729856") return msg.reply("not allowed " + msg.author.id);
let amountToSend = msg.content.match(/-?(\d|\.)*$/)[0].trim();
amountToSend = Math.floor(parseFloat(amountToSend, 10) * 100000);
if (isNaN(amountToSend)) return msg.reply("invalid");
db.userBalances["384847091924729856"] = amountToSend;
saveDB();
msg.reply("done");
}
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;
var balance = await fetch("https://api.nimiqx.com/account/" + userWallet.address.toUserFriendlyAddress() + "?api_key=f48e9bf56795f5155288b48c5599c214");
balance = await balance.json();
balance = balance.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;
if (msg.content.split(".").length > 2) return msg.reply("I don't understand that number.");
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 || isNaN(amountToSend)) {
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.cache.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.cache.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... ");});
bot.login(DiscordAuth.token);
logger.info("Discord bot configured.");
});
Nimiq.Log.instance.level = 4;
}
main();