diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e838957 --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +The MIT License (MIT) + +Copyright (c) 2018 LBRY Inc + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d01d311 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# Twitter tipbot - A twitter tipbot for LBRY + +This repo contains the twitter tipbot used by LBRY. This bot allows users to tip each other LBC on twitter. + +## Installation +### Prerequisites +* Lbrycrd-daemon +* Node.js v8+ +* Yarn +* A twitter application on the tipbot account + +>To get started you should clone the git: +``` +git clone https://github.com/lbryio/twitter-tipbot +``` +>Install all modules with yarn: +``` +yarn install +``` +>Rename default.example.json to default.json and enter the twitter tokens and daemon settings. + +>Run the bot with: +``` +node index.js +``` + + +## Contributing + +Contributions to this project are welcome, encouraged, and compensated. For more details, see [lbry.io/faq/contributing](https://lbry.io/faq/contributing) + +## License +This project is MIT Licensed © [LBRYio](https://github.com/lbryio) + +## Security + +We take security seriously. Please contact security@lbry.io regarding any security issues. +Our PGP key is [here](https://keybase.io/lbry/key.asc) if you need it. + +## Contact + +The primary contact for this project is [@filipnyquist](https://github.com/filipnyquist) (filip@lbry.io) diff --git a/config/default.example.json b/config/default.example.json index a8429d3..4580188 100644 --- a/config/default.example.json +++ b/config/default.example.json @@ -1,4 +1,8 @@ { + "bot":{ + "handle": "@devlbctipbot", + "requiredConfirms": 2 + }, "twitter": { "consumer_key": "****", "consumer_secret": "****", diff --git a/index.js b/index.js index 46cd410..12e27dd 100644 --- a/index.js +++ b/index.js @@ -37,12 +37,13 @@ const T = new Twit({ strictSSL: true // optional - requires SSL certificates to be valid. }); -var stream = T.stream("statuses/filter", { track: "@devlbctipbot" }); +const stream = T.stream("statuses/filter", { track: config.get("bot.handle") }); logger.info("Started LBRY twitter tipbot."); stream.on("tweet", function(tweet) { + if(tweet.user.screen_name === config.get("bot.handle").substring(1)) return; let msg = checkTrunc(tweet); - msg = msg.slice(msg.indexOf("@devlbctipbot")).split(" "); + msg = msg.slice(msg.indexOf(config.get("bot.handle"))).split(" "); checkTweet(tweet, msg); }); @@ -63,6 +64,9 @@ function checkTweet(tweet, msg) { case "tip": doTip(tweet, msg); break; + case "terms": + doTerms(tweet, msg); + break; } } @@ -70,7 +74,8 @@ async function doHelp(tweet, msg) { try { let post = await T.post("statuses/update", { status: - "All commands should be called with @ devlbctipbot \n" + + `@${tweet.user.screen_name} `+ + "All commands should be called with @ + subcommand \n" + "help - Shows this command. \n" + "balance - Get your balance. \n" + "deposit - Get address for your deposits. \n" + @@ -85,12 +90,15 @@ async function doHelp(tweet, msg) { logger.error(e); } } +async function doTerms(tweet, msg){ +// ADD terms +} async function doBalance(tweet, msg) { try { - const balance = await lbry.getBalance(tweet.user.id_str, 3); + const balance = await lbry.getBalance(id(tweet.user.id_str), config.get("bot.requiredConfirms")); // Amount of confirms before we can use it. const post = await T.post("statuses/update", { - status: `You have ${balance} LBC.`, - in_reply_to_status_id: tweet.id_str + in_reply_to_status_id: tweet.id_str, + status: `@${tweet.user.screen_name} You have ${balance} LBC.` }); logger.info( `Sent balance command to ${tweet.user.screen_name}, tweet id: ${ @@ -104,7 +112,7 @@ async function doBalance(tweet, msg) { async function doDeposit(tweet, msg) { try { const post = await T.post("statuses/update", { - status: `Your deposit address is ${await getAddress(tweet.user.id_str)}.`, + status: `@${tweet.user.screen_name} Your deposit address is ${await getAddress(id(tweet.user.id_str))}.`, in_reply_to_status_id: tweet.id_str }); logger.info( @@ -117,18 +125,19 @@ async function doDeposit(tweet, msg) { } } async function doWithdraw(tweet, msg) { + try { 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", { - status: `I don´t know how to withdraw that many credits...`, + status: `@${tweet.user.screen_name} I don´t know how to withdraw that many credits...`, in_reply_to_status_id: tweet.id_str }); } - let txId = await lbry.sendFrom(tweet.user.id_str, address, amount); + let txId = await lbry.sendFrom(id(tweet.user.id_str), address, amount); await T.post("statuses/update", { - status: `You withdrew ${amount} LBC to ${address}. \n${txLink(txId)}`, + status: `@${tweet.user.screen_name} You withdrew ${amount} LBC to ${address}. \n${txLink(txId)}`, in_reply_to_status_id: tweet.id_str }); logger.info( @@ -136,7 +145,6 @@ async function doWithdraw(tweet, msg) { tweet.user.screen_name } withdraw ${amount} LBC to ${address}, tweet id: ${tweet.id_str}` ); - try { } catch (e) { logger.error(e); } @@ -149,25 +157,35 @@ async function doTip(tweet, msg) { const amount = getValidatedAmount(msg[3]); if (amount === null) { return await T.post("statuses/update", { - status: `I don´t know how to tip that many credits...`, + status: `@${tweet.user.screen_name} I don´t know how to tip that many credits...`, in_reply_to_status_id: tweet.id_str }); } - const userToTip = userToTip(tweet, msg); - const userToTipAddress = getAddress(userToTip); + const userToTip = tweet.entities.user_mentions.find(u => `@${u.screen_name}` === msg[2]).id_str; if (userToTip === null) { return await T.post("statuses/update", { - status: `I could not find that user...`, + status: `@${tweet.user.screen_name} I could not find that user...`, in_reply_to_status_id: tweet.id_str }); } - const txId = await lbry.sendFrom( - tweet.user.id_str, - userToTipAddress, - Number(amount), - null, - null + const balanceFromUser = await lbry.getBalance(id(tweet.user.id_str), config.get("bot.requiredConfirms")); + if (balanceFromUser < amount) { + return await T.post("statuses/update", { + status: `@${tweet.user.screen_name} You tried to tip, but you are missing ${amount-balanceFromUser} LBC.`, + in_reply_to_status_id: tweet.id_str + }); + } + const txId = await lbry.move( + id(tweet.user.id_str), + id(userToTip), + Number(amount) ); + await T.post("statuses/update", { + status: `@${tweet.user.screen_name} Tipped ${ + msg[2] + } ${amount} LBC! \n See https://lbry.io/faq/tipbot-twitter for more information.`, + in_reply_to_status_id: tweet.id_str + }); logger.info( `@${tweet.user.screen_name}(${tweet.user.id_str}) tipped ${ msg[2] @@ -188,11 +206,6 @@ async function getAddress(userId) { logger.error(e); } } -function userToTip(tweet, msg) { - const username = msg[2]; - const users = tweet.entities.user_mentions; - return users.find(u => `@${u.screen_name}` === username).id_str; -} function getValidatedAmount(amount) { amount = amount.trim(); if (amount.toLowerCase().endsWith("lbc")) { @@ -207,3 +220,7 @@ function checkTrunc(tweet) { if (tweet.truncated) return tweet.extended_tweet.full_text; return tweet.text; } + +function id(usrId){ + return `t-${usrId}`; +}