2018-07-02 15:43:16 +02:00
|
|
|
|
const Twit = require("twit");
|
|
|
|
|
const config = require("config");
|
|
|
|
|
const winston = require("winston");
|
|
|
|
|
require("winston-daily-rotate-file");
|
|
|
|
|
const Client = require("bitcoin-core");
|
|
|
|
|
const lbry = new Client({
|
|
|
|
|
username: config.get("lbrycrd.username"),
|
|
|
|
|
password: config.get("lbrycrd.password"),
|
|
|
|
|
port: config.get("lbrycrd.port")
|
|
|
|
|
});
|
|
|
|
|
const logger = winston.createLogger({
|
|
|
|
|
level: "info",
|
|
|
|
|
format: winston.format.json(),
|
|
|
|
|
transports: [
|
|
|
|
|
new winston.transports.DailyRotateFile({
|
|
|
|
|
filename: "tipbot-%DATE%.log",
|
|
|
|
|
dirname: "./logs",
|
|
|
|
|
datePattern: "YYYY-MM-DD-HH",
|
|
|
|
|
zippedArchive: true,
|
|
|
|
|
maxSize: "20m",
|
|
|
|
|
maxFiles: "14d"
|
|
|
|
|
}),
|
|
|
|
|
new winston.transports.Console({
|
|
|
|
|
format: winston.format.simple(),
|
|
|
|
|
level: "debug"
|
|
|
|
|
})
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const T = new Twit({
|
|
|
|
|
consumer_key: config.get("twitter.consumer_key"),
|
|
|
|
|
consumer_secret: config.get("twitter.consumer_secret"),
|
|
|
|
|
access_token: config.get("twitter.access_token"),
|
|
|
|
|
access_token_secret: config.get("twitter.access_token_secret"),
|
|
|
|
|
timeout_ms: 60 * 1000, // optional HTTP request timeout to apply to all requests.
|
|
|
|
|
strictSSL: true // optional - requires SSL certificates to be valid.
|
|
|
|
|
});
|
|
|
|
|
|
2018-07-05 11:37:04 +02:00
|
|
|
|
const stream = T.stream("statuses/filter", { track: config.get("bot.handle") });
|
2018-07-02 15:43:16 +02:00
|
|
|
|
logger.info("Started LBRY twitter tipbot.");
|
|
|
|
|
|
|
|
|
|
stream.on("tweet", function(tweet) {
|
2018-07-05 11:37:04 +02:00
|
|
|
|
if(tweet.user.screen_name === config.get("bot.handle").substring(1)) return;
|
2018-07-02 15:43:16 +02:00
|
|
|
|
let msg = checkTrunc(tweet);
|
2018-08-04 11:35:07 +02:00
|
|
|
|
msg = msg.replace(/[\n\\]/g, " ").slice(msg.lastIndexOf(config.get("bot.handle"))).split(" ");
|
2018-07-06 15:47:49 +02:00
|
|
|
|
if (msg.length >= 2) checkTweet(tweet, msg);
|
2018-07-02 15:43:16 +02:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function checkTweet(tweet, msg) {
|
|
|
|
|
switch (msg[1]) {
|
|
|
|
|
case "help":
|
|
|
|
|
doHelp(tweet, msg);
|
|
|
|
|
break;
|
|
|
|
|
case "balance":
|
|
|
|
|
doBalance(tweet, msg);
|
|
|
|
|
break;
|
|
|
|
|
case "deposit":
|
|
|
|
|
doDeposit(tweet, msg);
|
|
|
|
|
break;
|
|
|
|
|
case "withdraw":
|
|
|
|
|
doWithdraw(tweet, msg);
|
|
|
|
|
break;
|
|
|
|
|
case "tip":
|
|
|
|
|
doTip(tweet, msg);
|
|
|
|
|
break;
|
2018-07-05 11:37:04 +02:00
|
|
|
|
case "terms":
|
|
|
|
|
doTerms(tweet, msg);
|
|
|
|
|
break;
|
2018-07-06 12:03:28 +02:00
|
|
|
|
case "lbryian":
|
|
|
|
|
logger.info("Got a command with the old format, handling it...");
|
|
|
|
|
checkTweet(tweet, msg.splice(1));
|
|
|
|
|
break;
|
2018-07-02 15:43:16 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function doHelp(tweet, msg) {
|
|
|
|
|
try {
|
|
|
|
|
let post = await T.post("statuses/update", {
|
|
|
|
|
status:
|
2018-07-06 16:29:35 +02:00
|
|
|
|
`@${tweet.user.screen_name} `+
|
|
|
|
|
`Call commands with: ${config.get("bot.handle")} + \n` +
|
|
|
|
|
"help - Shows this command.\n" +
|
|
|
|
|
"balance - Get your balance.\n" +
|
|
|
|
|
"deposit - Get address for your deposits.\n" +
|
|
|
|
|
"withdraw ADDRESS AMOUNT - Withdraw AMOUNT credits to ADDRESS.\n" +
|
|
|
|
|
"tip USER AMOUNT - Tip USER AMOUNT.\n"+
|
|
|
|
|
"terms - Sends the TOS.",
|
2018-07-02 15:43:16 +02:00
|
|
|
|
in_reply_to_status_id: tweet.id_str
|
|
|
|
|
});
|
|
|
|
|
logger.info(
|
|
|
|
|
`Sent help to ${tweet.user.screen_name}, tweet id: ${tweet.id_str}`
|
|
|
|
|
);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-05 11:37:04 +02:00
|
|
|
|
async function doTerms(tweet, msg){
|
|
|
|
|
// ADD terms
|
2018-07-06 12:03:28 +02:00
|
|
|
|
await T.post("statuses/update", {
|
|
|
|
|
status:
|
|
|
|
|
`@${tweet.user.screen_name} `+
|
|
|
|
|
"There are no fees to use this bot except the automatic daemon fee. \n"+
|
2018-07-06 15:47:49 +02:00
|
|
|
|
"Under no circumstances shall LBRY Inc. be held responsible for lost, stolen or misdirected funds.",
|
2018-07-06 12:03:28 +02:00
|
|
|
|
in_reply_to_status_id: tweet.id_str
|
|
|
|
|
});
|
2018-07-05 11:37:04 +02:00
|
|
|
|
}
|
2018-07-02 15:43:16 +02:00
|
|
|
|
async function doBalance(tweet, msg) {
|
|
|
|
|
try {
|
2018-07-05 11:37:04 +02:00
|
|
|
|
const balance = await lbry.getBalance(id(tweet.user.id_str), config.get("bot.requiredConfirms")); // Amount of confirms before we can use it.
|
2018-07-02 15:43:16 +02:00
|
|
|
|
const post = await T.post("statuses/update", {
|
2018-07-05 11:37:04 +02:00
|
|
|
|
in_reply_to_status_id: tweet.id_str,
|
|
|
|
|
status: `@${tweet.user.screen_name} You have ${balance} LBC.`
|
2018-07-02 15:43:16 +02:00
|
|
|
|
});
|
|
|
|
|
logger.info(
|
|
|
|
|
`Sent balance command to ${tweet.user.screen_name}, tweet id: ${
|
|
|
|
|
tweet.id_str
|
|
|
|
|
}`
|
|
|
|
|
);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
async function doDeposit(tweet, msg) {
|
|
|
|
|
try {
|
|
|
|
|
const post = await T.post("statuses/update", {
|
2018-07-05 11:37:04 +02:00
|
|
|
|
status: `@${tweet.user.screen_name} Your deposit address is ${await getAddress(id(tweet.user.id_str))}.`,
|
2018-07-02 15:43:16 +02:00
|
|
|
|
in_reply_to_status_id: tweet.id_str
|
|
|
|
|
});
|
|
|
|
|
logger.info(
|
|
|
|
|
`Sent deposit address to ${tweet.user.screen_name}, tweet id: ${
|
|
|
|
|
tweet.id_str
|
|
|
|
|
}`
|
|
|
|
|
);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
async function doWithdraw(tweet, msg) {
|
2018-07-05 11:37:04 +02:00
|
|
|
|
try {
|
2018-07-02 15:43:16 +02:00
|
|
|
|
if (msg.length < 4) return doHelp(tweet, msg);
|
|
|
|
|
let address = msg[2];
|
|
|
|
|
let amount = getValidatedAmount(msg[3]);
|
|
|
|
|
if (amount === null) {
|
|
|
|
|
return await T.post("statuses/update", {
|
2018-07-05 11:37:04 +02:00
|
|
|
|
status: `@${tweet.user.screen_name} I don´t know how to withdraw that many credits...`,
|
2018-07-02 15:43:16 +02:00
|
|
|
|
in_reply_to_status_id: tweet.id_str
|
|
|
|
|
});
|
|
|
|
|
}
|
2018-07-05 11:37:04 +02:00
|
|
|
|
let txId = await lbry.sendFrom(id(tweet.user.id_str), address, amount);
|
2018-07-02 15:43:16 +02:00
|
|
|
|
await T.post("statuses/update", {
|
2018-07-05 11:37:04 +02:00
|
|
|
|
status: `@${tweet.user.screen_name} You withdrew ${amount} LBC to ${address}. \n${txLink(txId)}`,
|
2018-07-02 15:43:16 +02:00
|
|
|
|
in_reply_to_status_id: tweet.id_str
|
|
|
|
|
});
|
|
|
|
|
logger.info(
|
|
|
|
|
`User ${
|
|
|
|
|
tweet.user.screen_name
|
|
|
|
|
} withdraw ${amount} LBC to ${address}, tweet id: ${tweet.id_str}`
|
|
|
|
|
);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
async function doTip(tweet, msg) {
|
|
|
|
|
try {
|
|
|
|
|
if (msg.length < 3) {
|
|
|
|
|
return doHelp(tweet, msg);
|
|
|
|
|
}
|
|
|
|
|
const amount = getValidatedAmount(msg[3]);
|
|
|
|
|
if (amount === null) {
|
|
|
|
|
return await T.post("statuses/update", {
|
2018-07-05 11:37:04 +02:00
|
|
|
|
status: `@${tweet.user.screen_name} I don´t know how to tip that many credits...`,
|
2018-07-02 15:43:16 +02:00
|
|
|
|
in_reply_to_status_id: tweet.id_str
|
|
|
|
|
});
|
|
|
|
|
}
|
2018-07-05 11:37:04 +02:00
|
|
|
|
const userToTip = tweet.entities.user_mentions.find(u => `@${u.screen_name}` === msg[2]).id_str;
|
2018-07-06 15:47:49 +02:00
|
|
|
|
let tipToAddress = await getAddress(id(userToTip)) // Call this to ensure user has an account.
|
2018-07-02 15:43:16 +02:00
|
|
|
|
if (userToTip === null) {
|
|
|
|
|
return await T.post("statuses/update", {
|
2018-07-05 11:37:04 +02:00
|
|
|
|
status: `@${tweet.user.screen_name} I could not find that user...`,
|
2018-07-02 15:43:16 +02:00
|
|
|
|
in_reply_to_status_id: tweet.id_str
|
|
|
|
|
});
|
|
|
|
|
}
|
2018-07-05 11:37:04 +02:00
|
|
|
|
const balanceFromUser = await lbry.getBalance(id(tweet.user.id_str), config.get("bot.requiredConfirms"));
|
|
|
|
|
if (balanceFromUser < amount) {
|
|
|
|
|
return await T.post("statuses/update", {
|
2018-07-06 15:47:49 +02:00
|
|
|
|
status: `@${tweet.user.screen_name} You tried tipping more than you have! You are ${amount-balanceFromUser} LBC short.`,
|
2018-07-05 11:37:04 +02:00
|
|
|
|
in_reply_to_status_id: tweet.id_str
|
|
|
|
|
});
|
|
|
|
|
}
|
2018-07-06 15:47:49 +02:00
|
|
|
|
const txId = await lbry.sendFrom(id(tweet.user.id_str), tipToAddress, Number(amount), 1);
|
2018-07-05 11:37:04 +02:00
|
|
|
|
await T.post("statuses/update", {
|
|
|
|
|
status: `@${tweet.user.screen_name} Tipped ${
|
|
|
|
|
msg[2]
|
2018-07-06 15:47:49 +02:00
|
|
|
|
} ${amount} LBC! \nTransaction: ${txLink(txId)} \nSee https://lbry.io/faq/tipbot-twitter for more information.`,
|
2018-07-05 11:37:04 +02:00
|
|
|
|
in_reply_to_status_id: tweet.id_str
|
|
|
|
|
});
|
2018-07-02 15:43:16 +02:00
|
|
|
|
logger.info(
|
|
|
|
|
`@${tweet.user.screen_name}(${tweet.user.id_str}) tipped ${
|
|
|
|
|
msg[2]
|
|
|
|
|
}(${userToTip}) ${amount} LBC.`
|
|
|
|
|
);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function getAddress(userId) {
|
|
|
|
|
try {
|
|
|
|
|
let uAddresses = await lbry.getAddressesByAccount(userId);
|
|
|
|
|
if (uAddresses.length > 0) return uAddresses[0];
|
|
|
|
|
let nAddress = await lbry.getNewAddress(userId);
|
|
|
|
|
return nAddress;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-06 12:03:28 +02:00
|
|
|
|
|
2018-07-02 15:43:16 +02:00
|
|
|
|
function getValidatedAmount(amount) {
|
|
|
|
|
amount = amount.trim();
|
|
|
|
|
if (amount.toLowerCase().endsWith("lbc")) {
|
|
|
|
|
amount = amount.substring(0, amount.length - 3);
|
|
|
|
|
}
|
|
|
|
|
return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null;
|
|
|
|
|
}
|
|
|
|
|
function txLink(txId) {
|
|
|
|
|
return `https://explorer.lbry.io/tx/${txId}`;
|
|
|
|
|
}
|
|
|
|
|
function checkTrunc(tweet) {
|
|
|
|
|
if (tweet.truncated) return tweet.extended_tweet.full_text;
|
|
|
|
|
return tweet.text;
|
|
|
|
|
}
|
2018-07-05 11:37:04 +02:00
|
|
|
|
|
|
|
|
|
function id(usrId){
|
|
|
|
|
return `t-${usrId}`;
|
|
|
|
|
}
|