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-20 17:09:25 +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" , {
2019-10-10 22:15:07 +02:00
status : ` @ ${ tweet . user . screen _name } Tipped ${ amount } LBC! We'd say who it was to, but then Twitter would ban the bot. \n Transaction: ${ txLink ( txId ) } \n See https://lbry.com/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 ) {
2019-10-10 22:15:07 +02:00
return ` https://explorer.lbry.com/tx/ ${ txId } ` ;
2018-07-02 15:43:16 +02:00
}
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 } ` ;
}