├── .babelrc ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── bot ├── alias.json ├── bot.js ├── modules │ ├── bot-uptime.js │ ├── dogeTipper.js │ ├── exampleTipper.js │ ├── ftcTipper.js │ ├── helpTipper.js │ ├── lbcTipper.js │ ├── neblTipper.js │ ├── phaseTipper.js │ ├── ppcTipper.js │ ├── pxcTipper.js │ ├── rvnTipper.js │ ├── spkTipper.js │ ├── ufoTipper.js │ ├── vtlTipper.js │ └── xuezTipper.js └── plugins.js ├── config └── default.json.example ├── ecosystem.config.js.example ├── package.json ├── windows-install.bat └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["node8"] 3 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # dist 9 | dist/* 10 | #configuration 11 | config/default.json 12 | ecosystem.config.js 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Typescript v1 declaration files 46 | typings/ 47 | 48 | # Optional npm cache directory 49 | .npm 50 | 51 | # Optional eslint cache 52 | .eslintcache 53 | 54 | # Optional REPL history 55 | .node_repl_history 56 | 57 | # Output of 'npm pack' 58 | *.tgz 59 | 60 | # Yarn Integrity file 61 | .yarn-integrity 62 | 63 | # dotenv environment variables file 64 | .env 65 | bot/.DS_Store 66 | .DS_Store 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 MSFTserver 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bot for Discord communities to facilitate crypto coin tipping! 2 | (This README will be updated along with bot updates) 3 | 4 | Features: 5 | - Tipbot for any coin running the bitcoind client. 6 | - Help message `!tip`. 7 | - Dynamic plugin loading with permission support. 8 | - **out of the box Supported Coins** 9 | - Dogecoin (DOGE) 10 | - Ravencoin (RVN) 11 | - LBRY Credits (LBC) 12 | - Uniform Fiscal Object (UFO) 13 | - ~~Proton (PROTON)~~ Phase(PHASE) 14 | - Phoenixcoin (PXC) 15 | - Feathercoin (FTC) 16 | - Vertical (VTL) 17 | - Neblio (NEBL) 18 | - Xuez (XUEZ) 19 | - SparksPay (SPK) 20 | 21 | 22 | ## Create a Bot 23 | 24 | 1) Create a bot and get the bots Token and Client ID: https://discordapp.com/developers/applications/me 25 | 26 | 1) After going to the link above click “new application”. Give it a name, picture, and description. 27 | 28 | 2) On the side bar navigation menu click "Bot" Click “Add Bot” and click “Yes, Do It!” when the dialog pops up. 29 | 30 | 3) Copy down the token used on this page to login and Client ID on the general info page to invite your new bot to your discord server. 31 | 32 | 2) invite the bot to your server using the link below and entering the Client ID or generate your own [Here:link:](https://discordapi.com/permissions.html) 33 | 34 | ``` 35 | https://discordapp.com/oauth2/authorize?client_id=INSERT_CLIENT_ID_HERE&scope=bot&permissions=27648 36 | ``` 37 | 38 | ## Edit Files 39 | 40 | 1) Edit and rename `ecosystem.config.js.example` to `ecosystem.config.js` in the root folder to match the correct directories for log files and bot root folder. 41 | 42 | 2) Edit and rename `default.json.example` to `default.json` in `/config`. You will use the same info in the next step. 43 | 44 | ``` 45 | "rvn": { 46 | "paytxfee": .01 47 | "config": 48 | "port": 3335, 49 | "user": "username", 50 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 51 | } 52 | }, 53 | ``` 54 | 55 | (you can add more coins by following this format and using the `exampleTipper.js` file in `/bot/modules`) 56 | 57 | 3) set up the wallets config file 58 | 59 | 1) In most cases, your wallets data folder can be found in `%appdata%` 60 | 61 | (default Roaming Folder), `e.g. C:\Users\USER\AppData\Roaming\COIN.` 62 | 63 | 2) Edit or create your `COIN.conf` file (Where "COIN" is the coin name) to include the following: 64 | 65 | ``` 66 | server=1 67 | par=1 68 | rpcbind=127.0.0.1 69 | rpcallowip=127.0.0.1 70 | rpcport=3335 71 | rpcuser= 72 | rpcpassword= 73 | rpcclienttimeout=30 74 | rpcthreads= 75 | rpcworkqueue=1000 76 | paytxfee= 77 | ``` 78 | 79 | 1) NOTE: for `paytxfee` to actually work properly use the console or rpc command `settxfee number` number being the fee of course. 80 | 81 | 2) NOTE: if you are using a master node coin you also need to add these extra options into your wallets config file 82 | 83 | ``` 84 | staking=0 85 | enableaccounts=1 86 | ``` 87 | 88 | ## Install Bot 89 | 90 | ### Auto - Windows 91 | 92 | 1) run the `windows-install.bat` file to install needed tools, Not on windows or don't want to auto install follow the instructions below for manual Installation. 93 | 94 | 2) verify the following tools are installed by running the commands below in cmd: 95 | 96 | * git - `git --version` 97 | * node - `node -v` 98 | * npm - `npm -v` 99 | * pm2 - `pm2 -v` 100 | * yarn - `yarn --version` 101 | 102 | 3) start the bot with `yarn start` or `pm2 start ecosystem.config.js` in the bots root directory 103 | 104 | 1) if the bot fails to start and throws missing npm package errors simply run `npm install` again in the bots root directory 105 | 106 | ### Manual - Linux/Mac 107 | 108 | 1) Download and install the required tools listed below: 109 | * [git > 2.0.0](https://git-scm.com/downloads) 110 | * [node > 8.0.0](https://nodejs.org/en/) 111 | * [npm > 0.12.x](https://nodejs.org/en/) 112 | * [pm2 > latest](http://pm2.keymetrics.io/) 113 | * [yarn > latest](https://yarnpkg.com/en/docs/install) 114 | 115 | 2) After the above tools have been installed run `npm install` in the bots root directory. 116 | 117 | 1) this may throw some errors on some systems not all packages are required for some systems, the bot will still run unless it's an absolutely needed dependency. 118 | 119 | 3) start the bot with `yarn start` or `pm2 start ecosystem.config.js` in the bots root directory 120 | 121 | ### Development 122 | 123 | Be sure to run the command below before working on any code, this ensures 124 | prettier goes to work and keeps the code to our standard. 125 | 126 | ``` 127 | yarn install --production=false 128 | ``` 129 | to run prettier before submitting your code simply run the following in the bots root directory. 130 | 131 | ``` 132 | yarn precommit 133 | ``` 134 | -------------------------------------------------------------------------------- /bot/alias.json: -------------------------------------------------------------------------------- 1 | { 2 | "rvntip":"tiprvn", 3 | "dogetip":"tipdoge", 4 | "lbctip":"tiplbc", 5 | "ppctip":"tipppc", 6 | "protontip":"tipproton", 7 | "ufotip":"tipufo", 8 | "pxctip":"tippxc", 9 | "ftctip":"tipftc", 10 | "vtltip": "tipvtl", 11 | "xueztip": "tipxuez", 12 | "spktip": "tipspk", 13 | "tip":"tiphelp", 14 | "tip help":"tiphelp" 15 | } 16 | -------------------------------------------------------------------------------- /bot/bot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Load up libraries 4 | const Discord = require('discord.js'); 5 | let moment = require('moment-timezone'); 6 | // Load config! 7 | let config = require('config'); 8 | let logChannel = config.get('moderation').logchannel; 9 | let pm2Name = config.get('moderation').pm2Name; 10 | config = config.get('bot'); 11 | 12 | var aliases; 13 | // check if any aliases are defined 14 | try { 15 | var time = moment() 16 | .tz('America/Los_Angeles') 17 | .format('MM-DD-YYYY hh:mm a'); 18 | aliases = require('./alias.json'); 19 | console.log('[' + time + ' PST][' + pm2Name + '] ' + Object.keys(aliases).length + ' aliases Loaded!'); 20 | } catch (e) { 21 | var time = moment() 22 | .tz('America/Los_Angeles') 23 | .format('MM-DD-YYYY hh:mm a'); 24 | console.log('[' + time + ' PST][' + pm2Name + '] No aliases defined'); 25 | } 26 | var commands = {}; 27 | 28 | var bot = new Discord.Client(); 29 | 30 | bot.on('ready', function() { 31 | var time = moment() 32 | .tz('America/Los_Angeles') 33 | .format('MM-DD-YYYY hh:mm a'); 34 | console.log( 35 | '[' + 36 | time + 37 | ' PST][' + 38 | pm2Name + 39 | '] ' + 40 | bot.user.username + 41 | 'Logged in! Serving in ' + 42 | bot.guilds.array().length + 43 | ' servers' 44 | ); 45 | bot.channels 46 | .get(logChannel) 47 | .send( 48 | '[' + 49 | time + 50 | ' PST][' + 51 | pm2Name + 52 | '] ' + 53 | bot.user.username + 54 | 'Logged in! Serving in ' + 55 | bot.guilds.array().length + 56 | ' servers' 57 | ); 58 | require('./plugins.js').init(); 59 | console.log( 60 | '[' + 61 | time + 62 | ' PST][' + 63 | pm2Name + 64 | '] type ' + 65 | config.prefix + 66 | 'tiphelp in Discord for a commands list.' 67 | ); 68 | bot.channels 69 | .get(logChannel) 70 | .send( 71 | '[' + 72 | time + 73 | ' PST][' + 74 | pm2Name + 75 | '] type ' + 76 | config.prefix + 77 | 'tiphelp in Discord for a commands list.' 78 | ); 79 | bot.user.setActivity(config.prefix + 'Intialized!'); 80 | var text = ['tiprvn', 'tipdoge', 'tiplbc', 'tipufo', 'tipppc','tipphase', 'tippxc', 'tipftc', 'tipvtl', 'tipnebl', 'tipxuez', 'tipspk', 'tiphelp']; 81 | var counter = 0; 82 | setInterval(change, 10000); 83 | 84 | function change() { 85 | bot.user.setActivity(config.prefix + text[counter]); 86 | counter++; 87 | if (counter >= text.length) { 88 | counter = 0; 89 | } 90 | } 91 | }); 92 | 93 | process.on('uncaughtException', err => { 94 | var time = moment() 95 | .tz('America/Los_Angeles') 96 | .format('MM-DD-YYYY hh:mm a'); 97 | console.log('[' + time + ' PST][' + pm2Name + '] uncaughtException: ' + err); 98 | bot.channels 99 | .get(logChannel) 100 | .send('[' + time + ' PST][' + pm2Name + '] uncaughtException: ' + err); 101 | process.exit(1); //exit node.js with an error 102 | }); 103 | 104 | process.on('unhandledRejection', err => { 105 | var time = moment() 106 | .tz('America/Los_Angeles') 107 | .format('MM-DD-YYYY hh:mm a'); 108 | console.log('[' + time + ' PST][' + pm2Name + '] unhandledRejection: ' + err); 109 | bot.channels 110 | .get(logChannel) 111 | .send('[' + time + ' PST][' + pm2Name + '] unhandledRejection: ' + err); 112 | process.exit(1); //exit node.js with an error 113 | }); 114 | 115 | bot.on('disconnected', function() { 116 | var time = moment() 117 | .tz('America/Los_Angeles') 118 | .format('MM-DD-YYYY hh:mm a'); 119 | console.log('[' + time + ' PST][' + pm2Name + '] Disconnected!'); 120 | process.exit(1); //exit node.js with an error 121 | }); 122 | 123 | bot.on('error', function(error) { 124 | var time = moment() 125 | .tz('America/Los_Angeles') 126 | .format('MM-DD-YYYY hh:mm a'); 127 | console.log('[' + time + ' PST][' + pm2Name + '] error: ' + error); 128 | process.exit(1); //exit node.js with an error 129 | }); 130 | 131 | function checkMessageForCommand(msg, isEdit) { 132 | //check if message is a command 133 | if (msg.author.id != bot.user.id && msg.content.startsWith(config.prefix)) { 134 | //check if user is Online 135 | if ( 136 | !msg.author.presence.status || 137 | msg.author.presence.status == 'offline' || 138 | msg.author.presence.status == 'invisible' 139 | ) { 140 | msg.author 141 | .send('Please set your Discord Presence to Online to talk to the bot!') 142 | .catch(function(error) { 143 | msg.channel 144 | .send( 145 | msg.author + 146 | ', Please enable Direct Messages from server members to communicate fully with our bot, it is located in the user setting area under Privacy & Safety tab, select the option allow direct messages from server members' 147 | ) 148 | .then( 149 | msg.channel.send( 150 | 'Please set your Discord Presence to Online to talk to the Bot!' 151 | ) 152 | ); 153 | return; 154 | }); 155 | } 156 | var cmdTxt = msg.content.split(' ')[0].substring(config.prefix.length); 157 | var suffix = msg.content.substring( 158 | cmdTxt.length + config.prefix.length + 1 159 | ); //add one for the ! and one for the space 160 | if (msg.isMentioned(bot.user)) { 161 | try { 162 | cmdTxt = msg.content.split(' ')[1]; 163 | suffix = msg.content.substring( 164 | bot.user.mention().length + cmdTxt.length + config.prefix.length + 1 165 | ); 166 | } catch (e) { 167 | //no command 168 | msg.channel.send('Yes?'); 169 | return; 170 | } 171 | } 172 | let alias = aliases[cmdTxt]; 173 | if (alias) { 174 | var cmd = commands[alias]; 175 | } else { 176 | var cmd = commands[cmdTxt]; 177 | } 178 | if (cmd) { 179 | // Add permission check here later on ;) 180 | console.log( 181 | 'treating ' + 182 | msg.content + 183 | ' from ' + 184 | msg.author.username + 185 | ' as command' 186 | ); 187 | try { 188 | cmd.process(bot, msg, suffix, isEdit); 189 | } catch (e) { 190 | var msgTxt = 'command ' + cmdTxt + ' failed :('; 191 | var linebreak = '\n-------------------------------------------------\n'; 192 | if (config.debug) { 193 | msgTxt += '\n' + e.stack; 194 | } 195 | var time = moment() 196 | .tz('America/Los_Angeles') 197 | .format('MM-DD-YYYY hh:mm a'); 198 | bot.channels 199 | .get(logChannel) 200 | .send('[' + time + ' PST][' + pm2Name + '] ' + msgTxt + linebreak); 201 | } 202 | } 203 | } else { 204 | //message isn't a command or is from us 205 | //drop our own messages to prevent feedback loops 206 | if (msg.author == bot.user) { 207 | return; 208 | } 209 | 210 | if (msg.author != bot.user && msg.isMentioned(bot.user)) { 211 | msg.channel.send('yes?'); //using a mention here can lead to looping 212 | } else { 213 | } 214 | } 215 | } 216 | 217 | bot.on('message', msg => checkMessageForCommand(msg, false)); 218 | 219 | exports.addCommand = function(commandName, commandObject) { 220 | try { 221 | commands[commandName] = commandObject; 222 | } catch (err) { 223 | var time = moment() 224 | .tz('America/Los_Angeles') 225 | .format('MM-DD-YYYY hh:mm a'); 226 | console.log('[' + time + ' PST][' + pm2Name + '] Error addCommand: ' + err); 227 | bot.channels 228 | .get(logChannel) 229 | .send('[' + time + ' PST][' + pm2Name + '] Error addCommand: ' + err); 230 | } 231 | }; 232 | exports.addCustomFunc = function(customFunc) { 233 | try { 234 | customFunc(bot); 235 | } catch (err) { 236 | var time = moment() 237 | .tz('America/Los_Angeles') 238 | .format('MM-DD-YYYY hh:mm a'); 239 | console.log( 240 | '[' + time + ' PST][' + pm2Name + '] Error addCustomFunc: ' + err 241 | ); 242 | bot.channels 243 | .get(logChannel) 244 | .send('[' + time + ' PST][' + pm2Name + '] Error addCustomFunc: ' + err); 245 | } 246 | }; 247 | exports.commandCount = function() { 248 | return Object.keys(commands).length; 249 | }; 250 | 251 | bot.login(config.token); 252 | -------------------------------------------------------------------------------- /bot/modules/bot-uptime.js: -------------------------------------------------------------------------------- 1 | let config = require('config'); 2 | let pm2Name = config.get('moderation').pm2Name; 3 | 4 | exports.commands = ['uptime']; 5 | 6 | exports.uptime = { 7 | usage: '', 8 | description: 'gets Uptime for Bot', 9 | process: function(bot, msg, suffix) { 10 | if (suffix != pm2Name) { 11 | return; 12 | } 13 | msg.channel.send( 14 | 'i have been Online for ' + 15 | Math.round(bot.uptime / (1000 * 60 * 60 * 24)) + 16 | ' days, ' + 17 | Math.round(bot.uptime / (1000 * 60 * 60)) + 18 | ' hours, ' + 19 | Math.round(bot.uptime / (1000 * 60)) % 60 + 20 | ' minutes, and ' + 21 | Math.round(bot.uptime / 1000) % 60 + 22 | ' seconds' 23 | ); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /bot/modules/dogeTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('doge').config; 9 | let paytxfee = config.get('doge').paytxfee; 10 | const doge = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tipdoge']; 13 | exports.tipdoge = { 14 | usage: '', 15 | description: 16 | '__**Dogecoin (DOGE) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipdoge** : Displays This Message\n **!tipdoge balance** : get your balance\n **!tipdoge deposit** : get address for your deposits\n **!tipdoge withdraw
** : withdraw coins to specified address\n **!tipdoge <@user> ** :mention a user with @ and then the amount to tip them\n **!tipdoge private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**Dogecoin (DOGE) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipdoge** : Displays This Message\n **!tipdoge balance** : get your balance\n **!tipdoge deposit** : get address for your deposits\n **!tipdoge withdraw
** : withdraw coins to specified address\n **!tipdoge <@user> ** :mention a user with @ and then the amount to tip them\n **!tipdoge private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | doge.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting Dogecoin (DOGE) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:Dogecoin (DOGE) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your Dogecoin (DOGE) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:Dogecoin (DOGE) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Dogecoin (DOGE)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | doge.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting Dogecoin (DOGE) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Dogecoin (DOGE) for transaction fees!'); 130 | return; 131 | } 132 | doge.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:Dogecoin (DOGE) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Dogecoin (DOGE)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | doge.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting Dogecoin (DOGE) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Dogecoin (DOGE) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendDOGE(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendDOGE(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | doge.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:Dogecoin (DOGE) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:Dogecoin (DOGE) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tipdoge private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:Dogecoin (DOGE) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | doge.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | doge.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('doge')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'https://dogechain.info/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'https://dogechain.info/address/' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/modules/exampleTipper.js: -------------------------------------------------------------------------------- 1 | /* 2 | Simply find and replace instances below with the coin and symbol you want to use! 3 | search and replace with case sensitivity!! 4 | example: 5 | 1. Litecoin = Ethereum 6 | 2. ltc = eth 7 | 3. LTC = ETH 8 | 4. http://Explorer-Url/tx/ 9 | 5. http://Explorer-Url/address/ 10 | */ 11 | 12 | /* 13 | 'use strict'; 14 | 15 | const bitcoin = require('bitcoin'); 16 | 17 | let Regex = require('regex'), 18 | config = require('config'), 19 | spamchannels = config.get('moderation').botspamchannels; 20 | let walletConfig = config.get('ltc').config; 21 | let paytxfee = config.get('ltc').paytxfee; 22 | const ltc = new bitcoin.Client(walletConfig); 23 | 24 | exports.commands = ['tipltc']; 25 | exports.tipltc = { 26 | usage: '', 27 | description: 28 | '__**Litecoin (LTC) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipltc** : Displays This Message\n **!tipltc balance** : get your balance\n **!tipltc deposit** : get address for your deposits\n **!tipltc withdraw
** : withdraw coins to specified address\n **!tipltc <@user> ** :mention a user with @ and then the amount to tip them\n **!tipltc private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 29 | process: async function(bot, msg, suffix) { 30 | let tipper = msg.author.id.replace('!', ''), 31 | words = msg.content 32 | .trim() 33 | .split(' ') 34 | .filter(function(n) { 35 | return n !== ''; 36 | }), 37 | subcommand = words.length >= 2 ? words[1] : 'help', 38 | helpmsg = 39 | '__**Litecoin (LTC) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipltc** : Displays This Message\n **!tipltc balance** : get your balance\n **!tipltc deposit** : get address for your deposits\n **!tipltc withdraw
** : withdraw coins to specified address\n **!tipltc <@user> ** :mention a user with @ and then the amount to tip them\n **!tipltc private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 40 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 41 | switch (subcommand) { 42 | case 'help': 43 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 44 | break; 45 | case 'balance': 46 | doBalance(msg, tipper); 47 | break; 48 | case 'deposit': 49 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 50 | break; 51 | case 'withdraw': 52 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 53 | break; 54 | default: 55 | doTip(bot, msg, tipper, words, helpmsg); 56 | } 57 | } 58 | }; 59 | 60 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 61 | if (!inPrivateorSpamChannel(message)) { 62 | message.reply(wrongchannelmsg); 63 | return; 64 | } 65 | fn.apply(null, [message, ...args]); 66 | } 67 | 68 | function doHelp(message, helpmsg) { 69 | message.author.send(helpmsg); 70 | } 71 | 72 | function doBalance(message, tipper) { 73 | ltc.getBalance(tipper, 1, function(err, balance) { 74 | if (err) { 75 | message.reply('Error getting Litecoin (LTC) balance.').then(message => message.delete(10000)); 76 | } else { 77 | message.channel.send({ embed: { 78 | description: '**:bank::money_with_wings::moneybag:Litecoin (LTC) Balance!:moneybag::money_with_wings::bank:**', 79 | color: 1363892, 80 | fields: [ 81 | { 82 | name: '__User__', 83 | value: '<@' + message.author.id + '>', 84 | inline: false 85 | }, 86 | { 87 | name: '__Balance__', 88 | value: '**' + balance.toString() + '**', 89 | inline: false 90 | } 91 | ] 92 | } }); 93 | } 94 | }); 95 | } 96 | 97 | function doDeposit(message, tipper) { 98 | getAddress(tipper, function(err, address) { 99 | if (err) { 100 | message.reply('Error getting your Litecoin (LTC) deposit address.').then(message => message.delete(10000)); 101 | } else { 102 | message.channel.send({ embed: { 103 | description: '**:bank::card_index::moneybag:Litecoin (LTC) Address!:moneybag::card_index::bank:**', 104 | color: 1363892, 105 | fields: [ 106 | { 107 | name: '__User__', 108 | value: '<@' + message.author.id + '>', 109 | inline: false 110 | }, 111 | { 112 | name: '__Address__', 113 | value: '**' + address + '**', 114 | inline: false 115 | } 116 | ] 117 | } }); 118 | } 119 | }); 120 | } 121 | 122 | function doWithdraw(message, tipper, words, helpmsg) { 123 | if (words.length < 4) { 124 | doHelp(message, helpmsg); 125 | return; 126 | } 127 | 128 | var address = words[2], 129 | amount = getValidatedAmount(words[3]); 130 | 131 | if (amount === null) { 132 | message.reply("I don't know how to withdraw that much Litecoin (LTC)...").then(message => message.delete(10000)); 133 | return; 134 | } 135 | 136 | ltc.getBalance(tipper, 1, function(err, balance) { 137 | if (err) { 138 | message.reply('Error getting Litecoin (LTC) balance.').then(message => message.delete(10000)); 139 | } else { 140 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 141 | message.channel.send('Please leave atleast ' + paytxfee + ' Litecoin (LTC) for transaction fees!'); 142 | return; 143 | } 144 | ltc.sendFrom(tipper, address, Number(amount), function(err, txId) { 145 | if (err) { 146 | message.reply(err.message).then(message => message.delete(10000)); 147 | } else { 148 | message.channel.send({embed:{ 149 | description: '**:outbox_tray::money_with_wings::moneybag:Litecoin (LTC) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 150 | color: 1363892, 151 | fields: [ 152 | { 153 | name: '__Sender__', 154 | value: '<@' + message.author.id + '>', 155 | inline: true 156 | }, 157 | { 158 | name: '__Receiver__', 159 | value: '**' + address + '**\n' + addyLink(address), 160 | inline: true 161 | }, 162 | { 163 | name: '__txid__', 164 | value: '**' + txId + '**\n' + txLink(txId), 165 | inline: false 166 | }, 167 | { 168 | name: '__Amount__', 169 | value: '**' + amount.toString() + '**', 170 | inline: true 171 | }, 172 | { 173 | name: '__Fee__', 174 | value: '**' + paytxfee.toString() + '**', 175 | inline: true 176 | } 177 | ] 178 | }}); 179 | } 180 | }); 181 | } 182 | }); 183 | } 184 | 185 | function doTip(bot, message, tipper, words, helpmsg) { 186 | if (words.length < 3 || !words) { 187 | doHelp(message, helpmsg); 188 | return; 189 | } 190 | var prv = false; 191 | var amountOffset = 2; 192 | if (words.length >= 4 && words[1] === 'private') { 193 | prv = true; 194 | amountOffset = 3; 195 | } 196 | 197 | let amount = getValidatedAmount(words[amountOffset]); 198 | 199 | if (amount === null) { 200 | message.reply("I don't know how to tip that much Litecoin (LTC)...").then(message => message.delete(10000)); 201 | return; 202 | } 203 | 204 | ltc.getBalance(tipper, 1, function(err, balance) { 205 | if (err) { 206 | message.reply('Error getting Litecoin (LTC) balance.').then(message => message.delete(10000)); 207 | } else { 208 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 209 | message.channel.send('Please leave atleast ' + paytxfee + ' Litecoin (LTC) for transaction fees!'); 210 | return; 211 | } 212 | 213 | if (!message.mentions.users.first()){ 214 | message 215 | .reply('Sorry, I could not find a user in your tip...') 216 | .then(message => message.delete(10000)); 217 | return; 218 | } 219 | if (message.mentions.users.first().id) { 220 | sendLTC(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 221 | } else { 222 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 223 | } 224 | } 225 | }); 226 | } 227 | 228 | function sendLTC(bot, message, tipper, recipient, amount, privacyFlag) { 229 | getAddress(recipient.toString(), function(err, address) { 230 | if (err) { 231 | message.reply(err.message).then(message => message.delete(10000)); 232 | } else { 233 | ltc.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 234 | if (err) { 235 | message.reply(err.message).then(message => message.delete(10000)); 236 | } else { 237 | if (privacyFlag) { 238 | let userProfile = message.guild.members.find('id', recipient); 239 | userProfile.user.send({ embed: { 240 | description: '**:money_with_wings::moneybag:Litecoin (LTC) Transaction Completed!:moneybag::money_with_wings:**', 241 | color: 1363892, 242 | fields: [ 243 | { 244 | name: '__Sender__', 245 | value: 'Private Tipper', 246 | inline: true 247 | }, 248 | { 249 | name: '__Receiver__', 250 | value: '<@' + recipient + '>', 251 | inline: true 252 | }, 253 | { 254 | name: '__txid__', 255 | value: '**' + txId + '**\n' + txLink(txId), 256 | inline: false 257 | }, 258 | { 259 | name: '__Amount__', 260 | value: '**' + amount.toString() + '**', 261 | inline: true 262 | }, 263 | { 264 | name: '__Fee__', 265 | value: '**' + paytxfee.toString() + '**', 266 | inline: true 267 | } 268 | ] 269 | } }); 270 | message.author.send({ embed: { 271 | description: '**:money_with_wings::moneybag:Litecoin (LTC) Transaction Completed!:moneybag::money_with_wings:**', 272 | color: 1363892, 273 | fields: [ 274 | { 275 | name: '__Sender__', 276 | value: '<@' + message.author.id + '>', 277 | inline: true 278 | }, 279 | { 280 | name: '__Receiver__', 281 | value: '<@' + recipient + '>', 282 | inline: true 283 | }, 284 | { 285 | name: '__txid__', 286 | value: '**' + txId + '**\n' + txLink(txId), 287 | inline: false 288 | }, 289 | { 290 | name: '__Amount__', 291 | value: '**' + amount.toString() + '**', 292 | inline: true 293 | }, 294 | { 295 | name: '__Fee__', 296 | value: '**' + paytxfee.toString() + '**', 297 | inline: true 298 | } 299 | 300 | ] 301 | } }); 302 | if ( 303 | message.content.startsWith('!tipltc private ') 304 | ) { 305 | message.delete(1000); //Supposed to delete message 306 | } 307 | } else { 308 | message.channel.send({ embed: { 309 | description: '**:money_with_wings::moneybag:Litecoin (LTC) Transaction Completed!:moneybag::money_with_wings:**', 310 | color: 1363892, 311 | fields: [ 312 | { 313 | name: '__Sender__', 314 | value: '<@' + message.author.id + '>', 315 | inline: true 316 | }, 317 | { 318 | name: '__Receiver__', 319 | value: '<@' + recipient + '>', 320 | inline: true 321 | }, 322 | { 323 | name: '__txid__', 324 | value: '**' + txId + '**\n' + txLink(txId), 325 | inline: false 326 | }, 327 | { 328 | name: '__Amount__', 329 | value: '**' + amount.toString() + '**', 330 | inline: true 331 | }, 332 | { 333 | name: '__Fee__', 334 | value: '**' + paytxfee.toString() + '**', 335 | inline: true 336 | } 337 | ] 338 | } }); 339 | } 340 | } 341 | }); 342 | } 343 | }); 344 | } 345 | 346 | function getAddress(userId, cb) { 347 | ltc.getAddressesByAccount(userId, function(err, addresses) { 348 | if (err) { 349 | cb(err); 350 | } else if (addresses.length > 0) { 351 | cb(null, addresses[0]); 352 | } else { 353 | ltc.getNewAddress(userId, function(err, address) { 354 | if (err) { 355 | cb(err); 356 | } else { 357 | cb(null, address); 358 | } 359 | }); 360 | } 361 | }); 362 | } 363 | 364 | function inPrivateorSpamChannel(msg) { 365 | if (msg.channel.type == 'dm' || isSpam(msg)) { 366 | return true; 367 | } else { 368 | return false; 369 | } 370 | } 371 | 372 | function isSpam(msg) { 373 | return spamchannels.includes(msg.channel.id); 374 | }; 375 | 376 | 377 | function getValidatedAmount(amount) { 378 | amount = amount.trim(); 379 | if (amount.toLowerCase().endsWith('ltc')) { 380 | amount = amount.substring(0, amount.length - 3); 381 | } 382 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 383 | } 384 | 385 | function txLink(txId) { 386 | return 'http://Explorer-Url/tx/' + txId; 387 | } 388 | 389 | function addyLink(address) { 390 | return 'http://Explorer-Url/address/' + address; 391 | } 392 | */ 393 | -------------------------------------------------------------------------------- /bot/modules/ftcTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('ftc').config; 9 | let paytxfee = config.get('ftc').paytxfee; 10 | const ftc = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tipftc']; 13 | exports.tipftc = { 14 | usage: '', 15 | description: 16 | '__**Feathercoin (FTC) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipftc** : Displays This Message\n **!tipftc balance** : get your balance\n **!tipftc deposit** : get address for your deposits\n **!tipftc withdraw
** : withdraw coins to specified address\n **!tipftc <@user> ** :mention a user with @ and then the amount to tip them\n **!tipftc private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**Feathercoin (FTC) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipftc** : Displays This Message\n **!tipftc balance** : get your balance\n **!tipftc deposit** : get address for your deposits\n **!tipftc withdraw
** : withdraw coins to specified address\n **!tipftc <@user> ** :mention a user with @ and then the amount to tip them\n **!tipftc private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | ftc.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting Feathercoin (FTC) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:Feathercoin (FTC) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your Feathercoin (FTC) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:Feathercoin (FTC) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Feathercoin (FTC)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | ftc.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting Feathercoin (FTC) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Feathercoin (FTC) for transaction fees!'); 130 | return; 131 | } 132 | ftc.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:Feathercoin (FTC) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Feathercoin (FTC)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | ftc.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting Feathercoin (FTC) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Feathercoin (FTC) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendFTC(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendFTC(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | ftc.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:Feathercoin (FTC) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:Feathercoin (FTC) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tipftc private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:Feathercoin (FTC) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | ftc.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | ftc.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('ftc')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'https://explorer.feathercoin.com/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'https://explorer.feathercoin.com/address/' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/modules/helpTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let config = require('config'); 3 | let ravenFee = config.get('rvn').paytxfee; 4 | let dogeFee = config.get('doge').paytxfee; 5 | let lbryFee = config.get('lbc').paytxfee; 6 | let phaseFee = config.get('phase').paytxfee; 7 | let ufoFee = config.get('ufo').paytxfee; 8 | let phoenixFee = config.get('pxc').paytxfee; 9 | let featherFee = config.get('ftc').paytxfee; 10 | let verticalFee = config.get('vtl').paytxfee; 11 | let neblioFee = config.get('nebl').paytxfee; 12 | let xuezFee = config.get('xuez').paytxfee; 13 | let spkFee = config.get('spk').paytxfee; 14 | let ppcFee = config.get('ppc').paytxfee; 15 | let prefix = config.get('bot').prefix; 16 | exports.commands = ['tiphelp']; 17 | exports.tiphelp = { 18 | usage: '', 19 | description: 'This commands has been changed to currency specific commands!', 20 | process: function(bot, message) { 21 | message.author.send( 22 | '__**:bank: Coins :bank:**__\n' + 23 | ' **Ravencoin (RVN) Tipper**\n Transaction Fees: **' + ravenFee + '**\n' + 24 | ' **Dogecoin (DOGE) Tipper**\n Transaction Fees: **' + dogeFee + '**\n' + 25 | ' **LBRY Credit (LBC) Tipper**\n Transaction Fees: **' + lbryFee + '**\n' + 26 | ' **Phase (PHASE) Tipper**\n Transaction Fees: **' + phaseFee + '**\n' + 27 | ' **Uniform Fiscal Object (UFO) Tipper**\n Transaction Fees: **' + ufoFee + '**\n' + 28 | ' **Phoenixcoin (PXC) Tipper**\n Transaction Fees: **' + phoenixFee + '**\n' + 29 | ' **Feathercoin (FTC) Tipper**\n Transaction Fees: **' + featherFee + '**\n' + 30 | ' **Vertical (VTL) Tipper**\n Transaction Fees: **' + verticalFee + '**\n' + 31 | ' **Neblio (NEBL) Tipper**\n Transaction Fees: **' + neblioFee + '**\n' + 32 | ' **Xuez (XUEZ) Tipper**\n Transaction Fees: **' + xuezFee + '**\n' + 33 | ' **SparksPay (SPK) Tipper**\n Transaction Fees: **' + spkFee + '**\n' + 34 | ' **Peercoin (PPC) Tipper**\n Transaction Fees: **' + ppcFee + '**\n' + 35 | '__**Commands**__\n' + 36 | ' **' + prefix + 'tip** : Displays This Message\n' + 37 | ' **' + prefix + 'tip balance** : get your balance\n' + 38 | ' **' + prefix + 'tip deposit** : get address for your deposits\n' + 39 | ' **' + prefix + 'tip withdraw
** : withdraw coins to specified address\n' + 40 | ' **' + prefix + 'tip <@user> ** :mention a user with @ and then the amount to tip them\n' + 41 | ' **' + prefix + 'tip private ** : put private before Mentioning a user to tip them privately\n' + 42 | '**<> : Replace carrot <> symbole with appropriate value.**\n' + 43 | '__**Examples**__\n' + 44 | ' **' + prefix + 'tiprvn @MSFTserver 10**\n' + 45 | ' **' + prefix + 'tipdoge withdraw DOGEaddressHERE 10**\n' + 46 | ' **' + prefix + 'tipftc private @MSFTserver 10**\n' + 47 | ' **' + prefix + 'tiplbc balance**\n' + 48 | ' **' + prefix + 'tippxc deposit**\n' 49 | ); 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /bot/modules/lbcTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('lbc').config; 9 | let paytxfee = config.get('lbc').paytxfee; 10 | const lbc = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tiplbc']; 13 | exports.tiplbc = { 14 | usage: '', 15 | description: 16 | '__**LBRY Credit (LBC) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tiplbc** : Displays This Message\n **!tiplbc balance** : get your balance\n **!tiplbc deposit** : get address for your deposits\n **!tiplbc withdraw
** : withdraw coins to specified address\n **!tiplbc <@user> ** :mention a user with @ and then the amount to tip them\n **!tiplbc private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**LBRY Credit (LBC) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tiplbc** : Displays This Message\n **!tiplbc balance** : get your balance\n **!tiplbc deposit** : get address for your deposits\n **!tiplbc withdraw
** : withdraw coins to specified address\n **!tiplbc <@user> ** :mention a user with @ and then the amount to tip them\n **!tiplbc private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | lbc.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting LBRY Credit (LBC) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:LBRY Credit (LBC) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your LBRY Credit (LBC) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:LBRY Credit (LBC) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much LBRY Credit (LBC)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | lbc.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting LBRY Credit (LBC) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' LBRY Credit (LBC) for transaction fees!'); 130 | return; 131 | } 132 | lbc.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:LBRY Credit (LBC) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much LBRY Credit (LBC)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | lbc.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting LBRY Credit (LBC) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' LBRY Credit (LBC) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendLBC(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendLBC(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | lbc.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:LBRY Credit (LBC) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:LBRY Credit (LBC) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tiplbc private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:LBRY Credit (LBC) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | lbc.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | lbc.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('lbc')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'https://explorer.lbry.io/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'https://explorer.lbry.io/address/' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/modules/neblTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('nebl').config; 9 | let paytxfee = config.get('nebl').paytxfee; 10 | const nebl = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tipnebl']; 13 | exports.tipnebl = { 14 | usage: '', 15 | description: 16 | '__**Neblio (NEBL) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipnebl** : Displays This Message\n **!tipnebl balance** : get your balance\n **!tipnebl deposit** : get address for your deposits\n **!tipnebl withdraw
** : withdraw coins to specified address\n **!tipnebl <@user> ** :mention a user with @ and then the amount to tip them\n **!tipnebl private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**Neblio (NEBL) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipnebl** : Displays This Message\n **!tipnebl balance** : get your balance\n **!tipnebl deposit** : get address for your deposits\n **!tipnebl withdraw
** : withdraw coins to specified address\n **!tipnebl <@user> ** :mention a user with @ and then the amount to tip them\n **!tipnebl private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | nebl.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting Neblio (NEBL) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:Neblio (NEBL) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your Neblio (NEBL) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:Neblio (NEBL) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Neblio (NEBL)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | nebl.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting Neblio (NEBL) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Neblio (NEBL) for transaction fees!'); 130 | return; 131 | } 132 | nebl.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:Neblio (NEBL) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Neblio (NEBL)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | nebl.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting Neblio (NEBL) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Neblio (NEBL) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendNEBL(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendNEBL(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | nebl.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:Neblio (NEBL) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:Neblio (NEBL) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tipnebl private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:Neblio (NEBL) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | nebl.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | nebl.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('nebl')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'https://explorer.nebl.io/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'https://explorer.nebl.io/address/' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/modules/phaseTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('phase').config; 9 | let paytxfee = config.get('phase').paytxfee; 10 | const phase = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tipphase']; 13 | exports.tipphase = { 14 | usage: '', 15 | description: 16 | '__**Phase (PHASE) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipphase** : Displays This Message\n **!tipphase balance** : get your balance\n **!tipphase deposit** : get address for your deposits\n **!tipphase withdraw
** : withdraw coins to specified address\n **!tipphase <@user> ** :mention a user with @ and then the amount to tip them\n **!tipphase private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**Phase (PHASE) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipphase** : Displays This Message\n **!tipphase balance** : get your balance\n **!tipphase deposit** : get address for your deposits\n **!tipphase withdraw
** : withdraw coins to specified address\n **!tipphase <@user> ** :mention a user with @ and then the amount to tip them\n **!tipphase private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | phase.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting Phase (PHASE) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:Phase (PHASE) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your Phase (PHASE) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:Phase (PHASE) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Phase (PHASE)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | phase.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting Phase (PHASE) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Phase (PHASE) for transaction fees!'); 130 | return; 131 | } 132 | phase.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:Phase (PHASE) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Phase (PHASE)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | phase.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting Phase (PHASE) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Phase (PHASE) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendPHASE(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendPHASE(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | phase.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:Phase (PHASE) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:Phase (PHASE) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tipphase private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:Phase (PHASE) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | phase.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | phase.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('phase')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'http://80.211.25.138:3001/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'http://80.211.25.138:3001/address/' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/modules/ppcTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('ppc').config; 9 | let paytxfee = config.get('ppc').paytxfee; 10 | const ppc = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tipppc']; 13 | exports.tipppc = { 14 | usage: '', 15 | description: 16 | '__**Peercoin (PPC) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipppc** : Displays This Message\n **!tipppc balance** : get your balance\n **!tipppc deposit** : get address for your deposits\n **!tipppc withdraw
** : withdraw coins to specified address\n **!tipppc <@user> ** :mention a user with @ and then the amount to tip them\n **!tipppc private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**Peercoin (LTC) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipppc** : Displays This Message\n **!tipppc balance** : get your balance\n **!tipppc deposit** : get address for your deposits\n **!tipppc withdraw
** : withdraw coins to specified address\n **!tipppc <@user> ** :mention a user with @ and then the amount to tip them\n **!tipppc private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | ppc.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting Peercoin (PPC) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:Peercoin (PPC) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your Peercoin (PPC) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:Peercoin (PPC) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Peercoin (PPC)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | ppc.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting Peercoin (PPC) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Peercoin (PPC) for transaction fees!'); 130 | return; 131 | } 132 | ppc.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:Peercoin (PPC) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Peercoin (PPC)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | ppc.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting Peercoin (PPC) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Peercoin (PPC) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendPPC(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendPPC(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | ppc.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:Peercoin (PPC) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:Peercoin (PPC) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tipppc private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:Peercoin (PPC) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | ppc.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | ppc.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('ppc')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'https://explorer.peercoin.net/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'https://explorer.peercoin.net/address/' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/modules/pxcTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('pxc').config; 9 | let paytxfee = config.get('pxc').paytxfee; 10 | const pxc = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tippxc']; 13 | exports.tippxc = { 14 | usage: '', 15 | description: 16 | '__**Phoenixcoin (PXC) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tippxc** : Displays This Message\n **!tippxc balance** : get your balance\n **!tippxc deposit** : get address for your deposits\n **!tippxc withdraw
** : withdraw coins to specified address\n **!tippxc <@user> ** :mention a user with @ and then the amount to tip them\n **!tippxc private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**Phoenixcoin (PXC) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tippxc** : Displays This Message\n **!tippxc balance** : get your balance\n **!tippxc deposit** : get address for your deposits\n **!tippxc withdraw
** : withdraw coins to specified address\n **!tippxc <@user> ** :mention a user with @ and then the amount to tip them\n **!tippxc private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | pxc.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting Phoenixcoin (PXC) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:Phoenixcoin (PXC) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your Phoenixcoin (PXC) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:Phoenixcoin (PXC) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Phoenixcoin (PXC)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | pxc.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting Phoenixcoin (PXC) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Phoenixcoin (PXC) for transaction fees!'); 130 | return; 131 | } 132 | pxc.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:Phoenixcoin (PXC) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Phoenixcoin (PXC)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | pxc.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting Phoenixcoin (PXC) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Phoenixcoin (PXC) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendPXC(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendPXC(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | pxc.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:Phoenixcoin (PXC) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:Phoenixcoin (PXC) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tippxc private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:Phoenixcoin (PXC) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | pxc.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | pxc.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('pxc')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'http://explorer.phoenixcoin.org/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'http://explorer.phoenixcoin.org/address/' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/modules/rvnTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('rvn').config; 9 | let paytxfee = config.get('rvn').paytxfee; 10 | const rvn = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tiprvn']; 13 | exports.tiprvn = { 14 | usage: '', 15 | description: 16 | '__**Ravencoin (RVN) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tiprvn** : Displays This Message\n **!tiprvn balance** : get your balance\n **!tiprvn deposit** : get address for your deposits\n **!tiprvn withdraw
** : withdraw coins to specified address\n **!tiprvn <@user> ** :mention a user with @ and then the amount to tip them\n **!tiprvn private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**Ravencoin (RVN) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tiprvn** : Displays This Message\n **!tiprvn balance** : get your balance\n **!tiprvn deposit** : get address for your deposits\n **!tiprvn withdraw
** : withdraw coins to specified address\n **!tiprvn <@user> ** :mention a user with @ and then the amount to tip them\n **!tiprvn private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | rvn.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting Ravencoin (RVN) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:Ravencoin (RVN) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your Ravencoin (RVN) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:Ravencoin (RVN) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Ravencoin (RVN)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | rvn.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting Ravencoin (RVN) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Ravencoin (RVN) for transaction fees!'); 130 | return; 131 | } 132 | rvn.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:Ravencoin (RVN) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Ravencoin (RVN)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | rvn.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting Ravencoin (RVN) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Ravencoin (RVN) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendRVN(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendRVN(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | rvn.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:Ravencoin (RVN) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:Ravencoin (RVN) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tiprvn private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:Ravencoin (RVN) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | rvn.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | rvn.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('rvn')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'https://ravencoin.network/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'https://ravencoin.network/address/' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/modules/spkTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('spk').config; 9 | let paytxfee = config.get('spk').paytxfee; 10 | const spk = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tipspk']; 13 | exports.tipspk = { 14 | usage: '', 15 | description: 16 | '__**SparksPay (SPK) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipspk** : Displays This Message\n **!tipspk balance** : get your balance\n **!tipspk deposit** : get address for your deposits\n **!tipspk withdraw
** : withdraw coins to specified address\n **!tipspk <@user> ** :mention a user with @ and then the amount to tip them\n **!tipspk private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**SparksPay (SPK) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipspk** : Displays This Message\n **!tipspk balance** : get your balance\n **!tipspk deposit** : get address for your deposits\n **!tipspk withdraw
** : withdraw coins to specified address\n **!tipspk <@user> ** :mention a user with @ and then the amount to tip them\n **!tipspk private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | spk.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting SparksPay (SPK) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:SparksPay (SPK) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your SparksPay (SPK) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:SparksPay (SPK) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Sparks (SPK)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | spk.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting SparksPay (SPK) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Sparks (SPK) for transaction fees!'); 130 | return; 131 | } 132 | spk.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:SparksPay (SPK) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Sparks (SPK)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | spk.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting SparksPay (SPK) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Sparks (SPK) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendSPK(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendSPK(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | spk.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:SparksPay (SPK) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:SparksPay (SPK) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tipspk private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:SparksPay (SPK) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | spk.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | spk.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('spk')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'http://explorer.sparkspay.io/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'http://explorer.sparkspay.io/address/' + address; 379 | } -------------------------------------------------------------------------------- /bot/modules/ufoTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('ufo').config; 9 | let paytxfee = config.get('ufo').paytxfee; 10 | const ufo = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tipufo']; 13 | exports.tipufo = { 14 | usage: '', 15 | description: 16 | '__**Uniform Fiscal Object (UFO) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipufo** : Displays This Message\n **!tipufo balance** : get your balance\n **!tipufo deposit** : get address for your deposits\n **!tipufo withdraw
** : withdraw coins to specified address\n **!tipufo <@user> ** :mention a user with @ and then the amount to tip them\n **!tipufo private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**Uniform Fiscal Object (UFO) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipufo** : Displays This Message\n **!tipufo balance** : get your balance\n **!tipufo deposit** : get address for your deposits\n **!tipufo withdraw
** : withdraw coins to specified address\n **!tipufo <@user> ** :mention a user with @ and then the amount to tip them\n **!tipufo private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | ufo.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting Uniform Fiscal Object (UFO) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:Uniform Fiscal Object (UFO) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your Uniform Fiscal Object (UFO) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:Uniform Fiscal Object (UFO) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Uniform Fiscal Object (UFO)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | ufo.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting Uniform Fiscal Object (UFO) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Uniform Fiscal Object (UFO) for transaction fees!'); 130 | return; 131 | } 132 | ufo.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:Uniform Fiscal Object (UFO) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Uniform Fiscal Object (UFO)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | ufo.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting Uniform Fiscal Object (UFO) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Uniform Fiscal Object (UFO) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendUFO(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendUFO(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | ufo.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:Uniform Fiscal Object (UFO) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:Uniform Fiscal Object (UFO) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tipufo private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:Uniform Fiscal Object (UFO) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | ufo.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | ufo.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('ufo')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'https://chainz.cryptoid.info/ufo/tx.dws?' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'https://chainz.cryptoid.info/ufo/address.dws?' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/modules/vtlTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('vtl').config; 9 | let paytxfee = config.get('vtl').paytxfee; 10 | const vtl = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tipvtl']; 13 | exports.tipvtl = { 14 | usage: '', 15 | description: 16 | '__**Vertical (VTL) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipvtl** : Displays This Message\n **!tipvtl balance** : get your balance\n **!tipvtl deposit** : get address for your deposits\n **!tipvtl withdraw
** : withdraw coins to specified address\n **!tipvtl <@user> ** :mention a user with @ and then the amount to tip them\n **!tipvtl private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**Vertical (VTL) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipvtl** : Displays This Message\n **!tipvtl balance** : get your balance\n **!tipvtl deposit** : get address for your deposits\n **!tipvtl withdraw
** : withdraw coins to specified address\n **!tipvtl <@user> ** :mention a user with @ and then the amount to tip them\n **!tipvtl private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | vtl.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting Vertical (VTL) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:Vertical (VTL) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your Vertical (VTL) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:Vertical (VTL) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Vertical (VTL)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | vtl.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting Vertical (VTL) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Vertical (VTL) for transaction fees!'); 130 | return; 131 | } 132 | vtl.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:Vertical (VTL) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Vertical (VTL)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | vtl.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting Vertical (VTL) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Vertical (VTL) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendVTL(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendVTL(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | vtl.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:Vertical (VTL) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:Vertical (VTL) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tipvtl private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:Vertical (VTL) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | vtl.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | vtl.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('vtl')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'https://explorer.vertical.ovh/#/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'https://explorer.vertical.ovh/#/address/' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/modules/xuezTipper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bitcoin = require('bitcoin'); 4 | 5 | let Regex = require('regex'), 6 | config = require('config'), 7 | spamchannels = config.get('moderation').botspamchannels; 8 | let walletConfig = config.get('xuez').config; 9 | let paytxfee = config.get('xuez').paytxfee; 10 | const xuez = new bitcoin.Client(walletConfig); 11 | 12 | exports.commands = ['tipxuez']; 13 | exports.tipxuez = { 14 | usage: '', 15 | description: 16 | '__**Xuez (XUEZ) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipxuez** : Displays This Message\n **!tipxuez balance** : get your balance\n **!tipxuez deposit** : get address for your deposits\n **!tipxuez withdraw
** : withdraw coins to specified address\n **!tipxuez <@user> ** :mention a user with @ and then the amount to tip them\n **!tipxuez private ** : put private before Mentioning a user to tip them privately.\n\n has a default txfee of ' + paytxfee, 17 | process: async function(bot, msg, suffix) { 18 | let tipper = msg.author.id.replace('!', ''), 19 | words = msg.content 20 | .trim() 21 | .split(' ') 22 | .filter(function(n) { 23 | return n !== ''; 24 | }), 25 | subcommand = words.length >= 2 ? words[1] : 'help', 26 | helpmsg = 27 | '__**Xuez (xuez) Tipper**__\nTransaction Fees: **' + paytxfee + '**\n **!tipxuez** : Displays This Message\n **!tipxuez balance** : get your balance\n **!tipxuez deposit** : get address for your deposits\n **!tipxuez withdraw
** : withdraw coins to specified address\n **!tipxuez <@user> ** :mention a user with @ and then the amount to tip them\n **!tipxuez private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', 28 | channelwarning = 'Please use <#bot-spam> or DMs to talk to bots.'; 29 | switch (subcommand) { 30 | case 'help': 31 | privateorSpamChannel(msg, channelwarning, doHelp, [helpmsg]); 32 | break; 33 | case 'balance': 34 | doBalance(msg, tipper); 35 | break; 36 | case 'deposit': 37 | privateorSpamChannel(msg, channelwarning, doDeposit, [tipper]); 38 | break; 39 | case 'withdraw': 40 | privateorSpamChannel(msg, channelwarning, doWithdraw, [tipper, words, helpmsg]); 41 | break; 42 | default: 43 | doTip(bot, msg, tipper, words, helpmsg); 44 | } 45 | } 46 | }; 47 | 48 | function privateorSpamChannel(message, wrongchannelmsg, fn, args) { 49 | if (!inPrivateorSpamChannel(message)) { 50 | message.reply(wrongchannelmsg); 51 | return; 52 | } 53 | fn.apply(null, [message, ...args]); 54 | } 55 | 56 | function doHelp(message, helpmsg) { 57 | message.author.send(helpmsg); 58 | } 59 | 60 | function doBalance(message, tipper) { 61 | xuez.getBalance(tipper, 1, function(err, balance) { 62 | if (err) { 63 | message.reply('Error getting Xuez (XUEZ) balance.').then(message => message.delete(10000)); 64 | } else { 65 | message.channel.send({ embed: { 66 | description: '**:bank::money_with_wings::moneybag:Xuez (XUEZ) Balance!:moneybag::money_with_wings::bank:**', 67 | color: 1363892, 68 | fields: [ 69 | { 70 | name: '__User__', 71 | value: '<@' + message.author.id + '>', 72 | inline: false 73 | }, 74 | { 75 | name: '__Balance__', 76 | value: '**' + balance.toString() + '**', 77 | inline: false 78 | } 79 | ] 80 | } }); 81 | } 82 | }); 83 | } 84 | 85 | function doDeposit(message, tipper) { 86 | getAddress(tipper, function(err, address) { 87 | if (err) { 88 | message.reply('Error getting your Xuez (XUEZ) deposit address.').then(message => message.delete(10000)); 89 | } else { 90 | message.channel.send({ embed: { 91 | description: '**:bank::card_index::moneybag:Xuez (XUEZ) Address!:moneybag::card_index::bank:**', 92 | color: 1363892, 93 | fields: [ 94 | { 95 | name: '__User__', 96 | value: '<@' + message.author.id + '>', 97 | inline: false 98 | }, 99 | { 100 | name: '__Address__', 101 | value: '**' + address + '**', 102 | inline: false 103 | } 104 | ] 105 | } }); 106 | } 107 | }); 108 | } 109 | 110 | function doWithdraw(message, tipper, words, helpmsg) { 111 | if (words.length < 4) { 112 | doHelp(message, helpmsg); 113 | return; 114 | } 115 | 116 | var address = words[2], 117 | amount = getValidatedAmount(words[3]); 118 | 119 | if (amount === null) { 120 | message.reply("I don't know how to withdraw that much Xuez (XUEZ)...").then(message => message.delete(10000)); 121 | return; 122 | } 123 | 124 | xuez.getBalance(tipper, 1, function(err, balance) { 125 | if (err) { 126 | message.reply('Error getting Xuez (XUEZ) balance.').then(message => message.delete(10000)); 127 | } else { 128 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 129 | message.channel.send('Please leave atleast ' + paytxfee + ' Xuez (XUEZ) for transaction fees!'); 130 | return; 131 | } 132 | xuez.sendFrom(tipper, address, Number(amount), function(err, txId) { 133 | if (err) { 134 | message.reply(err.message).then(message => message.delete(10000)); 135 | } else { 136 | message.channel.send({embed:{ 137 | description: '**:outbox_tray::money_with_wings::moneybag:Xuez (XUEZ) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', 138 | color: 1363892, 139 | fields: [ 140 | { 141 | name: '__Sender__', 142 | value: '<@' + message.author.id + '>', 143 | inline: true 144 | }, 145 | { 146 | name: '__Receiver__', 147 | value: '**' + address + '**\n' + addyLink(address), 148 | inline: true 149 | }, 150 | { 151 | name: '__txid__', 152 | value: '**' + txId + '**\n' + txLink(txId), 153 | inline: false 154 | }, 155 | { 156 | name: '__Amount__', 157 | value: '**' + amount.toString() + '**', 158 | inline: true 159 | }, 160 | { 161 | name: '__Fee__', 162 | value: '**' + paytxfee.toString() + '**', 163 | inline: true 164 | } 165 | ] 166 | }}); 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | 173 | function doTip(bot, message, tipper, words, helpmsg) { 174 | if (words.length < 3 || !words) { 175 | doHelp(message, helpmsg); 176 | return; 177 | } 178 | var prv = false; 179 | var amountOffset = 2; 180 | if (words.length >= 4 && words[1] === 'private') { 181 | prv = true; 182 | amountOffset = 3; 183 | } 184 | 185 | let amount = getValidatedAmount(words[amountOffset]); 186 | 187 | if (amount === null) { 188 | message.reply("I don't know how to tip that much Xuez (XUEZ)...").then(message => message.delete(10000)); 189 | return; 190 | } 191 | 192 | xuez.getBalance(tipper, 1, function(err, balance) { 193 | if (err) { 194 | message.reply('Error getting Xuez (XUEZ) balance.').then(message => message.delete(10000)); 195 | } else { 196 | if (Number(amount) + Number(paytxfee) > Number(balance)) { 197 | message.channel.send('Please leave atleast ' + paytxfee + ' Xuez (XUEZ) for transaction fees!'); 198 | return; 199 | } 200 | 201 | if (!message.mentions.users.first()){ 202 | message 203 | .reply('Sorry, I could not find a user in your tip...') 204 | .then(message => message.delete(10000)); 205 | return; 206 | } 207 | if (message.mentions.users.first().id) { 208 | sendXUEZ(bot, message, tipper, message.mentions.users.first().id.replace('!', ''), amount, prv); 209 | } else { 210 | message.reply('Sorry, I could not find a user in your tip...').then(message => message.delete(10000)); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | function sendXUEZ(bot, message, tipper, recipient, amount, privacyFlag) { 217 | getAddress(recipient.toString(), function(err, address) { 218 | if (err) { 219 | message.reply(err.message).then(message => message.delete(10000)); 220 | } else { 221 | xuez.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { 222 | if (err) { 223 | message.reply(err.message).then(message => message.delete(10000)); 224 | } else { 225 | if (privacyFlag) { 226 | let userProfile = message.guild.members.find('id', recipient); 227 | userProfile.user.send({ embed: { 228 | description: '**:money_with_wings::moneybag:Xuez (XUEZ) Transaction Completed!:moneybag::money_with_wings:**', 229 | color: 1363892, 230 | fields: [ 231 | { 232 | name: '__Sender__', 233 | value: 'Private Tipper', 234 | inline: true 235 | }, 236 | { 237 | name: '__Receiver__', 238 | value: '<@' + recipient + '>', 239 | inline: true 240 | }, 241 | { 242 | name: '__txid__', 243 | value: '**' + txId + '**\n' + txLink(txId), 244 | inline: false 245 | }, 246 | { 247 | name: '__Amount__', 248 | value: '**' + amount.toString() + '**', 249 | inline: true 250 | }, 251 | { 252 | name: '__Fee__', 253 | value: '**' + paytxfee.toString() + '**', 254 | inline: true 255 | } 256 | ] 257 | } }); 258 | message.author.send({ embed: { 259 | description: '**:money_with_wings::moneybag:Xuez (XUEZ) Transaction Completed!:moneybag::money_with_wings:**', 260 | color: 1363892, 261 | fields: [ 262 | { 263 | name: '__Sender__', 264 | value: '<@' + message.author.id + '>', 265 | inline: true 266 | }, 267 | { 268 | name: '__Receiver__', 269 | value: '<@' + recipient + '>', 270 | inline: true 271 | }, 272 | { 273 | name: '__txid__', 274 | value: '**' + txId + '**\n' + txLink(txId), 275 | inline: false 276 | }, 277 | { 278 | name: '__Amount__', 279 | value: '**' + amount.toString() + '**', 280 | inline: true 281 | }, 282 | { 283 | name: '__Fee__', 284 | value: '**' + paytxfee.toString() + '**', 285 | inline: true 286 | } 287 | 288 | ] 289 | } }); 290 | if ( 291 | message.content.startsWith('!tipxuez private ') 292 | ) { 293 | message.delete(1000); //Supposed to delete message 294 | } 295 | } else { 296 | message.channel.send({ embed: { 297 | description: '**:money_with_wings::moneybag:Xuez (XUEZ) Transaction Completed!:moneybag::money_with_wings:**', 298 | color: 1363892, 299 | fields: [ 300 | { 301 | name: '__Sender__', 302 | value: '<@' + message.author.id + '>', 303 | inline: true 304 | }, 305 | { 306 | name: '__Receiver__', 307 | value: '<@' + recipient + '>', 308 | inline: true 309 | }, 310 | { 311 | name: '__txid__', 312 | value: '**' + txId + '**\n' + txLink(txId), 313 | inline: false 314 | }, 315 | { 316 | name: '__Amount__', 317 | value: '**' + amount.toString() + '**', 318 | inline: true 319 | }, 320 | { 321 | name: '__Fee__', 322 | value: '**' + paytxfee.toString() + '**', 323 | inline: true 324 | } 325 | ] 326 | } }); 327 | } 328 | } 329 | }); 330 | } 331 | }); 332 | } 333 | 334 | function getAddress(userId, cb) { 335 | xuez.getAddressesByAccount(userId, function(err, addresses) { 336 | if (err) { 337 | cb(err); 338 | } else if (addresses.length > 0) { 339 | cb(null, addresses[0]); 340 | } else { 341 | xuez.getNewAddress(userId, function(err, address) { 342 | if (err) { 343 | cb(err); 344 | } else { 345 | cb(null, address); 346 | } 347 | }); 348 | } 349 | }); 350 | } 351 | 352 | function inPrivateorSpamChannel(msg) { 353 | if (msg.channel.type == 'dm' || isSpam(msg)) { 354 | return true; 355 | } else { 356 | return false; 357 | } 358 | } 359 | 360 | function isSpam(msg) { 361 | return spamchannels.includes(msg.channel.id); 362 | }; 363 | 364 | 365 | function getValidatedAmount(amount) { 366 | amount = amount.trim(); 367 | if (amount.toLowerCase().endsWith('xuez')) { 368 | amount = amount.substring(0, amount.length - 3); 369 | } 370 | return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; 371 | } 372 | 373 | function txLink(txId) { 374 | return 'http://xuez.donkeypool.com/tx/' + txId; 375 | } 376 | 377 | function addyLink(address) { 378 | return 'http://xuez.donkeypool.com/address/' + address; 379 | } 380 | -------------------------------------------------------------------------------- /bot/plugins.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'), 4 | path = require('path'); 5 | 6 | function getPlugins(srcpath) { 7 | return fs.readdirSync(srcpath); 8 | } 9 | let plugin_directory = path.join(__dirname, 'modules'); 10 | let plugins = getPlugins(plugin_directory); 11 | 12 | exports.init = function init() { 13 | load_plugins(); 14 | }; 15 | 16 | function load_plugins() { 17 | const dbot = require('./bot.js'); 18 | let commandCount = 0; 19 | let otherFunc = 0; 20 | for (let i = 0; i < plugins.length; i++) { 21 | let plugin; 22 | try { 23 | plugin = require(`${plugin_directory}/${plugins[i]}`); 24 | } catch (err) { 25 | console.log(`Improper setup of the '${plugins[i]}' plugin. : ${err}`); 26 | } 27 | if (plugin) { 28 | if ('commands' in plugin) { 29 | for (let j = 0; j < plugin.commands.length; j++) { 30 | if (plugin.commands[j] in plugin) { 31 | dbot.addCommand(plugin.commands[j], plugin[plugin.commands[j]]); 32 | commandCount++; 33 | } 34 | } 35 | } 36 | if ('custom' in plugin) { 37 | for (let j = 0; j < plugin.custom.length; j++) { 38 | if (plugin.custom[j] in plugin) { 39 | dbot.addCustomFunc(plugin[plugin.custom[j]]); 40 | otherFunc++; 41 | } 42 | } 43 | } 44 | } 45 | } 46 | console.log( 47 | `Loaded ${dbot.commandCount()} chat commands and ${otherFunc} custom functions.` 48 | ); 49 | } 50 | -------------------------------------------------------------------------------- /config/default.json.example: -------------------------------------------------------------------------------- 1 | { 2 | // Bot configuration 3 | "bot": { 4 | "token":"Bot-Token", 5 | "prefix": "!", 6 | "debug": true 7 | }, 8 | "rvn": { 9 | "paytxfee": .01, 10 | "config": { 11 | "port": 3335, 12 | "user": "username", 13 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 14 | } 15 | }, 16 | "doge": { 17 | "paytxfee": 1, 18 | "config": { 19 | "port": 3336, 20 | "user": "username", 21 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 22 | } 23 | }, 24 | "lbc": { 25 | "paytxfee": .01, 26 | "config": { 27 | "port": 3337, 28 | "user": "username", 29 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 30 | } 31 | }, 32 | "phase": { 33 | "paytxfee": .01, 34 | "config": { 35 | "port": 3338, 36 | "user": "username", 37 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 38 | } 39 | }, 40 | "ppc": { 41 | "paytxfee": .01, 42 | "config": { 43 | "port": 8832, 44 | "user": "username", 45 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 46 | } 47 | }, 48 | "ufo": { 49 | "paytxfee": .01, 50 | "config": { 51 | "port": 3338, 52 | "user": "username", 53 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 54 | } 55 | }, 56 | "pxc": { 57 | "paytxfee": .01, 58 | "config": { 59 | "port": 3339, 60 | "user": "username", 61 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 62 | } 63 | }, 64 | "ftc": { 65 | "paytxfee": .01, 66 | "config": { 67 | "port": 3340, 68 | "user": "username", 69 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 70 | } 71 | }, 72 | "vtl": { 73 | "paytxfee": .01, 74 | "config": { 75 | "port": 3341, 76 | "user": "username", 77 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 78 | } 79 | }, 80 | "nebl": { 81 | "paytxfee": .01, 82 | "config": { 83 | "port": 3342, 84 | "user": "username", 85 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 86 | } 87 | }, 88 | "xuez": { 89 | "paytxfee": .01, 90 | "config": { 91 | "port": 3345, 92 | "user": "username", 93 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 94 | } 95 | }, 96 | "spk": { 97 | "paytxfee": .01, 98 | "config": { 99 | "port": 8892, 100 | "user": "username", 101 | "pass": "Do-Not-Use-This-Password-Youll-Be-Hacked-For-all-Teh-Moneys!" 102 | } 103 | }, 104 | 105 | "moderation":{ 106 | "pm2Name": "TipBot", 107 | // Roles that have access to all commands. 108 | "perms": ["Admin","Moderator","Community Leader","Bots"], 109 | // Bot Devs! 110 | "botDev": "Bot Developer", 111 | // Channel to log the bots moderation.. 112 | "logchannel": "429853685179351050", 113 | //channel that the tip message will reply in if Multi or Role tip is used. 114 | "botspamchannels": ["429134627823812612", "429852470886268929"] 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /ecosystem.config.js.example: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apps: [ 3 | { 4 | name: 'TipBot', 5 | script: './bot/bot.js', 6 | cwd: 'Location-of-Bot-Dir', 7 | instance_id_env: '0', 8 | watch: true, 9 | ignore_watch : ['node_modules', 'Logs', 'Downloads', '.git'], 10 | error_file: 11 | 'Location-of-Bot-Dir/Logs/tipbot-err.log', 12 | out_file: 'Location-of-Bot-Dir/Logs/tipbot-out.log', 13 | env: { 14 | NODE_ENV: 'development' 15 | }, 16 | env_production: { 17 | NODE_ENV: 'production' 18 | } 19 | } 20 | ] 21 | }; 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "babel-cli": "^6.26.0", 4 | "babel-preset-node8": "^1.2.0", 5 | "bitcoin": "^3.0.1", 6 | "chrono-node": "^1.3.5", 7 | "config": "^1.27.0", 8 | "discord.js": "^11.2.1", 9 | "embed-creator": "^1.1.4", 10 | "jsonpath": "^0.2.12", 11 | "moment": "^2.20.1", 12 | "moment-timezone": "^0.5.14", 13 | "node-cmd": "^3.0.0", 14 | "node-config": "^0.0.2", 15 | "numeral": "^2.0.6", 16 | "pm2": "^2.10.2", 17 | "regex": "^0.1.1", 18 | "request": "^2.83.0" 19 | }, 20 | "scripts": { 21 | "precommit": "prettier --single-quote true --write bot/**/*.js", 22 | "rebuild": "git pull origin master && npm install && update all", 23 | "start": "pm2 start ecosystem.config.js" 24 | }, 25 | "devDependencies": { 26 | "prettier": "1.7.4" 27 | }, 28 | "name": "tipbot", 29 | "version": "1.0.0", 30 | "description": "Crypto coin tipbot for Discord", 31 | "main": "bot/bot.js", 32 | "repository": "https://github.com/MSFTserver/TipBot", 33 | "author": "MSFTserver ", 34 | "license": "MIT" 35 | } 36 | -------------------------------------------------------------------------------- /windows-install.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | Mode 51, 30 3 | set mainDir=%~dp0Logs 4 | set dlDir=%~dp0Downloads 5 | set nodeLog=%mainDir%\node-install.log 6 | set nodeCheck=%mainDir%\nodeCheck.txt 7 | set gitCheck=%mainDir%\gitCheck.txt 8 | :Start 9 | echo Installing Wunderbot for Windows! 10 | ping localhost -n 4 >nul 11 | goto :gitCheck 12 | :gitCheck 13 | echo ___________________________________________________ 14 | git --version > %gitCheck% 15 | if %errorlevel%==9009 ( 16 | echo git not found, Installing git! 17 | ping localhost -n 4 >nul 18 | goto :gitInstall 19 | ) 20 | set /p gitVersion=<%gitCheck% 21 | if /I "%gitVersion%"==" " ( 22 | echo git not found, Installing git! 23 | ping localhost -n 4 >nul 24 | goto :gitInstall 25 | ) 26 | echo git found, running %gitVersion% 27 | ping localhost -n 4 >nul 28 | goto :nodeCheck 29 | :gitInstall 30 | echo ___________________________________________________ 31 | echo Downloading git from https://github.com/git-for-windows/git/releases/ to %dlDir% 32 | ping localhost -n 4 >nul 33 | start bitsadmin.exe /transfer "Install Git" https://github.com/git-for-windows/git/releases/download/v2.16.2.windows.1/Git-2.16.2-32-bit.exe %dlDir%\Git-2.16.2-32-bit.exe 34 | echo continuing in 1 minute 35 | echo if the process finishes before time- 36 | echo is up you can press any key to continue 37 | timeout /t 60 38 | echo ___________________________________________________ 39 | echo Installing Git-2.16.2-32-bit.exe 40 | start Git-2.16.2-32-bit.exe /i %dlDir%\Git-2.16.2-32-bit.exe /N /L*V "%nodeLog%" 41 | echo continuing in 3 minutes 42 | echo if the process finishes before time- 43 | echo is up you can press any key to continue 44 | timeout /t 180 45 | del %dlDir%\Git-2.16.2-32-bit.exe 46 | echo ___________________________________________________ 47 | echo finished installing git 48 | ping localhost -n 4 >nul 49 | goto :nodeCheck 50 | :nodeCheck 51 | echo ___________________________________________________ 52 | node -v > %nodeCheck% 53 | if %errorlevel%==9009 ( 54 | echo node.js not found, Installing Node.js! 55 | ping localhost -n 4 >nul 56 | goto :nodeInstall 57 | ) 58 | set /p nodeVersion=<%nodeCheck% 59 | if /I "%nodeVersion%"==" " ( 60 | echo node.js not found, Installing Node.js! 61 | ping localhost -n 4 >nul 62 | goto :nodeInstall 63 | ) 64 | echo node.js found, running %nodeVersion% 65 | ping localhost -n 4 >nul 66 | goto :npmInstall 67 | :nodeInstall 68 | echo ___________________________________________________ 69 | echo Downloading node.js from https://nodejs.org/dist/latest/ to %dlDir% 70 | ping localhost -n 4 >nul 71 | start bitsadmin.exe /transfer "Install Node" https://nodejs.org/dist/latest/node-v9.9.0-x64.msi %dlDir%\node-v9.9.0-x64.msi 72 | echo continuing in 1 minute 73 | echo if the process finishes before time- 74 | echo is up you can press any key to continue 75 | timeout /t 60 76 | echo ___________________________________________________ 77 | echo Installing node-v9.9.0-x64.msi 78 | start msiexec.exe /i %dlDir%\node-v9.9.0-x64.msi /N /L*V "%nodeLog%" 79 | echo continuing in 3 minutes 80 | echo if the process finishes before time- 81 | echo is up you can press any key to continue 82 | timeout /t 180 83 | del %dlDir%\node-v9.9.0-x64.msi 84 | echo ___________________________________________________ 85 | echo finished installing node.js 86 | ping localhost -n 4 >nul 87 | goto :npmInstall 88 | :npmInstall 89 | echo ___________________________________________________ 90 | echo Installing npm packages for rvnButler! 91 | ping localhost -n 4 >nul 92 | start npm install 93 | echo continuing in 60 seconds 94 | echo if the process finishes before time- 95 | echo is up you can press any key to continue 96 | timeout /t 60 97 | echo ___________________________________________________ 98 | echo installing yarn! 99 | start npm install yarn -g 100 | echo continuing in 60 seconds 101 | echo if the process finishes before time- 102 | echo is up you can press any key to continue 103 | timeout /t 60 104 | echo ___________________________________________________ 105 | echo installing pm2! 106 | start npm install pm2 -g 107 | echo continuing in 60 seconds 108 | echo if the process finishes before time- 109 | echo is up you can press any key to continue 110 | timeout /t 60 111 | echo ___________________________________________________ 112 | echo Finished installing npm packages 113 | ping localhost -n 4 >nul 114 | goto :exit 115 | :exit 116 | echo ___________________________________________________ 117 | echo done installing rvnButler! 118 | del "%nodeCheck%" 119 | echo please run windows-start.bat to run rvnButler with pm2! 120 | echo Bye Bye... 121 | timeout /t 60 /nobreak 122 | --------------------------------------------------------------------------------