From 9f0c0b2a9155e060d6ec567352201eb217a95f6e Mon Sep 17 00:00:00 2001 From: poolman Date: Tue, 23 Apr 2019 00:46:26 +0300 Subject: [PATCH] Implement deploy script, delete redundant coins --- coinConfig.json | 34 -- config_example.json | 2 +- deployment/aeon.service | 13 - deployment/deploy.bash | 34 +- deployment/deploy_aeon.bash | 96 ---- deployment/monero.service | 13 - deployment/monero_daemon.patch | 13 - deployment/upgrade_monero.bash | 13 - deployment/zano.service | 13 + lib/coins/aeon-rebase.js | 165 ------- lib/coins/aeon.js | 156 ------- lib/coins/krb.js | 156 ------- lib/coins/xmr.js | 171 ------- lib/payment_systems/aeon-rebase.js | 697 ----------------------------- lib/payment_systems/aeon.js | 257 ----------- lib/payment_systems/krb.js | 254 ----------- lib/payment_systems/xmr.js | 696 ---------------------------- 17 files changed, 30 insertions(+), 2753 deletions(-) delete mode 100644 deployment/aeon.service delete mode 100644 deployment/deploy_aeon.bash delete mode 100644 deployment/monero.service delete mode 100644 deployment/monero_daemon.patch delete mode 100644 deployment/upgrade_monero.bash create mode 100644 deployment/zano.service delete mode 100644 lib/coins/aeon-rebase.js delete mode 100644 lib/coins/aeon.js delete mode 100644 lib/coins/krb.js delete mode 100644 lib/coins/xmr.js delete mode 100644 lib/payment_systems/aeon-rebase.js delete mode 100644 lib/payment_systems/aeon.js delete mode 100644 lib/payment_systems/krb.js delete mode 100644 lib/payment_systems/xmr.js diff --git a/coinConfig.json b/coinConfig.json index 2063c5d..db00398 100644 --- a/coinConfig.json +++ b/coinConfig.json @@ -1,38 +1,4 @@ { - "xmr": { - "funcFile": "./lib/coins/xmr.js", - "paymentFile": "./payment_systems/xmr.js", - "sigDigits": 1000000000000, - "shapeshift": "xmr_btc", - "xmrTo": true, - "name": "Monero", - "mixIn": 4, - "shortCode": "XMR" - }, - "krb": { - "funcFile": "./lib/coins/krb.js", - "paymentFile": "./payment_systems/krb.js", - "sigDigits": 1000000000000, - "name": "Karbowanec", - "mixIn": 4, - "shortCode": "KRB" - }, - "aeon": { - "funcFile": "./lib/coins/aeon.js", - "paymentFile": "./payment_systems/aeon.js", - "sigDigits": 1000000000000, - "name": "Aeon Coin", - "mixIn": 4, - "shortCode": "AEON" - }, - "aeon-rebase": { - "funcFile": "./lib/coins/aeon-rebase.js", - "paymentFile": "./payment_systems/aeon-rebase.js", - "sigDigits": 1000000000000, - "name": "Aeon Coin", - "mixIn": 4, - "shortCode": "AEON" - }, "zano": { "funcFile": "./lib/coins/zano.js", "paymentFile": "./payment_systems/zano.js", diff --git a/config_example.json b/config_example.json index cf3ea8a..93f4f07 100644 --- a/config_example.json +++ b/config_example.json @@ -3,7 +3,7 @@ "bind_ip": "127.0.0.1", "hostname": "testpool.com", "db_storage_path": "CHANGEME", - "coin": "xmr", + "coin": "zano", "mysql": { "connectionLimit": 20, "host": "127.0.0.1", diff --git a/deployment/aeon.service b/deployment/aeon.service deleted file mode 100644 index c805bda..0000000 --- a/deployment/aeon.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Aeon Daemon -After=network.target - -[Service] -Type=forking -GuessMainPID=no -ExecStart=/usr/local/src/aeon/build/release/bin/aeon --rpc-bind-ip 127.0.0.1 --detach --restricted-rpc -Restart=always -User=aeondaemon - -[Install] -WantedBy=multi-user.target diff --git a/deployment/deploy.bash b/deployment/deploy.bash index 01e2e4c..ae34cea 100644 --- a/deployment/deploy.bash +++ b/deployment/deploy.bash @@ -16,7 +16,7 @@ sudo debconf-set-selections <<< "mysql-server mysql-server/root_password_again p echo -e "[client]\nuser=root\npassword=$ROOT_SQL_PASS" | sudo tee /root/.my.cnf sudo DEBIAN_FRONTEND=noninteractive apt-get -y install git python-virtualenv python3-virtualenv curl ntp build-essential screen cmake pkg-config libboost-all-dev libevent-dev libunbound-dev libminiupnpc-dev libunwind8-dev liblzma-dev libldns-dev libexpat1-dev libgtest-dev mysql-server lmdb-utils libzmq3-dev cd ~ -git clone https://github.com/Snipa22/nodejs-pool.git # Change this depending on how the deployment goes. +git clone https://github.com/hyle-team/zano-nodejs-pool.git # Change this depending on how the deployment goes. cd /usr/src/gtest sudo cmake . sudo make @@ -24,24 +24,22 @@ sudo mv libg* /usr/lib/ cd ~ sudo systemctl enable ntp cd /usr/local/src -sudo git clone https://github.com/monero-project/monero.git -cd monero -sudo git checkout v0.11.1.0 -curl https://raw.githubusercontent.com/Snipa22/nodejs-pool/master/deployment/monero_daemon.patch | sudo git apply -v +sudo git clone https://github.com/hyle-team/zano.git +cd zano +sudo git checkout master +sudo mkdir build +sudo cd build +sudo cmake .. sudo make -j$(nproc) -sudo cp ~/nodejs-pool/deployment/monero.service /lib/systemd/system/ -sudo useradd -m monerodaemon -d /home/monerodaemon -BLOCKCHAIN_DOWNLOAD_DIR=$(sudo -u monerodaemon mktemp -d) -sudo -u monerodaemon wget --limit-rate=50m -O $BLOCKCHAIN_DOWNLOAD_DIR/blockchain.raw https://downloads.getmonero.org/blockchain.raw -sudo -u monerodaemon /usr/local/src/monero/build/release/bin/monero-blockchain-import --input-file $BLOCKCHAIN_DOWNLOAD_DIR/blockchain.raw --batch-size 20000 --database lmdb#fastest --verify off --data-dir /home/monerodaemon/.bitmonero -sudo -u monerodaemon rm -rf $BLOCKCHAIN_DOWNLOAD_DIR +sudo cp ~/zano-nodejs-pool/deployment/zano.service /lib/systemd/system/ +sudo useradd -m zanodaemon -d /home/zanodaemon sudo systemctl daemon-reload -sudo systemctl enable monero -sudo systemctl start monero +sudo systemctl enable zano +sudo systemctl start zano curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.0/install.sh | bash source ~/.nvm/nvm.sh nvm install v8.9.3 -cd ~/nodejs-pool +cd ~/zano-nodejs-pool npm install npm install -g pm2 openssl req -subj "/C=IT/ST=Pool/L=Daemon/O=Mining Pool/CN=mining.pool" -newkey rsa:2048 -nodes -keyout cert.key -x509 -out cert.pem -days 36500 @@ -69,7 +67,7 @@ sudo chown -R root:www-data /etc/caddy sudo mkdir /etc/ssl/caddy sudo chown -R www-data:root /etc/ssl/caddy sudo chmod 0770 /etc/ssl/caddy -sudo cp ~/nodejs-pool/deployment/caddyfile /etc/caddy/Caddyfile +sudo cp ~/zano-nodejs-pool/deployment/caddyfile /etc/caddy/Caddyfile sudo chown www-data:www-data /etc/caddy/Caddyfile sudo chmod 444 /etc/caddy/Caddyfile sudo sh -c "sed 's/ProtectHome=true/ProtectHome=false/' init/linux-systemd/caddy.service > /etc/systemd/system/caddy.service" @@ -81,7 +79,7 @@ sudo systemctl start caddy.service rm -rf $CADDY_DOWNLOAD_DIR cd ~ sudo env PATH=$PATH:`pwd`/.nvm/versions/node/v8.9.3/bin `pwd`/.nvm/versions/node/v8.9.3/lib/node_modules/pm2/bin/pm2 startup systemd -u $CURUSER --hp `pwd` -cd ~/nodejs-pool +cd ~/zano-nodejs-pool sudo chown -R $CURUSER. ~/.pm2 echo "Installing pm2-logrotate in the background!" pm2 install pm2-logrotate & @@ -89,7 +87,7 @@ mysql -u root --password=$ROOT_SQL_PASS < deployment/base.sql mysql -u root --password=$ROOT_SQL_PASS pool -e "INSERT INTO pool.config (module, item, item_value, item_type, Item_desc) VALUES ('api', 'authKey', '`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1`', 'string', 'Auth key sent with all Websocket frames for validation.')" mysql -u root --password=$ROOT_SQL_PASS pool -e "INSERT INTO pool.config (module, item, item_value, item_type, Item_desc) VALUES ('api', 'secKey', '`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1`', 'string', 'HMAC key for Passwords. JWT Secret Key. Changing this will invalidate all current logins.')" pm2 start init.js --name=api --log-date-format="YYYY-MM-DD HH:mm Z" -- --module=api -bash ~/nodejs-pool/deployment/install_lmdb_tools.sh -cd ~/nodejs-pool/sql_sync/ +bash ~/zano-nodejs-pool/deployment/install_lmdb_tools.sh +cd ~/zano-nodejs-pool/sql_sync/ env PATH=$PATH:`pwd`/.nvm/versions/node/v8.9.3/bin node sql_sync.js echo "You're setup! Please read the rest of the readme for the remainder of your setup and configuration. These steps include: Setting your Fee Address, Pool Address, Global Domain, and the Mailgun setup!" diff --git a/deployment/deploy_aeon.bash b/deployment/deploy_aeon.bash deleted file mode 100644 index c453669..0000000 --- a/deployment/deploy_aeon.bash +++ /dev/null @@ -1,96 +0,0 @@ -#!/bin/bash -echo "This assumes that you are doing a green-field install. If you're not, please exit in the next 15 seconds." -sleep 15 -echo "Continuing install, this will prompt you for your password if you're not already running as root and you didn't enable passwordless sudo. Please do not run me as root!" -if [[ `whoami` == "root" ]]; then - echo "You ran me as root! Do not run me as root!" - exit 1 -fi -ROOT_SQL_PASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1) -CURUSER=$(whoami) -echo "Etc/UTC" | sudo tee -a /etc/timezone -sudo rm -rf /etc/localtime -sudo ln -s /usr/share/zoneinfo/Zulu /etc/localtime -sudo dpkg-reconfigure -f noninteractive tzdata -sudo apt-get update -sudo DEBIAN_FRONTEND=noninteractive apt-get -y upgrade -sudo debconf-set-selections <<< "mysql-server mysql-server/root_password password $ROOT_SQL_PASS" -sudo debconf-set-selections <<< "mysql-server mysql-server/root_password_again password $ROOT_SQL_PASS" -echo -e "[client]\nuser=root\npassword=$ROOT_SQL_PASS" | sudo tee /root/.my.cnf -sudo DEBIAN_FRONTEND=noninteractive apt-get -y install git python-virtualenv python3-virtualenv curl ntp build-essential screen cmake pkg-config libboost-all-dev libevent-dev libunbound-dev libminiupnpc-dev libunwind8-dev liblzma-dev libldns-dev libexpat1-dev libgtest-dev mysql-server lmdb-utils libzmq3-dev -cd /usr/src/gtest -sudo cmake . -sudo make -sudo mv libg* /usr/lib/ -cd ~ -#sudo systemctl enable ntp -#cd /usr/local/src -#sudo git clone https://github.com/aeonix/aeon.git -#cd aeon -#sudo git checkout v0.9.14.0 -#sudo make -j$(nproc) -#sudo cp ~/nodejs-pool/deployment/aeon.service /lib/systemd/system/ -#sudo useradd -m aeondaemon -d /home/aeondaemon -#sudo -u aeondaemon mkdir /home/aeondaemon/.aeon -#BLOCKCHAIN_DOWNLOAD_DIR=$(sudo -u aeondaemon mktemp -d) -#sudo -u aeondaemon wget --limit-rate=50m -O $BLOCKCHAIN_DOWNLOAD_DIR/blockchain.bin http://74.208.156.45/blockchain.raw -#sudo -u aeondaemon mv $BLOCKCHAIN_DOWNLOAD_DIR/blockchain.bin /home/aeondaemon/.aeon/blockchain.bin -#sudo -u aeondaemon rm -rf $BLOCKCHAIN_DOWNLOAD_DIR -#sudo systemctl daemon-reload -#sudo systemctl enable aeon -#sudo systemctl start aeon -curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.0/install.sh | bash -source ~/.nvm/nvm.sh -nvm install v6.9.2 -cd ~/nodejs-pool -npm install -npm install -g pm2 -openssl req -subj "/C=IT/ST=Pool/L=Daemon/O=Mining Pool/CN=mining.pool" -newkey rsa:2048 -nodes -keyout cert.key -x509 -out cert.pem -days 36500 -mkdir ~/pool_db/ -sed -r "s/(\"db_storage_path\": ).*/\1\"\/home\/$CURUSER\/pool_db\/\",/" config_example.json > config.json -cd ~ -git clone https://github.com/mesh0000/poolui.git -cd poolui -npm install -./node_modules/bower/bin/bower update -./node_modules/gulp/bin/gulp.js build -cd build -sudo ln -s `pwd` /var/www -CADDY_DOWNLOAD_DIR=$(mktemp -d) -cd $CADDY_DOWNLOAD_DIR -curl -sL "https://snipanet.com/caddy.tar.gz" | tar -xz caddy init/linux-systemd/caddy.service -sudo mv caddy /usr/local/bin -sudo chown root:root /usr/local/bin/caddy -sudo chmod 755 /usr/local/bin/caddy -sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy -sudo groupadd -g 33 www-data -sudo useradd -g www-data --no-user-group --home-dir /var/www --no-create-home --shell /usr/sbin/nologin --system --uid 33 www-data -sudo mkdir /etc/caddy -sudo chown -R root:www-data /etc/caddy -sudo mkdir /etc/ssl/caddy -sudo chown -R www-data:root /etc/ssl/caddy -sudo chmod 0770 /etc/ssl/caddy -sudo cp ~/nodejs-pool/deployment/caddyfile /etc/caddy/Caddyfile -sudo chown www-data:www-data /etc/caddy/Caddyfile -sudo chmod 444 /etc/caddy/Caddyfile -sudo sh -c "sed 's/ProtectHome=true/ProtectHome=false/' init/linux-systemd/caddy.service > /etc/systemd/system/caddy.service" -sudo chown root:root /etc/systemd/system/caddy.service -sudo chmod 644 /etc/systemd/system/caddy.service -sudo systemctl daemon-reload -sudo systemctl enable caddy.service -sudo systemctl start caddy.service -rm -rf $CADDY_DOWNLOAD_DIR -cd ~ -sudo env PATH=$PATH:`pwd`/.nvm/versions/node/v6.9.2/bin `pwd`/.nvm/versions/node/v6.9.2/lib/node_modules/pm2/bin/pm2 startup systemd -u $CURUSER --hp `pwd` -cd ~/nodejs-pool -sudo chown -R $CURUSER. ~/.pm2 -echo "Installing pm2-logrotate in the background!" -pm2 install pm2-logrotate & -mysql -u root --password=$ROOT_SQL_PASS < deployment/base.sql -mysql -u root --password=$ROOT_SQL_PASS pool -e "INSERT INTO pool.config (module, item, item_value, item_type, Item_desc) VALUES ('api', 'authKey', '`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1`', 'string', 'Auth key sent with all Websocket frames for validation.')" -mysql -u root --password=$ROOT_SQL_PASS pool -e "INSERT INTO pool.config (module, item, item_value, item_type, Item_desc) VALUES ('api', 'secKey', '`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1`', 'string', 'HMAC key for Passwords. JWT Secret Key. Changing this will invalidate all current logins.')" -pm2 start init.js --name=api --log-date-format="YYYY-MM-DD HH:mm Z" -- --module=api -bash ~/nodejs-pool/deployment/install_lmdb_tools.sh -cd ~/nodejs-pool/sql_sync/ -env PATH=$PATH:`pwd`/.nvm/versions/node/v6.9.2/bin node sql_sync.js -echo "You're setup! Please read the rest of the readme for the remainder of your setup and configuration. These steps include: Setting your Fee Address, Pool Address, Global Domain, and the Mailgun setup!" diff --git a/deployment/monero.service b/deployment/monero.service deleted file mode 100644 index a1ad70d..0000000 --- a/deployment/monero.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Monero Daemon -After=network.target - -[Service] -Type=forking -GuessMainPID=no -ExecStart=/usr/local/src/monero/build/release/bin/monerod --rpc-bind-ip 127.0.0.1 --detach --restricted-rpc -Restart=always -User=monerodaemon - -[Install] -WantedBy=multi-user.target diff --git a/deployment/monero_daemon.patch b/deployment/monero_daemon.patch deleted file mode 100644 index 5f681f7..0000000 --- a/deployment/monero_daemon.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp -index 4b3fa787..a2340139 100644 ---- a/src/cryptonote_core/tx_pool.cpp -+++ b/src/cryptonote_core/tx_pool.cpp -@@ -863,7 +863,7 @@ namespace cryptonote - LockedTXN lock(m_blockchain); - - auto sorted_it = m_txs_by_fee_and_receive_time.begin(); -- while (sorted_it != m_txs_by_fee_and_receive_time.end()) -+ while (sorted_it != m_txs_by_fee_and_receive_time.end() && bl.tx_hashes.size() <= 120) - { - txpool_tx_meta_t meta = m_blockchain.get_txpool_tx_meta(sorted_it->second); - LOG_PRINT_L2("Considering " << sorted_it->second << ", size " << meta.blob_size << ", current block size " << total_size << "/" << max_total_size << ", current coinbase " << print_money(best_coinbase)); diff --git a/deployment/upgrade_monero.bash b/deployment/upgrade_monero.bash deleted file mode 100644 index b8cc1e2..0000000 --- a/deployment/upgrade_monero.bash +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -echo "This assumes that you have a standard nodejs-pool install, and will patch and update it to the latest stable builds of Monero." -sleep 15 -echo "Continuing install, this will prompt you for your password if you didn't enable passwordless sudo. Please do not run me as root!" -cd /usr/local/src/monero -sudo git checkout . -sudo git checkout master -sudo git pull -sudo git checkout origin/release-v0.11.0.0 -curl -L https://raw.githubusercontent.com/Snipa22/nodejs-pool/master/deployment/monero_daemon.patch | sudo git apply -v -sudo rm -rf build -sudo make -j$(nproc) -echo "Done building the new Monero daemon! Please go ahead and reboot monero with: sudo systemctl restart monero as soon as the pool source is updated!" diff --git a/deployment/zano.service b/deployment/zano.service new file mode 100644 index 0000000..bb4a9f2 --- /dev/null +++ b/deployment/zano.service @@ -0,0 +1,13 @@ +[Unit] +Description=Zano Daemon +After=network.target + +[Service] +Type=forking +GuessMainPID=no +ExecStart=/usr/local/src/zano/build/release/src/zanod --rpc-bind-ip 127.0.0.1 +Restart=always +User=zanodaemon + +[Install] +WantedBy=multi-user.target diff --git a/lib/coins/aeon-rebase.js b/lib/coins/aeon-rebase.js deleted file mode 100644 index 5517c3f..0000000 --- a/lib/coins/aeon-rebase.js +++ /dev/null @@ -1,165 +0,0 @@ -"use strict"; -const bignum = require('bignum'); -const cnUtil = require('cryptonote-util'); -const multiHashing = require('multi-hashing'); -const crypto = require('crypto'); -const debug = require('debug')('coinFuncs'); - -let hexChars = new RegExp("[0-9a-f]+"); - -function Coin(data){ - this.isxmr = false; - this.bestExchange = global.config.payout.bestExchange; - this.data = data; - let instanceId = crypto.randomBytes(4); - this.coinDevAddress = "WmsSWgtT1JPg5e3cK41hKXSHVpKW7e47bjgiKmWZkYrhSS5LhRemNyqayaSBtAQ6517eo5PtH9wxHVmM78JDZSUu2W8PqRiNs"; // Developer Address - this.poolDevAddress = "WmtvM6SoYya4qzkoPB4wX7FACWcXyFPWAYzfz7CADECgKyBemAeb3dVb3QomHjRWwGS3VYzMJAnBXfUx5CfGLFZd1U7ssdXTu"; // Snipa Address - - this.blockedAddresses = [ - this.coinDevAddress, - this.poolDevAddress, - ]; - - this.exchangeAddresses = [ - "WmtK9TQ6yd2ZWZDAkRsebc2ppzUq2Wuo9XRRjHMH2fvqM3ARVqk3styJ6AavJFcpJFPFtxRGAqGFoJMZGJ6YYzQ61TYGfpykX", // Bittrex - ]; // These are addresses that MUST have a paymentID to perform logins with. - - this.prefix = 178; - //this.intPrefix = 0x2733; - - if (global.config.general.testnet === true){ - this.prefix = 0x0426; - // this.intPrefix = 0x2C27; - } - - this.supportsAutoExchange = false; - - this.niceHashDiff = 200000; - - this.getBlockHeaderByID = function(blockId, callback){ - global.support.rpcDaemon('getblockheaderbyheight', {"height": blockId}, function (body) { - if (body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getBlockHeaderByHash = function(blockHash, callback){ - global.support.rpcDaemon('getblockheaderbyhash', {"hash": blockHash}, function (body) { - if (typeof(body) !== 'undefined' && body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getLastBlockHeader = function(callback){ - global.support.rpcDaemon('getlastblockheader', [], function (body) { - if (typeof(body) !== 'undefined' && body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getBlockTemplate = function(walletAddress, callback){ - global.support.rpcDaemon('getblocktemplate', { - reserve_size: 17, - wallet_address: walletAddress - }, function(body){ - return callback(body); - }); - }; - - this.baseDiff = function(){ - return bignum('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 16); - }; - - this.validateAddress = function(address){ - // This function should be able to be called from the async library, as we need to BLOCK ever so slightly to verify the address. - address = new Buffer(address); - if (cnUtil.address_decode(address) === this.prefix){ - return true; - } - return cnUtil.address_decode_integrated(address) === this.intPrefix; - }; - - this.convertBlob = function(blobBuffer){ - return cnUtil.convert_blob(blobBuffer); - }; - - this.constructNewBlob = function(blockTemplate, NonceBuffer){ - return cnUtil.construct_block_blob(blockTemplate, NonceBuffer); - }; - - this.getBlockID = function(blockBuffer){ - return cnUtil.get_block_id(blockBuffer); - }; - - this.BlockTemplate = function(template) { - /* - Generating a block template is a simple thing. Ask for a boatload of information, and go from there. - Important things to consider. - The reserved space is 13 bytes long now in the following format: - Assuming that the extraNonce starts at byte 130: - |130-133|134-137|138-141|142-145| - |minerNonce/extraNonce - 4 bytes|instanceId - 4 bytes|clientPoolNonce - 4 bytes|clientNonce - 4 bytes| - This is designed to allow a single block template to be used on up to 4 billion poolSlaves (clientPoolNonce) - Each with 4 billion clients. (clientNonce) - While being unique to this particular pool thread (instanceId) - With up to 4 billion clients (minerNonce/extraNonce) - Overkill? Sure. But that's what we do here. Overkill. - */ - - // Set this.blob equal to the BT blob that we get from upstream. - this.blob = template.blocktemplate_blob; - this.idHash = crypto.createHash('md5').update(template.blocktemplate_blob).digest('hex'); - // Set this.diff equal to the known diff for this block. - this.difficulty = template.difficulty; - // Set this.height equal to the known height for this block. - this.height = template.height; - // Set this.reserveOffset to the byte location of the reserved offset. - this.reserveOffset = template.reserved_offset; - // Set this.buffer to the binary decoded version of the BT blob. - this.buffer = new Buffer(this.blob, 'hex'); - // Copy the Instance ID to the reserve offset + 4 bytes deeper. Copy in 4 bytes. - instanceId.copy(this.buffer, this.reserveOffset + 4, 0, 3); - // Generate a clean, shiny new buffer. - this.previous_hash = new Buffer(32); - // Copy in bytes 7 through 39 to this.previous_hash from the current BT. - this.buffer.copy(this.previous_hash, 0, 7, 39); - // Reset the Nonce. - This is the per-miner/pool nonce - this.extraNonce = 0; - // The clientNonceLocation is the location at which the client pools should set the nonces for each of their clients. - this.clientNonceLocation = this.reserveOffset + 12; - // The clientPoolLocation is for multi-thread/multi-server pools to handle the nonce for each of their tiers. - this.clientPoolLocation = this.reserveOffset + 8; - this.nextBlob = function () { - // Write a 32 bit integer, big-endian style to the 0 byte of the reserve offset. - this.buffer.writeUInt32BE(++this.extraNonce, this.reserveOffset); - // Convert the blob into something hashable. - return global.coinFuncs.convertBlob(this.buffer).toString('hex'); - }; - // Make it so you can get the raw block blob out. - this.nextBlobWithChildNonce = function () { - // Write a 32 bit integer, big-endian style to the 0 byte of the reserve offset. - this.buffer.writeUInt32BE(++this.extraNonce, this.reserveOffset); - // Don't convert the blob to something hashable. You bad. - return this.buffer.toString('hex'); - }; - }; - - this.cryptoNight = function(convertedBlob) { - return multiHashing.cryptonight_light(convertedBlob, convertedBlob[0] >= 7 ? convertedBlob[0] - 6 : 0); - } - -} - -module.exports = Coin; diff --git a/lib/coins/aeon.js b/lib/coins/aeon.js deleted file mode 100644 index 825155b..0000000 --- a/lib/coins/aeon.js +++ /dev/null @@ -1,156 +0,0 @@ -"use strict"; -const bignum = require('bignum'); -const cnUtil = require('cryptonote-util'); -const multiHashing = require('multi-hashing'); -const crypto = require('crypto'); -const debug = require('debug')('coinFuncs'); - -let hexChars = new RegExp("[0-9a-f]+"); - -function Coin(data){ - this.isxmr = false; - this.bestExchange = global.config.payout.bestExchange; - this.data = data; - let instanceId = crypto.randomBytes(4); - this.coinDevAddress = "WmsSWgtT1JPg5e3cK41hKXSHVpKW7e47bjgiKmWZkYrhSS5LhRemNyqayaSBtAQ6517eo5PtH9wxHVmM78JDZSUu2W8PqRiNs"; // Developer Address - this.poolDevAddress = "WmtvM6SoYya4qzkoPB4wX7FACWcXyFPWAYzfz7CADECgKyBemAeb3dVb3QomHjRWwGS3VYzMJAnBXfUx5CfGLFZd1U7ssdXTu"; // Snipa Address - - this.blockedAddresses = [ - this.coinDevAddress, - this.poolDevAddress, - ]; - - this.exchangeAddresses = [ - ]; // These are addresses that MUST have a paymentID to perform logins with. - - this.prefix = 178; - - this.supportsAutoExchange = false; - - this.niceHashDiff = 400000; - - this.getBlockHeaderByID = function(blockId, callback){ - global.support.rpcDaemon('getblockheaderbyheight', {"height": blockId}, function (body) { - if (body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getBlockHeaderByHash = function(blockHash, callback){ - global.support.rpcDaemon('getblockheaderbyhash', {"hash": blockHash}, function (body) { - if (typeof(body) !== 'undefined' && body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getLastBlockHeader = function(callback){ - global.support.rpcDaemon('getlastblockheader', [], function (body) { - if (typeof(body) !== 'undefined' && body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getBlockTemplate = function(walletAddress, callback){ - global.support.rpcDaemon('getblocktemplate', { - reserve_size: 17, - wallet_address: walletAddress - }, function(body){ - return callback(body); - }); - }; - - this.baseDiff = function(){ - return bignum('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 16); - }; - - this.validateAddress = function(address){ - // This function should be able to be called from the async library, as we need to BLOCK ever so slightly to verify the address. - address = new Buffer(address); - if (cnUtil.address_decode(address) === this.prefix){ - return true; - } - return cnUtil.address_decode_integrated(address) === this.intPrefix; - }; - - this.convertBlob = function(blobBuffer){ - return cnUtil.convert_blob(blobBuffer); - }; - - this.constructNewBlob = function(blockTemplate, NonceBuffer){ - return cnUtil.construct_block_blob(blockTemplate, NonceBuffer); - }; - - this.getBlockID = function(blockBuffer){ - return cnUtil.get_block_id(blockBuffer); - }; - - this.BlockTemplate = function(template) { - /* - Generating a block template is a simple thing. Ask for a boatload of information, and go from there. - Important things to consider. - The reserved space is 13 bytes long now in the following format: - Assuming that the extraNonce starts at byte 130: - |130-133|134-137|138-141|142-145| - |minerNonce/extraNonce - 4 bytes|instanceId - 4 bytes|clientPoolNonce - 4 bytes|clientNonce - 4 bytes| - This is designed to allow a single block template to be used on up to 4 billion poolSlaves (clientPoolNonce) - Each with 4 billion clients. (clientNonce) - While being unique to this particular pool thread (instanceId) - With up to 4 billion clients (minerNonce/extraNonce) - Overkill? Sure. But that's what we do here. Overkill. - */ - - // Set this.blob equal to the BT blob that we get from upstream. - this.blob = template.blocktemplate_blob; - this.idHash = crypto.createHash('md5').update(template.blocktemplate_blob).digest('hex'); - // Set this.diff equal to the known diff for this block. - this.difficulty = template.difficulty; - // Set this.height equal to the known height for this block. - this.height = template.height; - // Set this.reserveOffset to the byte location of the reserved offset. - this.reserveOffset = template.reserved_offset; - // Set this.buffer to the binary decoded version of the BT blob. - this.buffer = new Buffer(this.blob, 'hex'); - // Copy the Instance ID to the reserve offset + 4 bytes deeper. Copy in 4 bytes. - instanceId.copy(this.buffer, this.reserveOffset + 4, 0, 3); - // Generate a clean, shiny new buffer. - this.previous_hash = new Buffer(32); - // Copy in bytes 7 through 39 to this.previous_hash from the current BT. - this.buffer.copy(this.previous_hash, 0, 7, 39); - // Reset the Nonce. - This is the per-miner/pool nonce - this.extraNonce = 0; - // The clientNonceLocation is the location at which the client pools should set the nonces for each of their clients. - this.clientNonceLocation = this.reserveOffset + 12; - // The clientPoolLocation is for multi-thread/multi-server pools to handle the nonce for each of their tiers. - this.clientPoolLocation = this.reserveOffset + 8; - this.nextBlob = function () { - // Write a 32 bit integer, big-endian style to the 0 byte of the reserve offset. - this.buffer.writeUInt32BE(++this.extraNonce, this.reserveOffset); - // Convert the blob into something hashable. - return global.coinFuncs.convertBlob(this.buffer).toString('hex'); - }; - // Make it so you can get the raw block blob out. - this.nextBlobWithChildNonce = function () { - // Write a 32 bit integer, big-endian style to the 0 byte of the reserve offset. - this.buffer.writeUInt32BE(++this.extraNonce, this.reserveOffset); - // Don't convert the blob to something hashable. You bad. - return this.buffer.toString('hex'); - }; - }; - - this.cryptoNight = multiHashing.cryptonight_light; - -} - -module.exports = Coin; diff --git a/lib/coins/krb.js b/lib/coins/krb.js deleted file mode 100644 index 5bbc020..0000000 --- a/lib/coins/krb.js +++ /dev/null @@ -1,156 +0,0 @@ -"use strict"; -const bignum = require('bignum'); -const cnUtil = require('cryptonote-util'); -const multiHashing = require('multi-hashing'); -const crypto = require('crypto'); -const debug = require('debug')('coinFuncs'); - -let hexChars = new RegExp("[0-9a-f]+"); - -function Coin(data){ - this.isxmr = false; - this.bestExchange = global.config.payout.bestExchange; - this.data = data; - let instanceId = crypto.randomBytes(4); - this.coinDevAddress = "Kdev1L9V5ow3cdKNqDpLcFFxZCqu5W2GE9xMKewsB2pUXWxcXvJaUWHcSrHuZw91eYfQFzRtGfTemReSSMN4kE445i6Etb3"; // Developer Address - this.poolDevAddress = "KgseWakG2bMXHGJSsAUfzL1HykCyvD4m8gd9qgcuyZ1ufy8PqUCKRxEfAv3nahfdTrCjZByiWoCiRiohxq4u2rf2RgQ1pcJ"; // Snipa Address - - this.blockedAddresses = [ - this.coinDevAddress, - this.poolDevAddress, - ]; - - this.exchangeAddresses = [ - ]; // These are addresses that MUST have a paymentID to perform logins with. - - this.prefix = 111; - - this.supportsAutoExchange = false; - - this.niceHashDiff = 200000; - - this.getBlockHeaderByID = function(blockId, callback){ - global.support.rpcDaemon('getblockheaderbyheight', {"height": blockId}, function (body) { - if (body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getBlockHeaderByHash = function(blockHash, callback){ - global.support.rpcDaemon('getblockheaderbyhash', {"hash": blockHash}, function (body) { - if (typeof(body) !== 'undefined' && body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getLastBlockHeader = function(callback){ - global.support.rpcDaemon('getlastblockheader', [], function (body) { - if (typeof(body) !== 'undefined' && body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getBlockTemplate = function(walletAddress, callback){ - global.support.rpcDaemon('getblocktemplate', { - reserve_size: 17, - wallet_address: walletAddress - }, function(body){ - return callback(body); - }); - }; - - this.baseDiff = function(){ - return bignum('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 16); - }; - - this.validateAddress = function(address){ - // This function should be able to be called from the async library, as we need to BLOCK ever so slightly to verify the address. - address = new Buffer(address); - if (cnUtil.address_decode(address) === this.prefix){ - return true; - } - return cnUtil.address_decode_integrated(address) === this.intPrefix; - }; - - this.convertBlob = function(blobBuffer){ - return cnUtil.convert_blob(blobBuffer); - }; - - this.constructNewBlob = function(blockTemplate, NonceBuffer){ - return cnUtil.construct_block_blob(blockTemplate, NonceBuffer); - }; - - this.getBlockID = function(blockBuffer){ - return cnUtil.get_block_id(blockBuffer); - }; - - this.BlockTemplate = function(template) { - /* - Generating a block template is a simple thing. Ask for a boatload of information, and go from there. - Important things to consider. - The reserved space is 13 bytes long now in the following format: - Assuming that the extraNonce starts at byte 130: - |130-133|134-137|138-141|142-145| - |minerNonce/extraNonce - 4 bytes|instanceId - 4 bytes|clientPoolNonce - 4 bytes|clientNonce - 4 bytes| - This is designed to allow a single block template to be used on up to 4 billion poolSlaves (clientPoolNonce) - Each with 4 billion clients. (clientNonce) - While being unique to this particular pool thread (instanceId) - With up to 4 billion clients (minerNonce/extraNonce) - Overkill? Sure. But that's what we do here. Overkill. - */ - - // Set this.blob equal to the BT blob that we get from upstream. - this.blob = template.blocktemplate_blob; - this.idHash = crypto.createHash('md5').update(template.blocktemplate_blob).digest('hex'); - // Set this.diff equal to the known diff for this block. - this.difficulty = template.difficulty; - // Set this.height equal to the known height for this block. - this.height = template.height; - // Set this.reserveOffset to the byte location of the reserved offset. - this.reserveOffset = template.reserved_offset; - // Set this.buffer to the binary decoded version of the BT blob. - this.buffer = new Buffer(this.blob, 'hex'); - // Copy the Instance ID to the reserve offset + 4 bytes deeper. Copy in 4 bytes. - instanceId.copy(this.buffer, this.reserveOffset + 4, 0, 3); - // Generate a clean, shiny new buffer. - this.previous_hash = new Buffer(32); - // Copy in bytes 7 through 39 to this.previous_hash from the current BT. - this.buffer.copy(this.previous_hash, 0, 7, 39); - // Reset the Nonce. - This is the per-miner/pool nonce - this.extraNonce = 0; - // The clientNonceLocation is the location at which the client pools should set the nonces for each of their clients. - this.clientNonceLocation = this.reserveOffset + 12; - // The clientPoolLocation is for multi-thread/multi-server pools to handle the nonce for each of their tiers. - this.clientPoolLocation = this.reserveOffset + 8; - this.nextBlob = function () { - // Write a 32 bit integer, big-endian style to the 0 byte of the reserve offset. - this.buffer.writeUInt32BE(++this.extraNonce, this.reserveOffset); - // Convert the blob into something hashable. - return global.coinFuncs.convertBlob(this.buffer).toString('hex'); - }; - // Make it so you can get the raw block blob out. - this.nextBlobWithChildNonce = function () { - // Write a 32 bit integer, big-endian style to the 0 byte of the reserve offset. - this.buffer.writeUInt32BE(++this.extraNonce, this.reserveOffset); - // Don't convert the blob to something hashable. You bad. - return this.buffer.toString('hex'); - }; - }; - - this.cryptoNight = multiHashing.cryptonight; - -} - -module.exports = Coin; diff --git a/lib/coins/xmr.js b/lib/coins/xmr.js deleted file mode 100644 index 5cc1244..0000000 --- a/lib/coins/xmr.js +++ /dev/null @@ -1,171 +0,0 @@ -"use strict"; -const bignum = require('bignum'); -const cnUtil = require('cryptonote-util'); -const multiHashing = require("cryptonight-hashing"); -const crypto = require('crypto'); -const debug = require('debug')('coinFuncs'); - -let hexChars = new RegExp("[0-9a-f]+"); - -function Coin(data){ - this.isxmr = true; - this.bestExchange = global.config.payout.bestExchange; - this.data = data; - let instanceId = crypto.randomBytes(4); - this.coinDevAddress = "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A"; // Developer Address - this.poolDevAddress = "44Ldv5GQQhP7K7t3ZBdZjkPA7Kg7dhHwk3ZM3RJqxxrecENSFx27Vq14NAMAd2HBvwEPUVVvydPRLcC69JCZDHLT2X5a4gr"; // Snipa Address - - this.blockedAddresses = [ - this.coinDevAddress, - this.poolDevAddress, - "43SLUTpyTgXCNXsL43uD8FWZ5wLAdX7Ak67BgGp7dxnGhLmrffDTXoeGm2GBRm8JjigN9PTg2gnShQn5gkgE1JGWJr4gsEU", // Wolf0's address - "42QWoLF7pdwMcTXDviJvNkWEHJ4TXnMBh2Cx6HNkVAW57E48Zfw6wLwDUYFDYJAqY7PLJUTz9cHWB5C4wUA7UJPu5wPf4sZ", // Wolf0's address - "46gq64YYgCk88LxAadXbKLeQtCJtsLSD63NiEc3XHLz8NyPAyobACP161JbgyH2SgTau3aPUsFAYyK2RX4dHQoaN1ats6iT", // Claymore's Fee Address. - "47mr7jYTroxQMwdKoPQuJoc9Vs9S9qCUAL6Ek4qyNFWJdqgBZRn4RYY2QjQfqEMJZVWPscupSgaqmUn1dpdUTC4fQsu3yjN" // Claymore's _other_ fee address. - ]; - - this.exchangeAddresses = [ - "46yzCCD3Mza9tRj7aqPSaxVbbePtuAeKzf8Ky2eRtcXGcEgCg1iTBio6N4sPmznfgGEUGDoBz5CLxZ2XPTyZu1yoCAG7zt6", // Shapeshift.io - "463tWEBn5XZJSxLU6uLQnQ2iY9xuNcDbjLSjkn3XAXHCbLrTTErJrBWYgHJQyrCwkNgYvyV3z8zctJLPCZy24jvb3NiTcTJ", // Bittrex - "44TVPcCSHebEQp4LnapPkhb2pondb2Ed7GJJLc6TkKwtSyumUnQ6QzkCCkojZycH2MRfLcujCM7QR1gdnRULRraV4UpB5n4", // Xmr.to - "47sghzufGhJJDQEbScMCwVBimTuq6L5JiRixD8VeGbpjCTA12noXmi4ZyBZLc99e66NtnKff34fHsGRoyZk3ES1s1V4QVcB" // Poloniex - ]; // These are addresses that MUST have a paymentID to perform logins with. - - this.prefix = 18; - this.intPrefix = 19; - - if (global.config.general.testnet === true){ - this.prefix = 53; - this.intPrefix = 54; - } - - this.supportsAutoExchange = true; - - this.niceHashDiff = 400000; - - this.getBlockHeaderByID = function(blockId, callback){ - global.support.rpcDaemon('getblockheaderbyheight', {"height": blockId}, function (body) { - if (body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getBlockHeaderByHash = function(blockHash, callback){ - global.support.rpcDaemon('getblockheaderbyhash', {"hash": blockHash}, function (body) { - if (typeof(body) !== 'undefined' && body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getLastBlockHeader = function(callback){ - global.support.rpcDaemon('getlastblockheader', [], function (body) { - if (typeof(body) !== 'undefined' && body.hasOwnProperty('result')){ - return callback(null, body.result.block_header); - } else { - console.error(JSON.stringify(body)); - return callback(true, body); - } - }); - }; - - this.getBlockTemplate = function(walletAddress, callback){ - global.support.rpcDaemon('getblocktemplate', { - reserve_size: 17, - wallet_address: walletAddress - }, function(body){ - return callback(body); - }); - }; - - this.baseDiff = function(){ - return bignum('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 16); - }; - - this.validateAddress = function(address){ - // This function should be able to be called from the async library, as we need to BLOCK ever so slightly to verify the address. - address = new Buffer(address); - if (cnUtil.address_decode(address) === this.prefix){ - return true; - } - return cnUtil.address_decode_integrated(address) === this.intPrefix; - }; - - this.convertBlob = function(blobBuffer){ - return cnUtil.convert_blob(blobBuffer); - }; - - this.constructNewBlob = function(blockTemplate, NonceBuffer){ - return cnUtil.construct_block_blob(blockTemplate, NonceBuffer); - }; - - this.getBlockID = function(blockBuffer){ - return cnUtil.get_block_id(blockBuffer); - }; - - this.BlockTemplate = function(template) { - /* - Generating a block template is a simple thing. Ask for a boatload of information, and go from there. - Important things to consider. - The reserved space is 13 bytes long now in the following format: - Assuming that the extraNonce starts at byte 130: - |130-133|134-137|138-141|142-145| - |minerNonce/extraNonce - 4 bytes|instanceId - 4 bytes|clientPoolNonce - 4 bytes|clientNonce - 4 bytes| - This is designed to allow a single block template to be used on up to 4 billion poolSlaves (clientPoolNonce) - Each with 4 billion clients. (clientNonce) - While being unique to this particular pool thread (instanceId) - With up to 4 billion clients (minerNonce/extraNonce) - Overkill? Sure. But that's what we do here. Overkill. - */ - - // Set this.blob equal to the BT blob that we get from upstream. - this.blob = template.blocktemplate_blob; - this.idHash = crypto.createHash('md5').update(template.blocktemplate_blob).digest('hex'); - // Set this.diff equal to the known diff for this block. - this.difficulty = template.difficulty; - // Set this.height equal to the known height for this block. - this.height = template.height; - // Set this.reserveOffset to the byte location of the reserved offset. - this.reserveOffset = template.reserved_offset; - // Set this.buffer to the binary decoded version of the BT blob. - this.buffer = new Buffer(this.blob, 'hex'); - // Copy the Instance ID to the reserve offset + 4 bytes deeper. Copy in 4 bytes. - instanceId.copy(this.buffer, this.reserveOffset + 4, 0, 3); - // Generate a clean, shiny new buffer. - this.previous_hash = new Buffer(32); - // Copy in bytes 7 through 39 to this.previous_hash from the current BT. - this.buffer.copy(this.previous_hash, 0, 7, 39); - // Reset the Nonce. - This is the per-miner/pool nonce - this.extraNonce = 0; - // The clientNonceLocation is the location at which the client pools should set the nonces for each of their clients. - this.clientNonceLocation = this.reserveOffset + 12; - // The clientPoolLocation is for multi-thread/multi-server pools to handle the nonce for each of their tiers. - this.clientPoolLocation = this.reserveOffset + 8; - this.nextBlob = function () { - // Write a 32 bit integer, big-endian style to the 0 byte of the reserve offset. - this.buffer.writeUInt32BE(++this.extraNonce, this.reserveOffset); - // Convert the blob into something hashable. - return global.coinFuncs.convertBlob(this.buffer).toString('hex'); - }; - // Make it so you can get the raw block blob out. - this.nextBlobWithChildNonce = function () { - // Write a 32 bit integer, big-endian style to the 0 byte of the reserve offset. - this.buffer.writeUInt32BE(++this.extraNonce, this.reserveOffset); - // Don't convert the blob to something hashable. You bad. - return this.buffer.toString('hex'); - }; - }; - - this.cryptoNight = function(convertedBlob) { - return multiHashing.cryptonight(convertedBlob, convertedBlob[0] >= 8 ? 8 : 1); - } -} - -module.exports = Coin; diff --git a/lib/payment_systems/aeon-rebase.js b/lib/payment_systems/aeon-rebase.js deleted file mode 100644 index ff2059f..0000000 --- a/lib/payment_systems/aeon-rebase.js +++ /dev/null @@ -1,697 +0,0 @@ -"use strict"; -const shapeshift = require('shapeshift.io'); -const async = require("async"); -const debug = require("debug")("payments"); -const request = require('request-json'); -const range = require('range'); - -let hexChars = new RegExp("[0-9a-f]+"); -let bestExchange = global.config.payout.bestExchange; -let xmrAPIClient = request.createClient('https://xmr.to/api/v1/xmr2btc/'); -let extraPaymentRound = false; -let paymentTimer = null; - -let shapeshiftQueue = async.queue(function (task, callback) { - // Amount needs to be shifted in as a non-completed value, as the wallet will only take non-complete values.. - let amount = task.amount - task.fee; - // Address is the destination address IN BTC. - let address = task.address; - // PaymentIDs are the paymentID's to flag as paid by this transaction. - // Should be a massive list of ID's so we can bulk-update them, by merging them with 's. - // Here we go! General process: Scan shapeshift for valid amounts of funds to xfer around. - // Once there's enough funds, then we active txn - // Do a wallet call to xfer. - // Setup a monitor on the transaction - async.waterfall([ - function (intCallback) { - // Verify if the coin is active in ShapeShift first. - shapeshift.coins(function (err, coinData) { - if (err) { - intCallback(err); - } else if (!coinData.hasOwnProperty(global.config.general.coinCode) || coinData[global.config.general.coinCode].status !== "available") { - intCallback("Coin " + global.config.general.coinCode + " Is not available at this time on shapeshift."); - } else { - intCallback(null); - } - }); - }, - function (intCallback) { - // Get the market information from shapeshift, which includes deposit limits, minimum deposits, rates, etc. - shapeshift.marketInfo(global.config.payout.shapeshiftPair, function (err, marketInfo) { - if (err) { - intCallback(err); - } else if (!marketInfo.hasOwnProperty("limit") || marketInfo.limit <= global.support.coinToDecimal(amount)) { - intCallback("Not enough coin in shapeshift to process at this time."); - } else if (!marketInfo.hasOwnProperty("min") || marketInfo.min >= global.support.coinToDecimal(amount)) { - intCallback("Not enough coin to hit the shapeshift minimum deposits."); - } else { - intCallback(null, marketInfo); - } - }); - }, - function (marketInfo, intCallback) { - // Validated there's enough coin. Time to make our dank txn. - // Return: - /* - { - "orderId": "cc49c556-e645-4c15-a943-d50a935274e4", - "sAddress": "46yzCCD3Mza9tRj7aqPSaxVbbePtuAeKzf8Ky2eRtcXGcEgCg1iTBio6N4sPmznfgGEUGDoBz5CLxZ2XPTyZu1yoCAG7zt6", - "deposit": "d8041668718e6e9d9d0fd335ee5ecd923e6fd074c41316d041cc18b779ade10e", - "depositType": "XMR", - "withdrawal": "1DbxcoCBSA9N7uZvkcvWxuLxSau9q9Pwiu", - "withdrawalType": "BTC", - "public": null, - "apiPubKey": "shapeshift", - "returnAddress": "46XWBqE1iwsVxSDP1qDrxhE1XvsZV6eALG5LwnoMdjbT4GPdy2bZTb99kagzxp2MMjUamTYZ4WgvZdFadvMimTjvR6Gv8hL", - "returnAddressType": "XMR" - } - Valid Statuses: - "received" - "complete" - "error" - "no_deposits" - Complete State Information: - { - "status": "complete", - "address": "d8041668718e6e9d9d0fd335ee5ecd923e6fd074c41316d041cc18b779ade10e", - "withdraw": "1DbxcoCBSA9N7uZvkcvWxuLxSau9q9Pwiu", - "incomingCoin": 3, - "incomingType": "XMR", - "outgoingCoin": "0.04186155", - "outgoingType": "BTC", - "transaction": "be9d97f6fc75262151f8f63e035c6ed638b9eb2a4e93fef43ea63124b045dbfb" - } - */ - shapeshift.shift(address, global.config.payout.shapeshiftPair, {returnAddress: global.config.pool.address}, function (err, returnData) { - if (err) { - intCallback(err); - } else { - global.mysql.query("INSERT INTO shapeshiftTxn (id, address, paymentID, depositType, withdrawl, withdrawlType, returnAddress, returnAddressType, txnStatus) VALUES (?,?,?,?,?,?,?,?,?)", - [returnData.orderId, returnData.sAddress, returnData.deposit, returnData.depositType, returnData.withdrawl, returnData.withdrawlType, returnData.returnAddress, returnData.returnAddressType, 'no_deposits']).then(function () { - intCallback(null, marketInfo, returnData); - }).catch(function (error) { - intCallback(error); - }); - } - }); - }, - function (marketInfo, shapeshiftTxnData, intCallback) { - // Make the payment to ShapeShift - let paymentDetails = { - destinations: [ - { - amount: amount, - address: shapeshiftTxnData.sAddress - } - ], - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn, - payment_id: shapeshiftTxnData.deposit - }; - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (body.fee && body.fee > 10) { - intCallback(null, marketInfo, shapeshiftTxnData, body); - } else { - intCallback("Unknown error from the wallet."); - } - }); - }, - function (marketInfo, shapeshiftTxnData, body, intCallback) { - // body.tx_hash = XMR transaction hash. - // Need to add transaction. - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees, exchange_rate, exchange_name, exchange_txn_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - [1, address, null, task.amount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, global.support.decimalToCoin(marketInfo.minerFee), 1, global.support.decimalToCoin(marketInfo.rate), 'shapeshift', shapeshiftTxnData.orderId]).then(function (result) { - intCallback(null, result.insertId); - }).catch(function (error) { - intCallback(error); - }); - } - ], function (err, result) { - if (err) { - console.error("Error processing shapeshift txn: " + JSON.stringify(err)); - callback(true); - } else { - // Need to fill out this data pronto! - console.log("Processed ShapeShift transaction for: " + address + " Paid out: " + result + " payments in the db"); - callback(null, result); - } - }); -}, 2); - -let xmrToQueue = async.queue(function (task, callback) { - // http://xmrto-api.readthedocs.io/en/latest/introduction.html - // Documentation looks good! - // Amount needs to be shifted in as a non-completed value, as the wallet will only take non-complete values.. - let amount = task.amount - task.fee; - // Address is the destination address IN BTC. - let address = task.address; - // PaymentIDs are the paymentID's to flag as paid by this transaction. - // Should be a massive list of ID's so we can bulk-update them, by merging them with 's. - // Here we go! General process: Scan shapeshift for valid amounts of funds to xfer around. - // Once there's enough funds, then we active txn - // Do a wallet call to xfer. - // Setup a monitor on the transaction - async.waterfall([ - function (intCallback) { - // Verify if XMR.to is ready to get to work. - xmrAPIClient.get('order_parameter_query/', function (err, res, body) { - if (err) { - return intCallback(err); - } else if (body.error_msg) { - return intCallback(body.error_msg); - } else { - let amtOfBTC = ((amount / global.config.general.sigDivisor) * body.price).toPrecision(5); - console.log("Attempting to pay: " + address + " Amount: " + amtOfBTC + " BTC or " + amount / global.config.general.sigDivisor + " XMR"); - console.log("Response from XMR.to: " + JSON.stringify(body)); - if (body.lower_limit >= amtOfBTC) { - return intCallback("Not enough XMR to hit the minimum deposit"); - } else if (body.upper_limit <= amtOfBTC) { - return intCallback("Too much XMR to pay out to xmr.to"); - } else { - return intCallback(null, amtOfBTC); - } - } - }); - }, - function (btcValue, intCallback) { - // Validated there's enough coin. Time to make our dank txn. - // Return: - /* - { - "state": "TO_BE_CREATED", - "btc_amount": , - "btc_dest_address": "", - "uuid": "" - } - Valid Statuses: - "TO_BE_CREATED" - "UNPAID" - "UNDERPAID" - "PAID_UNCONFIRMED" - "PAID" - "BTC_SENT" - "TIMED_OUT" - "NOT_FOUND" - // Create, then immediately update with the new information w/ a status call. - */ - console.log("Amount of BTC to pay: " + btcValue); - xmrAPIClient.post('order_create/', { - btc_amount: btcValue, - btc_dest_address: address - }, function (err, res, body) { - if (err) { - return intCallback(err); - } else if (body.error_msg) { - return intCallback(body.error_msg); - } else { - return intCallback(null, body.uuid); - } - }); - }, - function (txnID, intCallback) { - // This function only exists because xmr.to is a pretty little fucking princess. - async.doUntil(function (xmrCallback) { - xmrAPIClient.post('order_status_query/', {uuid: txnID}, function (err, res, body) { - if (err) { - return intCallback(err); - } else if (body.error_msg) { - return intCallback(body.error_msg); - } else { - xmrCallback(null, body.state); - } - }); - }, - function (xmrCallback) { - return xmrCallback !== "TO_BE_CREATED"; - }, - function () { - intCallback(null, txnID); - }); - }, - function (txnID, intCallback) { - xmrAPIClient.post('order_status_query/', {uuid: txnID}, function (err, res, body) { - if (err) { - return intCallback(err); - } else if (body.error_msg) { - return intCallback(body.error_msg); - } else { - console.log(JSON.stringify(body)); - global.mysql.query("INSERT INTO xmrtoTxn (id, address, paymentID, depositType, withdrawl, withdrawlType, returnAddress, returnAddressType, txnStatus, amountDeposited, amountSent) VALUES (?,?,?,?,?,?,?,?,?,?,?)", - [txnID, body.xmr_receiving_address, body.xmr_required_payment_id_long, 'XMR', body.btc_dest_address, 'BTC', global.config.pool.address, 'XMR', body.state_str, global.support.decimalToCoin(body.xmr_amount_total), global.support.decimalToCoin(body.btc_amount)]).then(function () { - return intCallback(null, body, global.support.decimalToCoin(body.xmr_amount_total)); - }).catch(function (error) { - return intCallback(error); - }); - } - }); - }, - function (orderStatus, xmrDeposit, intCallback) { - // Make the payment to ShapeShift - let paymentDetails = { - destinations: [ - { - amount: xmrDeposit, - address: orderStatus.xmr_receiving_address - } - ], - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn, - payment_id: orderStatus.xmr_required_payment_id_long - }; - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (body.fee && body.fee > 10) { - return intCallback(null, orderStatus, body); - } else { - return intCallback("Unknown error from the wallet."); - } - }); - }, - function (orderStatus, body, intCallback) { - // body.tx_hash = XMR transaction hash. - // Need to add transaction. - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees, exchange_rate, exchange_name, exchange_txn_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - [1, address, null, global.support.decimalToCoin(orderStatus.xmr_amount_total), body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, 1, global.support.decimalToCoin(orderStatus.xmr_price_btc), 'xmrto', orderStatus.uuid]).then(function (result) { - return intCallback(null, result.insertId); - }).catch(function (error) { - return intCallback(error); - }); - } - ], function (err, result) { - if (err) { - console.error("Error processing XMRTo txn: " + JSON.stringify(err)); - return callback("Error!"); - } else { - // Need to fill out this data pronto! - console.log("Processed XMRTo transaction for: " + address + " Paid out: " + result + " payments in the db"); - return callback(null, result); - } - }); -}, 2); - -let paymentQueue = async.queue(function (paymentDetails, callback) { - /* - support JSON URI: http://10.0.0.2:28082/json_rpc Args: {"id":"0","jsonrpc":"2.0","method":"transfer","params":{"destinations":[{"amount":68130252045355,"address":"A2MSrn49ziBPJBh8ZNEhhbfyLMou6mao4C1F5TLGUatmUnCxZArDYkcbAnVkVEopWVeak2rKDrmc8JpoS7n5dvfN9YDPBTG"}],"mixin":4,"payment_id":"7e52c5266de9fede7fb3abc0cd88f937b38b51426f7b34ff99729d28ce4e1142"}} +1ms - payments Payment made: {"id":"0","jsonrpc":"2.0","result":{"fee":40199391255,"tx_hash":"c418708643f72635edf522490bfb2cae9d42a6dc1df30dcde844862dfd88f5b3","tx_key":""}} +2s - */ - if (paymentTimer !== null){ - clearInterval(paymentTimer); - paymentTimer = null; - } - debug("Making payment based on: " + JSON.stringify(paymentDetails)); - let transferFunc = 'transfer'; - global.support.rpcWallet(transferFunc, paymentDetails, function (body) { - debug("Payment made: " + JSON.stringify(body)); - if (body.hasOwnProperty('error')) { - if (body.error.message === "not enough money"){ - console.error("Issue making payments, not enough money, will try later"); - if(!extraPaymentRound){ - setTimeout(function(){ - makePayments(); - }, global.config.payout.timerRetry * 60 * 1000); - } - extraPaymentRound = true; - return callback(false); - } else { - console.error("Issue making payments" + JSON.stringify(body.error)); - console.error("Will not make more payments until the payment daemon is restarted!"); - //toAddress, subject, body - global.support.sendEmail(global.config.general.adminEmail, "Payment daemon unable to make payment", - "Hello,\r\nThe payment daemon has hit an issue making a payment: " + JSON.stringify(body.error) + - ". Please investigate and restart the payment daemon as appropriate"); - return; - } - } - if (paymentDetails.hasOwnProperty('payment_id')) { - console.log("Payment made to " + paymentDetails.destinations[0].address + " with PaymentID: " + paymentDetails.payment_id + " For: " + global.support.coinToDecimal(paymentDetails.destinations[0].amount) + " AEON with a " + global.support.coinToDecimal(body.result.fee) + " AEON Mining Fee"); - return callback(body.result); - } else { - if (transferFunc === 'transfer') { - console.log(body); - console.log("Payment made out to multiple people, total fee: " + global.support.coinToDecimal(body.result.fee) + " AEON"); - } - let intCount = 0; - paymentDetails.destinations.forEach(function (details) { - console.log("Payment made to: " + details.address + " For: " + global.support.coinToDecimal(details.amount) + " AEON"); - intCount += 1; - if (intCount === paymentDetails.destinations.length) { - return callback(body.result); - } - }); - } - }); -}, 1); - -paymentQueue.drain = function(){ - extraPaymentRound = false; - if (global.config.payout.timer > 35791){ - console.error("Payout timer is too high. Please use a value under 35791 to avoid overflows."); - } else { - paymentTimer = setInterval(makePayments, global.config.payout.timer * 60 * 1000); - } - global.database.setCache('lastPaymentCycle', Math.floor(Date.now()/1000)); -}; - -function updateShapeshiftCompletion() { - global.mysql.query("SELECT * FROM shapeshiftTxn WHERE txnStatus NOT IN ('complete', 'error')").then(function (rows) { - rows.forEach(function (row) { - shapeshift.status(row.paymentID, function (err, status, returnData) { - if (err) { - return; - } - global.mysql.query("UPDATE shapeshiftTxn SET txnStatus = ? WHERE id = ?", [status, row.id]).then(function () { - if (status === 'complete') { - global.mysql.query("UPDATE shapeshiftTxn SET amountDeposited = ?, amountSent = ?, transactionHash = ? WHERE id = ?", - [global.support.decimalToCoin(returnData.incomingCoin), global.support.bitcoinDecimalToCoin(returnData.outgoingCoin), returnData.transaction, row.id]).then(function () { - global.mysql.query("UPDATE transactions SET confirmed = 1, confirmed_time = now(), btc_amt = ? WHERE exchange_txn_id = ?", [global.support.bitcoinDecimalToCoin(returnData.outgoingCoin), row.id]); - }); - } else if (status === 'error') { - // Failed txn. Need to rollback and delete all related data. Here we go! - global.mysql.query("DELETE FROM shapeshiftTxn WHERE id = ?", [row.id]); - global.mysql.query("SELECT id, xmr_amt, address FROM transactions WHERE exchange_txn_id = ?", [row.id]).then(function (rows) { - global.mysql.query("DELETE FROM transactions WHERE id = ?", [rows[0].id]); - global.mysql.query("DELETE payments WHERE transaction_id = ?", [rows[0].id]); - global.mysql.query("UPDATE balance SET amount = amount+? WHERE payment_address = ? limit 1", [rows[0].xmr_amt, rows[0].address]); - }); - console.error("Failed transaction from ShapeShift " + JSON.stringify(returnData)); - } - }); - }); - }); - }); -} - -function updateXMRToCompletion() { - global.mysql.query("SELECT * FROM xmrtoTxn WHERE txnStatus NOT IN ('PAID', 'TIMED_OUT', 'NOT_FOUND', 'BTC_SENT')").then(function (rows) { - rows.forEach(function (row) { - xmrAPIClient.post('order_status_query/', {uuid: row.id}, function (err, res, body) { - if (err) { - console.log("Error in getting order status: " + JSON.stringify(err)); - return; - } - if (body.error_msg) { - console.log("Error in getting order status: " + body.error_msg); - return; - } - global.mysql.query("UPDATE xmrtoTxn SET txnStatus = ? WHERE id = ?", [body.state, row.id]).then(function () { - if (body.status === 'BTC_SENT') { - global.mysql.query("UPDATE xmrtoTxn SET transactionHash = ? WHERE id = ?", [body.btc_transaction_id, row.id]).then(function () { - global.mysql.query("UPDATE transactions SET confirmed = 1, confirmed_time = now(), btc_amt = ? WHERE exchange_txn_id = ?", [global.support.bitcoinDecimalToCoin(body.btc_amount), row.id]); - }); - } else if (body.status === 'TIMED_OUT' || body.status === 'NOT_FOUND') { - global.mysql.query("DELETE FROM xmrtoTxn WHERE id = ?", [row.id]); - global.mysql.query("SELECT id, xmr_amt, address FROM transactions WHERE exchange_txn_id = ?", [row.id]).then(function (rows) { - global.mysql.query("DELETE FROM transactions WHERE id = ?", [rows[0].id]); - global.mysql.query("DELETE payments WHERE transaction_id = ?", [rows[0].id]); - global.mysql.query("UPDATE balance SET amount = amount+? WHERE payment_address = ? limit 1", [rows[0].xmr_amt, rows[0].address]); - }); - console.error("Failed transaction from XMRto " + JSON.stringify(body)); - } - }); - }); - }); - }); -} - -function determineBestExchange() { - async.waterfall([ - function (callback) { - // Verify if the coin is active in ShapeShift first. - shapeshift.coins(function (err, coinData) { - if (err) { - return callback(err); - } else if (!coinData.hasOwnProperty(global.config.general.coinCode) || coinData[global.config.general.coinCode].status !== "available") { - return callback("Coin " + global.config.general.coinCode + " Is not available at this time on shapeshift."); - } else { - return callback(null); - } - }); - }, - function (callback) { - // Get the market information from shapeshift, which includes deposit limits, minimum deposits, rates, etc. - shapeshift.marketInfo(global.config.payout.shapeshiftPair, function (err, marketInfo) { - if (err) { - return callback(err); - } else if (!marketInfo.hasOwnProperty("rate")) { - return callback("Shapeshift did not return the rate."); - } else { - return callback(null, global.support.bitcoinDecimalToCoin(marketInfo.rate)); - } - }); - }, - function (ssValue, callback) { - xmrAPIClient.get('order_parameter_query/', function (err, res, body) { - console.log("XMR.to pricing body: " + JSON.stringify(body)); - if (err) { - return callback(err); - } else if (body.error_msg) { - return callback(body.error_msg); - } else { - return callback(null, ssValue, global.support.bitcoinDecimalToCoin(body.price)); - } - }); - } - ], function (err, ssValue, xmrToValue) { - if (err) { - return console.error("Error processing exchange value: " + JSON.stringify(err)); - } - debug("ShapeShift Value: " + global.support.bitcoinCoinToDecimal(ssValue) + " XMR.to Value: " + global.support.bitcoinCoinToDecimal(xmrToValue)); - if (ssValue >= xmrToValue) { - console.log("ShapeShift is the better BTC exchange, current rate: " + global.support.bitcoinCoinToDecimal(ssValue)); - bestExchange = 'shapeshift'; - global.mysql.query("UPDATE config SET item_value = 'shapeshift' where item='bestExchange'"); - global.mysql.query("UPDATE config SET item_value = ? where item='exchangeRate'", [ssValue]); - } else { - console.log("XMR.to is the better BTC exchange, current rate: " + global.support.bitcoinCoinToDecimal(xmrToValue)); - bestExchange = 'xmrto'; - global.mysql.query("UPDATE config SET item_value = 'xmrto' where item='bestExchange'"); - global.mysql.query("UPDATE config SET item_value = ? where item='exchangeRate'", [xmrToValue]); - } - }); -} - -function Payee(amount, address, paymentID, bitcoin) { - this.amount = amount; - this.address = address; - this.paymentID = paymentID; - this.bitcoin = bitcoin; - this.blockID = 0; - this.poolType = ''; - this.transactionID = 0; - this.sqlID = 0; - if (paymentID === null) { - this.id = address; - } else { - this.id = address + "." + paymentID; - } - this.fee = 0; - this.baseFee = global.support.decimalToCoin(global.config.payout.feeSlewAmount); - this.setFeeAmount = function () { - if (this.amount <= global.support.decimalToCoin(global.config.payout.walletMin)) { - this.fee = this.baseFee; - } else if (this.amount <= global.support.decimalToCoin(global.config.payout.feeSlewEnd)) { - let feeValue = this.baseFee / (global.support.decimalToCoin(global.config.payout.feeSlewEnd) - global.support.decimalToCoin(global.config.payout.walletMin)); - this.fee = this.baseFee - ((this.amount - global.support.decimalToCoin(global.config.payout.walletMin)) * feeValue); - } - this.fee = Math.floor(this.fee); - }; - - this.makePaymentWithID = function () { - let paymentDetails = { - destinations: [ - { - amount: this.amount - this.fee, - address: this.address - } - ], - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn, - payment_id: this.paymentID - }; - let identifier = this.id; - let amount = this.amount; - let address = this.address; - let paymentID = this.paymentID; - let payee = this; - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (body.fee && body.fee > 10) { - debug("Successful payment sent to: " + identifier); - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - [0, address, paymentID, amount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, 1]).then(function (result) { - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - }; - - this.makePaymentAsIntegrated = function () { - let paymentDetails = { - destinations: [ - { - amount: this.amount - this.fee, - address: this.address - } - ], - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn - }; - let identifier = this.id; - let amount = this.amount; - let address = this.address; - let payee = this; - - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (body.fee && body.fee > 10) { - debug("Successful payment sent to: " + identifier); - global.mysql.query("INSERT INTO transactions (bitcoin, address, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?)", - [0, address, amount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, 1]).then(function (result) { - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - }; - - this.makeBitcoinPayment = function () { - let functionalData = {address: this.address, amount: this.amount, fee: this.fee}; - let payee = this; - if (bestExchange === 'xmrto') { - xmrToQueue.push(functionalData, function (err, transactionID) { - if (err) { - return console.error("Error processing payment for " + functionalData.address); - } - payee.transactionID = transactionID; - payee.trackPayment(); - }); - } else { - shapeshiftQueue.push(functionalData, function (err, transactionID) { - if (err) { - return console.error("Error processing payment for " + functionalData.address); - } - payee.transactionID = transactionID; - payee.trackPayment(); - }); - } - }; - - this.trackPayment = function () { - global.mysql.query("UPDATE balance SET amount = amount - ? WHERE id = ?", [this.amount, this.sqlID]); - global.mysql.query("INSERT INTO payments (unlocked_time, paid_time, pool_type, payment_address, transaction_id, bitcoin, amount, payment_id, transfer_fee)" + - " VALUES (now(), now(), ?, ?, ?, ?, ?, ?, ?)", [this.poolType, this.address, this.transactionID, this.bitcoin, this.amount - this.fee, this.paymentID, this.fee]); - }; -} - -function makePayments() { - global.mysql.query("SELECT * FROM balance WHERE amount >= ?", [global.support.decimalToCoin(global.config.payout.walletMin)]).then(function (rows) { - console.log("Loaded all payees into the system for processing"); - let paymentDestinations = []; - let totalAmount = 0; - let roundCount = 0; - let payeeList = []; - let payeeObjects = {}; - rows.forEach(function (row) { - debug("Starting round for: " + JSON.stringify(row)); - let payee = new Payee(row.amount, row.payment_address, row.payment_id, row.bitcoin); - payeeObjects[row.payment_address] = payee; - global.mysql.query("SELECT payout_threshold FROM users WHERE username = ?", [payee.id]).then(function (userRow) { - roundCount += 1; - let threshold = 0; - if (userRow.length !== 0) { - threshold = userRow[0].payout_threshold; - } - payee.poolType = row.pool_type; - payee.sqlID = row.id; - if (payee.poolType === "fees" && payee.address === global.config.payout.feeAddress && payee.amount >= ((global.support.decimalToCoin(global.config.payout.feesForTXN) + global.support.decimalToCoin(global.config.payout.exchangeMin)))) { - debug("This is the fee address internal check for value"); - payee.amount -= global.support.decimalToCoin(global.config.payout.feesForTXN); - } else if (payee.address === global.config.payout.feeAddress && payee.poolType === "fees") { - debug("Unable to pay fee address."); - payee.amount = 0; - } - let remainder = payee.amount % (global.config.payout.denom * global.config.general.sigDivisor); - if (remainder !== 0) { - payee.amount -= remainder; - } - if (payee.amount > threshold) { - payee.setFeeAmount(); - if (payee.bitcoin === 0 && payee.paymentID === null && payee.amount !== 0 && payee.amount > 0 && payee.address.length !== 106) { - debug("Adding " + payee.id + " to the list of people to pay (OG Address). Payee balance: " + global.support.coinToDecimal(payee.amount)); - paymentDestinations.push({amount: payee.amount - payee.fee, address: payee.address}); - totalAmount += payee.amount; - payeeList.push(payee); - } else if (payee.bitcoin === 0 && payee.paymentID === null && payee.amount !== 0 && payee.amount > 0 && payee.address.length === 106 && (payee.amount >= global.support.decimalToCoin(global.config.payout.exchangeMin) || (payee.amount > threshold && threshold !== 0))) { - // Special code to handle integrated payment addresses. What a pain in the rear. - // These are exchange addresses though, so they need to hit the exchange payout amount. - debug("Adding " + payee.id + " to the list of people to pay (Integrated Address). Payee balance: " + global.support.coinToDecimal(payee.amount)); - payee.makePaymentAsIntegrated(); - } else if ((payee.amount >= global.support.decimalToCoin(global.config.payout.exchangeMin) || (payee.amount > threshold && threshold !== 0)) && payee.bitcoin === 0) { - debug("Adding " + payee.id + " to the list of people to pay (Payment ID Address). Payee balance: " + global.support.coinToDecimal(payee.amount)); - payee.makePaymentWithID(); - } else if ((payee.amount >= global.support.decimalToCoin(global.config.payout.exchangeMin) || (payee.amount > threshold && threshold !== 0)) && payee.bitcoin === 1) { - debug("Adding " + payee.id + " to the list of people to pay (Bitcoin Payout). Payee balance: " + global.support.coinToDecimal(payee.amount)); - payee.makeBitcoinPayment(); - } - } - debug("Went: " + roundCount + " With: " + paymentDestinations.length + " Possible destinations and: " + rows.length + " Rows"); - if (roundCount === rows.length && paymentDestinations.length > 0) { - while (paymentDestinations.length > 0) { - let paymentDetails = { - destinations: paymentDestinations.splice(0, global.config.payout.maxPaymentTxns), - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn - }; - console.log("Paying out: " + paymentDetails.destinations.length + " people"); - paymentQueue.push(paymentDetails, function (body) { //jshint ignore:line - // This is the only section that could potentially contain multiple txns. Lets do this safely eh? - if (body.fee && body.fee > 10) { - debug("Made it to the SQL insert for transactions"); - let totalAmount = 0; - paymentDetails.destinations.forEach(function (payeeItem) { - totalAmount += payeeObjects[payeeItem.address].amount; - totalAmount += payeeObjects[payeeItem.address].fee; - }); - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - [0, null, null, totalAmount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, paymentDetails.destinations.length]).then(function (result) { - paymentDetails.destinations.forEach(function (payeeItem) { - payee = payeeObjects[payeeItem.address]; - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - } - } - }); - }); - }); -} - -function init() { - global.support.rpcWallet("store", [], function () { - }); - if (global.config.allowBitcoin) { - determineBestExchange(); - setInterval(updateXMRToCompletion, 90000); - setInterval(updateShapeshiftCompletion, 90000); - setInterval(determineBestExchange, 60000); - } - setInterval(function () { - global.support.rpcWallet("store", [], function () { - }); - }, 60000); - console.log("Setting the payment timer to: " + global.config.payout.timer + " minutes with a: " + global.config.payout.timerRetry + " minute delay if the wallet is out of money"); - makePayments(); -} - -init(); \ No newline at end of file diff --git a/lib/payment_systems/aeon.js b/lib/payment_systems/aeon.js deleted file mode 100644 index 28ba1a9..0000000 --- a/lib/payment_systems/aeon.js +++ /dev/null @@ -1,257 +0,0 @@ -"use strict"; -const async = require("async"); -const debug = require("debug")("payments"); - -let hexChars = new RegExp("[0-9a-f]+"); -let extraPaymentRound = false; -let paymentTimer = null; - -let paymentQueue = async.queue(function (paymentDetails, callback) { - if (paymentTimer !== null){ - clearInterval(paymentTimer); - paymentTimer = null; - } - debug("Making payment based on: " + JSON.stringify(paymentDetails)); - let transferFunc = 'transfer'; - global.support.rpcWallet(transferFunc, paymentDetails, function (body) { - debug("Payment made: " + JSON.stringify(body)); - if (body.hasOwnProperty('error')) { - if (body.error.message === "not enough money"){ - console.error("Issue making payments, not enough money, will try later"); - if(!extraPaymentRound){ - setTimeout(function(){ - makePayments(); - }, global.config.payout.timerRetry * 60 * 1000); - } - extraPaymentRound = true; - return callback(false); - } else { - console.error("Issue making payments" + JSON.stringify(body.error)); - console.error("Will not make more payments until the payment daemon is restarted!"); - //toAddress, subject, body - global.support.sendEmail(global.config.general.adminEmail, "Payment daemon unable to make payment", - "Hello,\r\nThe payment daemon has hit an issue making a payment: " + JSON.stringify(body.error) + - ". Please investigate and restart the payment daemon as appropriate"); - return; - } - } - if (paymentDetails.hasOwnProperty('payment_id')) { - console.log("Payment made to " + paymentDetails.destinations[0].address + " with PaymentID: " + paymentDetails.payment_id + " For: " + global.support.coinToDecimal(paymentDetails.destinations[0].amount) + " XMR with a " + global.support.coinToDecimal(body.result.fee) + " XMR Mining Fee"); - return callback(body.result); - } else { - if (transferFunc === 'transfer') { - console.log("Payment made out to multiple people, total fee: " + global.support.coinToDecimal(body.result.fee) + " XMR"); - } - let intCount = 0; - paymentDetails.destinations.forEach(function (details) { - console.log("Payment made to: " + details.address + " For: " + global.support.coinToDecimal(details.amount) + " XMR"); - intCount += 1; - if (intCount === paymentDetails.destinations.length) { - return callback(body.result); - } - }); - } - }); -}, 1); - -paymentQueue.drain = function(){ - extraPaymentRound = false; - if (global.config.payout.timer > 35791){ - console.error("Payout timer is too high. Please use a value under 35791 to avoid overflows."); - } else { - paymentTimer = setInterval(makePayments, global.config.payout.timer * 60 * 1000); - } - global.database.setCache('lastPaymentCycle', Math.floor(Date.now()/1000)); -}; - -function Payee(amount, address, paymentID, bitcoin) { - this.amount = amount; - this.address = address; - this.paymentID = paymentID; - this.bitcoin = bitcoin; - this.blockID = 0; - this.poolType = ''; - this.transactionID = 0; - this.sqlID = 0; - if (paymentID === null) { - this.id = address; - } else { - this.id = address + "." + paymentID; - } - this.fee = 0; - this.baseFee = global.support.decimalToCoin(global.config.payout.feeSlewAmount); - this.setFeeAmount = function () { - if (this.amount <= global.support.decimalToCoin(global.config.payout.walletMin)) { - this.fee = this.baseFee; - } else if (this.amount <= global.support.decimalToCoin(global.config.payout.feeSlewEnd)) { - let feeValue = this.baseFee / (global.support.decimalToCoin(global.config.payout.feeSlewEnd) - global.support.decimalToCoin(global.config.payout.walletMin)); - this.fee = this.baseFee - ((this.amount - global.support.decimalToCoin(global.config.payout.walletMin)) * feeValue); - } - this.fee = Math.floor(this.fee); - }; - - this.makePaymentWithID = function () { - let paymentDetails = { - destinations: [ - { - amount: this.amount - this.fee, - address: this.address - } - ], - fee: global.config.payout.fee, - unlock_time: global.config.payout.unlock_time, - mixin: global.config.payout.mixIn, - payment_id: this.paymentID - }; - let identifier = this.id; - let amount = this.amount; - let address = this.address; - let paymentID = this.paymentID; - let payee = this; - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (typeof body.tx_hash !== 'undefined') { - debug("Successful payment sent to: " + identifier); - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - [0, address, paymentID, amount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, global.config.payout.fee, 1]).then(function (result) { - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - }; - - this.makePaymentAsIntegrated = function () { - let paymentDetails = { - destinations: [ - { - amount: this.amount - this.fee, - address: this.address - } - ], - fee: global.config.payout.fee, - unlock_time: global.config.payout.unlock_time, - mixin: global.config.payout.mixIn - }; - let identifier = this.id; - let amount = this.amount; - let address = this.address; - let payee = this; - - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (typeof body.tx_hash !== 'undefined') { - debug("Successful payment sent to: " + identifier); - global.mysql.query("INSERT INTO transactions (bitcoin, address, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?)", - [0, address, amount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, global.config.payout.fee, 1]).then(function (result) { - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - }; - - this.trackPayment = function () { - global.mysql.query("UPDATE balance SET amount = amount - ? WHERE id = ?", [this.amount, this.sqlID]); - global.mysql.query("INSERT INTO payments (unlocked_time, paid_time, pool_type, payment_address, transaction_id, bitcoin, amount, payment_id, transfer_fee)" + - " VALUES (now(), now(), ?, ?, ?, ?, ?, ?, ?)", [this.poolType, this.address, this.transactionID, this.bitcoin, this.amount - this.fee, this.paymentID, this.fee]); - }; -} - -function makePayments() { - global.mysql.query("SELECT * FROM balance WHERE amount >= ?", [global.support.decimalToCoin(global.config.payout.walletMin)]).then(function (rows) { - console.log("Loaded all payees into the system for processing"); - let paymentDestinations = []; - let totalAmount = 0; - let roundCount = 0; - let payeeList = []; - let payeeObjects = {}; - rows.forEach(function (row) { - debug("Starting round for: " + JSON.stringify(row)); - let payee = new Payee(row.amount, row.payment_address, row.payment_id, row.bitcoin); - payeeObjects[row.payment_address] = payee; - global.mysql.query("SELECT payout_threshold FROM users WHERE username = ?", [payee.id]).then(function (userRow) { - roundCount += 1; - let threshold = 0; - if (userRow.length !== 0) { - threshold = userRow[0].payout_threshold; - } - payee.poolType = row.pool_type; - payee.sqlID = row.id; - if (payee.poolType === "fees" && payee.address === global.config.payout.feeAddress && payee.amount >= ((global.support.decimalToCoin(global.config.payout.feesForTXN) + global.support.decimalToCoin(global.config.payout.exchangeMin)))) { - debug("This is the fee address internal check for value"); - payee.amount -= global.support.decimalToCoin(global.config.payout.feesForTXN); - } else if (payee.address === global.config.payout.feeAddress && payee.poolType === "fees") { - debug("Unable to pay fee address."); - payee.amount = 0; - } - let remainder = payee.amount % (global.config.payout.denom * global.config.general.sigDivisor); - if (remainder !== 0) { - payee.amount -= remainder; - } - if (payee.amount > threshold) { - payee.setFeeAmount(); - if (payee.bitcoin === 0 && payee.paymentID === null && payee.amount !== 0 && payee.amount > 0 && payee.address.length !== 106) { - debug("Adding " + payee.id + " to the list of people to pay (OG Address). Payee balance: " + global.support.coinToDecimal(payee.amount)); - paymentDestinations.push({amount: payee.amount - payee.fee, address: payee.address}); - totalAmount += payee.amount; - payeeList.push(payee); - } else if ((payee.amount >= global.support.decimalToCoin(global.config.payout.exchangeMin) || (payee.amount > threshold && threshold !== 0)) && payee.bitcoin === 0) { - debug("Adding " + payee.id + " to the list of people to pay (Payment ID Address). Payee balance: " + global.support.coinToDecimal(payee.amount)); - payee.makePaymentWithID(); - } - } - debug("Went: " + roundCount + " With: " + paymentDestinations.length + " Possible destinations and: " + rows.length + " Rows"); - if (roundCount === rows.length && paymentDestinations.length > 0) { - while (paymentDestinations.length > 0) { - let paymentDetails = { - destinations: paymentDestinations.splice(0, global.config.payout.maxPaymentTxns), - mixin: global.config.payout.mixIn, - fee: global.config.payout.fee, - unlock_time: global.config.payout.unlock_time - }; - console.log("Paying out: " + paymentDetails.destinations.length + " people"); - paymentQueue.push(paymentDetails, function (body) { //jshint ignore:line - // This is the only section that could potentially contain multiple txns. Lets do this safely eh? - if (typeof body.tx_hash !== 'undefined') { - debug("Made it to the SQL insert for transactions"); - let totalAmount = 0; - paymentDetails.destinations.forEach(function (payeeItem) { - totalAmount += payeeObjects[payeeItem.address].amount; - totalAmount += payeeObjects[payeeItem.address].fee; - }); - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - [0, null, null, totalAmount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, global.config.payout.fee, paymentDetails.destinations.length]).then(function (result) { - paymentDetails.destinations.forEach(function (payeeItem) { - payee = payeeObjects[payeeItem.address]; - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - } - } - }); - }); - }); -} - -function init() { - global.support.rpcWallet("store", [], function () { - }); - setInterval(function () { - global.support.rpcWallet("store", [], function () { - }); - }, 60000); - console.log("Setting the payment timer to: " + global.config.payout.timer + " minutes with a: " + global.config.payout.timerRetry + " minute delay if the wallet is out of money"); - makePayments(); -} - -init(); \ No newline at end of file diff --git a/lib/payment_systems/krb.js b/lib/payment_systems/krb.js deleted file mode 100644 index bc907c1..0000000 --- a/lib/payment_systems/krb.js +++ /dev/null @@ -1,254 +0,0 @@ -"use strict"; -const async = require("async"); -const debug = require("debug")("payments"); - -let hexChars = new RegExp("[0-9a-f]+"); -let extraPaymentRound = false; -let paymentTimer = null; - -let paymentQueue = async.queue(function (paymentDetails, callback) { - if (paymentTimer !== null){ - clearInterval(paymentTimer); - paymentTimer = null; - } - debug("Making payment based on: " + JSON.stringify(paymentDetails)); - let transferFunc = 'transfer'; - global.support.rpcWallet(transferFunc, paymentDetails, function (body) { - debug("Payment made: " + JSON.stringify(body)); - if (body.hasOwnProperty('error')) { - if (body.error.message === "not enough money"){ - console.error("Issue making payments, not enough money, will try later"); - if(!extraPaymentRound){ - setTimeout(function(){ - makePayments(); - }, global.config.payout.timerRetry * 60 * 1000); - } - extraPaymentRound = true; - return callback(false); - } else { - console.error("Issue making payments" + JSON.stringify(body.error)); - console.error("Will not make more payments until the payment daemon is restarted!"); - //toAddress, subject, body - global.support.sendEmail(global.config.general.adminEmail, "Payment daemon unable to make payment", - "Hello,\r\nThe payment daemon has hit an issue making a payment: " + JSON.stringify(body.error) + - ". Please investigate and restart the payment daemon as appropriate"); - return; - } - } - if (paymentDetails.hasOwnProperty('payment_id')) { - console.log("Payment made to " + paymentDetails.destinations[0].address + " with PaymentID: " + paymentDetails.payment_id + " For: " + global.support.coinToDecimal(paymentDetails.destinations[0].amount) + " XMR with a " + global.support.coinToDecimal(body.result.fee) + " XMR Mining Fee"); - return callback(body.result); - } else { - if (transferFunc === 'transfer') { - console.log("Payment made out to multiple people, total fee: " + global.support.coinToDecimal(body.result.fee) + " XMR"); - } - let intCount = 0; - paymentDetails.destinations.forEach(function (details) { - console.log("Payment made to: " + details.address + " For: " + global.support.coinToDecimal(details.amount) + " XMR"); - intCount += 1; - if (intCount === paymentDetails.destinations.length) { - return callback(body.result); - } - }); - } - }); -}, 1); - -paymentQueue.drain = function(){ - extraPaymentRound = false; - if (global.config.payout.timer > 35791){ - console.error("Payout timer is too high. Please use a value under 35791 to avoid overflows."); - } else { - paymentTimer = setInterval(makePayments, global.config.payout.timer * 60 * 1000); - } - global.database.setCache('lastPaymentCycle', Math.floor(Date.now()/1000)); -}; - -function Payee(amount, address, paymentID, bitcoin) { - this.amount = amount; - this.address = address; - this.paymentID = paymentID; - this.bitcoin = bitcoin; - this.blockID = 0; - this.poolType = ''; - this.transactionID = 0; - this.sqlID = 0; - if (paymentID === null) { - this.id = address; - } else { - this.id = address + "." + paymentID; - } - this.fee = 0; - this.baseFee = global.support.decimalToCoin(global.config.payout.feeSlewAmount); - this.setFeeAmount = function () { - if (this.amount <= global.support.decimalToCoin(global.config.payout.walletMin)) { - this.fee = this.baseFee; - } else if (this.amount <= global.support.decimalToCoin(global.config.payout.feeSlewEnd)) { - let feeValue = this.baseFee / (global.support.decimalToCoin(global.config.payout.feeSlewEnd) - global.support.decimalToCoin(global.config.payout.walletMin)); - this.fee = this.baseFee - ((this.amount - global.support.decimalToCoin(global.config.payout.walletMin)) * feeValue); - } - this.fee = Math.floor(this.fee); - }; - - this.makePaymentWithID = function () { - let paymentDetails = { - destinations: [ - { - amount: this.amount - this.fee, - address: this.address - } - ], - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn, - payment_id: this.paymentID - }; - let identifier = this.id; - let amount = this.amount; - let address = this.address; - let paymentID = this.paymentID; - let payee = this; - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (body.fee && body.fee > 10) { - debug("Successful payment sent to: " + identifier); - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - [0, address, paymentID, amount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, 1]).then(function (result) { - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - }; - - this.makePaymentAsIntegrated = function () { - let paymentDetails = { - destinations: [ - { - amount: this.amount - this.fee, - address: this.address - } - ], - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn - }; - let identifier = this.id; - let amount = this.amount; - let address = this.address; - let payee = this; - - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (body.fee && body.fee > 10) { - debug("Successful payment sent to: " + identifier); - global.mysql.query("INSERT INTO transactions (bitcoin, address, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?)", - [0, address, amount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, 1]).then(function (result) { - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - }; - - this.trackPayment = function () { - global.mysql.query("UPDATE balance SET amount = amount - ? WHERE id = ?", [this.amount, this.sqlID]); - global.mysql.query("INSERT INTO payments (unlocked_time, paid_time, pool_type, payment_address, transaction_id, bitcoin, amount, payment_id, transfer_fee)" + - " VALUES (now(), now(), ?, ?, ?, ?, ?, ?, ?)", [this.poolType, this.address, this.transactionID, this.bitcoin, this.amount - this.fee, this.paymentID, this.fee]); - }; -} - -function makePayments() { - global.mysql.query("SELECT * FROM balance WHERE amount >= ?", [global.support.decimalToCoin(global.config.payout.walletMin)]).then(function (rows) { - console.log("Loaded all payees into the system for processing"); - let paymentDestinations = []; - let totalAmount = 0; - let roundCount = 0; - let payeeList = []; - let payeeObjects = {}; - rows.forEach(function (row) { - debug("Starting round for: " + JSON.stringify(row)); - let payee = new Payee(row.amount, row.payment_address, row.payment_id, row.bitcoin); - payeeObjects[row.payment_address] = payee; - global.mysql.query("SELECT payout_threshold FROM users WHERE username = ?", [payee.id]).then(function (userRow) { - roundCount += 1; - let threshold = 0; - if (userRow.length !== 0) { - threshold = userRow[0].payout_threshold; - } - payee.poolType = row.pool_type; - payee.sqlID = row.id; - if (payee.poolType === "fees" && payee.address === global.config.payout.feeAddress && payee.amount >= ((global.support.decimalToCoin(global.config.payout.feesForTXN) + global.support.decimalToCoin(global.config.payout.exchangeMin)))) { - debug("This is the fee address internal check for value"); - payee.amount -= global.support.decimalToCoin(global.config.payout.feesForTXN); - } else if (payee.address === global.config.payout.feeAddress && payee.poolType === "fees") { - debug("Unable to pay fee address."); - payee.amount = 0; - } - let remainder = payee.amount % (global.config.payout.denom * global.config.general.sigDivisor); - if (remainder !== 0) { - payee.amount -= remainder; - } - if (payee.amount > threshold) { - payee.setFeeAmount(); - if (payee.bitcoin === 0 && payee.paymentID === null && payee.amount !== 0 && payee.amount > 0 && payee.address.length !== 106) { - debug("Adding " + payee.id + " to the list of people to pay (OG Address). Payee balance: " + global.support.coinToDecimal(payee.amount)); - paymentDestinations.push({amount: payee.amount - payee.fee, address: payee.address}); - totalAmount += payee.amount; - payeeList.push(payee); - } else if ((payee.amount >= global.support.decimalToCoin(global.config.payout.exchangeMin) || (payee.amount > threshold && threshold !== 0)) && payee.bitcoin === 0) { - debug("Adding " + payee.id + " to the list of people to pay (Payment ID Address). Payee balance: " + global.support.coinToDecimal(payee.amount)); - payee.makePaymentWithID(); - } - } - debug("Went: " + roundCount + " With: " + paymentDestinations.length + " Possible destinations and: " + rows.length + " Rows"); - if (roundCount === rows.length && paymentDestinations.length > 0) { - while (paymentDestinations.length > 0) { - let paymentDetails = { - destinations: paymentDestinations.splice(0, global.config.payout.maxPaymentTxns), - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn - }; - console.log("Paying out: " + paymentDetails.destinations.length + " people"); - paymentQueue.push(paymentDetails, function (body) { //jshint ignore:line - // This is the only section that could potentially contain multiple txns. Lets do this safely eh? - if (body.fee && body.fee > 10) { - debug("Made it to the SQL insert for transactions"); - let totalAmount = 0; - paymentDetails.destinations.forEach(function (payeeItem) { - totalAmount += payeeObjects[payeeItem.address].amount; - totalAmount += payeeObjects[payeeItem.address].fee; - }); - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - [0, null, null, totalAmount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, paymentDetails.destinations.length]).then(function (result) { - paymentDetails.destinations.forEach(function (payeeItem) { - payee = payeeObjects[payeeItem.address]; - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - } - } - }); - }); - }); -} - -function init() { - global.support.rpcWallet("store", [], function () { - }); - setInterval(function () { - global.support.rpcWallet("store", [], function () { - }); - }, 60000); - console.log("Setting the payment timer to: " + global.config.payout.timer + " minutes with a: " + global.config.payout.timerRetry + " minute delay if the wallet is out of money"); - makePayments(); -} - -init(); \ No newline at end of file diff --git a/lib/payment_systems/xmr.js b/lib/payment_systems/xmr.js deleted file mode 100644 index 0a7a1fc..0000000 --- a/lib/payment_systems/xmr.js +++ /dev/null @@ -1,696 +0,0 @@ -"use strict"; -const shapeshift = require('shapeshift.io'); -const async = require("async"); -const debug = require("debug")("payments"); -const request = require('request-json'); -const range = require('range'); - -let hexChars = new RegExp("[0-9a-f]+"); -let bestExchange = global.config.payout.bestExchange; -let xmrAPIClient = request.createClient('https://xmr.to/api/v1/xmr2btc/'); -let extraPaymentRound = false; -let paymentTimer = null; - -let shapeshiftQueue = async.queue(function (task, callback) { - // Amount needs to be shifted in as a non-completed value, as the wallet will only take non-complete values.. - let amount = task.amount - task.fee; - // Address is the destination address IN BTC. - let address = task.address; - // PaymentIDs are the paymentID's to flag as paid by this transaction. - // Should be a massive list of ID's so we can bulk-update them, by merging them with 's. - // Here we go! General process: Scan shapeshift for valid amounts of funds to xfer around. - // Once there's enough funds, then we active txn - // Do a wallet call to xfer. - // Setup a monitor on the transaction - async.waterfall([ - function (intCallback) { - // Verify if the coin is active in ShapeShift first. - shapeshift.coins(function (err, coinData) { - if (err) { - intCallback(err); - } else if (!coinData.hasOwnProperty(global.config.general.coinCode) || coinData[global.config.general.coinCode].status !== "available") { - intCallback("Coin " + global.config.general.coinCode + " Is not available at this time on shapeshift."); - } else { - intCallback(null); - } - }); - }, - function (intCallback) { - // Get the market information from shapeshift, which includes deposit limits, minimum deposits, rates, etc. - shapeshift.marketInfo(global.config.payout.shapeshiftPair, function (err, marketInfo) { - if (err) { - intCallback(err); - } else if (!marketInfo.hasOwnProperty("limit") || marketInfo.limit <= global.support.coinToDecimal(amount)) { - intCallback("Not enough coin in shapeshift to process at this time."); - } else if (!marketInfo.hasOwnProperty("min") || marketInfo.min >= global.support.coinToDecimal(amount)) { - intCallback("Not enough coin to hit the shapeshift minimum deposits."); - } else { - intCallback(null, marketInfo); - } - }); - }, - function (marketInfo, intCallback) { - // Validated there's enough coin. Time to make our dank txn. - // Return: - /* - { - "orderId": "cc49c556-e645-4c15-a943-d50a935274e4", - "sAddress": "46yzCCD3Mza9tRj7aqPSaxVbbePtuAeKzf8Ky2eRtcXGcEgCg1iTBio6N4sPmznfgGEUGDoBz5CLxZ2XPTyZu1yoCAG7zt6", - "deposit": "d8041668718e6e9d9d0fd335ee5ecd923e6fd074c41316d041cc18b779ade10e", - "depositType": "XMR", - "withdrawal": "1DbxcoCBSA9N7uZvkcvWxuLxSau9q9Pwiu", - "withdrawalType": "BTC", - "public": null, - "apiPubKey": "shapeshift", - "returnAddress": "46XWBqE1iwsVxSDP1qDrxhE1XvsZV6eALG5LwnoMdjbT4GPdy2bZTb99kagzxp2MMjUamTYZ4WgvZdFadvMimTjvR6Gv8hL", - "returnAddressType": "XMR" - } - Valid Statuses: - "received" - "complete" - "error" - "no_deposits" - Complete State Information: - { - "status": "complete", - "address": "d8041668718e6e9d9d0fd335ee5ecd923e6fd074c41316d041cc18b779ade10e", - "withdraw": "1DbxcoCBSA9N7uZvkcvWxuLxSau9q9Pwiu", - "incomingCoin": 3, - "incomingType": "XMR", - "outgoingCoin": "0.04186155", - "outgoingType": "BTC", - "transaction": "be9d97f6fc75262151f8f63e035c6ed638b9eb2a4e93fef43ea63124b045dbfb" - } - */ - shapeshift.shift(address, global.config.payout.shapeshiftPair, {returnAddress: global.config.pool.address}, function (err, returnData) { - if (err) { - intCallback(err); - } else { - global.mysql.query("INSERT INTO shapeshiftTxn (id, address, paymentID, depositType, withdrawl, withdrawlType, returnAddress, returnAddressType, txnStatus) VALUES (?,?,?,?,?,?,?,?,?)", - [returnData.orderId, returnData.sAddress, returnData.deposit, returnData.depositType, returnData.withdrawl, returnData.withdrawlType, returnData.returnAddress, returnData.returnAddressType, 'no_deposits']).then(function () { - intCallback(null, marketInfo, returnData); - }).catch(function (error) { - intCallback(error); - }); - } - }); - }, - function (marketInfo, shapeshiftTxnData, intCallback) { - // Make the payment to ShapeShift - let paymentDetails = { - destinations: [ - { - amount: amount, - address: shapeshiftTxnData.sAddress - } - ], - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn, - payment_id: shapeshiftTxnData.deposit - }; - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (body.fee && body.fee > 10) { - intCallback(null, marketInfo, shapeshiftTxnData, body); - } else { - intCallback("Unknown error from the wallet."); - } - }); - }, - function (marketInfo, shapeshiftTxnData, body, intCallback) { - // body.tx_hash = XMR transaction hash. - // Need to add transaction. - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees, exchange_rate, exchange_name, exchange_txn_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - [1, address, null, task.amount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, global.support.decimalToCoin(marketInfo.minerFee), 1, global.support.decimalToCoin(marketInfo.rate), 'shapeshift', shapeshiftTxnData.orderId]).then(function (result) { - intCallback(null, result.insertId); - }).catch(function (error) { - intCallback(error); - }); - } - ], function (err, result) { - if (err) { - console.error("Error processing shapeshift txn: " + JSON.stringify(err)); - callback(true); - } else { - // Need to fill out this data pronto! - console.log("Processed ShapeShift transaction for: " + address + " Paid out: " + result + " payments in the db"); - callback(null, result); - } - }); -}, 2); - -let xmrToQueue = async.queue(function (task, callback) { - // http://xmrto-api.readthedocs.io/en/latest/introduction.html - // Documentation looks good! - // Amount needs to be shifted in as a non-completed value, as the wallet will only take non-complete values.. - let amount = task.amount - task.fee; - // Address is the destination address IN BTC. - let address = task.address; - // PaymentIDs are the paymentID's to flag as paid by this transaction. - // Should be a massive list of ID's so we can bulk-update them, by merging them with 's. - // Here we go! General process: Scan shapeshift for valid amounts of funds to xfer around. - // Once there's enough funds, then we active txn - // Do a wallet call to xfer. - // Setup a monitor on the transaction - async.waterfall([ - function (intCallback) { - // Verify if XMR.to is ready to get to work. - xmrAPIClient.get('order_parameter_query/', function (err, res, body) { - if (err) { - return intCallback(err); - } else if (body.error_msg) { - return intCallback(body.error_msg); - } else { - let amtOfBTC = ((amount / global.config.general.sigDivisor) * body.price).toPrecision(5); - console.log("Attempting to pay: " + address + " Amount: " + amtOfBTC + " BTC or " + amount / global.config.general.sigDivisor + " XMR"); - console.log("Response from XMR.to: " + JSON.stringify(body)); - if (body.lower_limit >= amtOfBTC) { - return intCallback("Not enough XMR to hit the minimum deposit"); - } else if (body.upper_limit <= amtOfBTC) { - return intCallback("Too much XMR to pay out to xmr.to"); - } else { - return intCallback(null, amtOfBTC); - } - } - }); - }, - function (btcValue, intCallback) { - // Validated there's enough coin. Time to make our dank txn. - // Return: - /* - { - "state": "TO_BE_CREATED", - "btc_amount": , - "btc_dest_address": "", - "uuid": "" - } - Valid Statuses: - "TO_BE_CREATED" - "UNPAID" - "UNDERPAID" - "PAID_UNCONFIRMED" - "PAID" - "BTC_SENT" - "TIMED_OUT" - "NOT_FOUND" - // Create, then immediately update with the new information w/ a status call. - */ - console.log("Amount of BTC to pay: " + btcValue); - xmrAPIClient.post('order_create/', { - btc_amount: btcValue, - btc_dest_address: address - }, function (err, res, body) { - if (err) { - return intCallback(err); - } else if (body.error_msg) { - return intCallback(body.error_msg); - } else { - return intCallback(null, body.uuid); - } - }); - }, - function (txnID, intCallback) { - // This function only exists because xmr.to is a pretty little fucking princess. - async.doUntil(function (xmrCallback) { - xmrAPIClient.post('order_status_query/', {uuid: txnID}, function (err, res, body) { - if (err) { - return intCallback(err); - } else if (body.error_msg) { - return intCallback(body.error_msg); - } else { - xmrCallback(null, body.state); - } - }); - }, - function (xmrCallback) { - return xmrCallback !== "TO_BE_CREATED"; - }, - function () { - intCallback(null, txnID); - }); - }, - function (txnID, intCallback) { - xmrAPIClient.post('order_status_query/', {uuid: txnID}, function (err, res, body) { - if (err) { - return intCallback(err); - } else if (body.error_msg) { - return intCallback(body.error_msg); - } else { - console.log(JSON.stringify(body)); - global.mysql.query("INSERT INTO xmrtoTxn (id, address, paymentID, depositType, withdrawl, withdrawlType, returnAddress, returnAddressType, txnStatus, amountDeposited, amountSent) VALUES (?,?,?,?,?,?,?,?,?,?,?)", - [txnID, body.xmr_receiving_address, body.xmr_required_payment_id_long, 'XMR', body.btc_dest_address, 'BTC', global.config.pool.address, 'XMR', body.state_str, global.support.decimalToCoin(body.xmr_amount_total), global.support.decimalToCoin(body.btc_amount)]).then(function () { - return intCallback(null, body, global.support.decimalToCoin(body.xmr_amount_total)); - }).catch(function (error) { - return intCallback(error); - }); - } - }); - }, - function (orderStatus, xmrDeposit, intCallback) { - // Make the payment to ShapeShift - let paymentDetails = { - destinations: [ - { - amount: xmrDeposit, - address: orderStatus.xmr_receiving_address - } - ], - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn, - payment_id: orderStatus.xmr_required_payment_id_long - }; - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (body.fee && body.fee > 10) { - return intCallback(null, orderStatus, body); - } else { - return intCallback("Unknown error from the wallet."); - } - }); - }, - function (orderStatus, body, intCallback) { - // body.tx_hash = XMR transaction hash. - // Need to add transaction. - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees, exchange_rate, exchange_name, exchange_txn_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - [1, address, null, global.support.decimalToCoin(orderStatus.xmr_amount_total), body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, 1, global.support.decimalToCoin(orderStatus.xmr_price_btc), 'xmrto', orderStatus.uuid]).then(function (result) { - return intCallback(null, result.insertId); - }).catch(function (error) { - return intCallback(error); - }); - } - ], function (err, result) { - if (err) { - console.error("Error processing XMRTo txn: " + JSON.stringify(err)); - return callback("Error!"); - } else { - // Need to fill out this data pronto! - console.log("Processed XMRTo transaction for: " + address + " Paid out: " + result + " payments in the db"); - return callback(null, result); - } - }); -}, 2); - -let paymentQueue = async.queue(function (paymentDetails, callback) { - /* - support JSON URI: http://10.0.0.2:28082/json_rpc Args: {"id":"0","jsonrpc":"2.0","method":"transfer","params":{"destinations":[{"amount":68130252045355,"address":"A2MSrn49ziBPJBh8ZNEhhbfyLMou6mao4C1F5TLGUatmUnCxZArDYkcbAnVkVEopWVeak2rKDrmc8JpoS7n5dvfN9YDPBTG"}],"mixin":4,"payment_id":"7e52c5266de9fede7fb3abc0cd88f937b38b51426f7b34ff99729d28ce4e1142"}} +1ms - payments Payment made: {"id":"0","jsonrpc":"2.0","result":{"fee":40199391255,"tx_hash":"c418708643f72635edf522490bfb2cae9d42a6dc1df30dcde844862dfd88f5b3","tx_key":""}} +2s - */ - if (paymentTimer !== null){ - clearInterval(paymentTimer); - paymentTimer = null; - } - debug("Making payment based on: " + JSON.stringify(paymentDetails)); - let transferFunc = 'transfer'; - global.support.rpcWallet(transferFunc, paymentDetails, function (body) { - debug("Payment made: " + JSON.stringify(body)); - if (body.hasOwnProperty('error')) { - if (body.error.message === "not enough money" || body.error.message === "not enough unlocked money"){ - console.error("Issue making payments, not enough money, will try later"); - if(!extraPaymentRound){ - setTimeout(function(){ - makePayments(); - }, global.config.payout.timerRetry * 60 * 1000); - } - extraPaymentRound = true; - return callback(false); - } else { - console.error("Issue making payments" + JSON.stringify(body.error)); - console.error("Will not make more payments until the payment daemon is restarted!"); - //toAddress, subject, body - global.support.sendEmail(global.config.general.adminEmail, "Payment daemon unable to make payment", - "Hello,\r\nThe payment daemon has hit an issue making a payment: " + JSON.stringify(body.error) + - ". Please investigate and restart the payment daemon as appropriate"); - return; - } - } - if (paymentDetails.hasOwnProperty('payment_id')) { - console.log("Payment made to " + paymentDetails.destinations[0].address + " with PaymentID: " + paymentDetails.payment_id + " For: " + global.support.coinToDecimal(paymentDetails.destinations[0].amount) + " XMR with a " + global.support.coinToDecimal(body.result.fee) + " XMR Mining Fee"); - return callback(body.result); - } else { - if (transferFunc === 'transfer') { - console.log("Payment made out to multiple people, total fee: " + global.support.coinToDecimal(body.result.fee) + " XMR"); - } - let intCount = 0; - paymentDetails.destinations.forEach(function (details) { - console.log("Payment made to: " + details.address + " For: " + global.support.coinToDecimal(details.amount) + " XMR"); - intCount += 1; - if (intCount === paymentDetails.destinations.length) { - return callback(body.result); - } - }); - } - }); -}, 1); - -paymentQueue.drain = function(){ - extraPaymentRound = false; - if (global.config.payout.timer > 35791){ - console.error("Payout timer is too high. Please use a value under 35791 to avoid overflows."); - } else { - paymentTimer = setInterval(makePayments, global.config.payout.timer * 60 * 1000); - } - global.database.setCache('lastPaymentCycle', Math.floor(Date.now()/1000)); -}; - -function updateShapeshiftCompletion() { - global.mysql.query("SELECT * FROM shapeshiftTxn WHERE txnStatus NOT IN ('complete', 'error')").then(function (rows) { - rows.forEach(function (row) { - shapeshift.status(row.paymentID, function (err, status, returnData) { - if (err) { - return; - } - global.mysql.query("UPDATE shapeshiftTxn SET txnStatus = ? WHERE id = ?", [status, row.id]).then(function () { - if (status === 'complete') { - global.mysql.query("UPDATE shapeshiftTxn SET amountDeposited = ?, amountSent = ?, transactionHash = ? WHERE id = ?", - [global.support.decimalToCoin(returnData.incomingCoin), global.support.bitcoinDecimalToCoin(returnData.outgoingCoin), returnData.transaction, row.id]).then(function () { - global.mysql.query("UPDATE transactions SET confirmed = 1, confirmed_time = now(), btc_amt = ? WHERE exchange_txn_id = ?", [global.support.bitcoinDecimalToCoin(returnData.outgoingCoin), row.id]); - }); - } else if (status === 'error') { - // Failed txn. Need to rollback and delete all related data. Here we go! - global.mysql.query("DELETE FROM shapeshiftTxn WHERE id = ?", [row.id]); - global.mysql.query("SELECT id, xmr_amt, address FROM transactions WHERE exchange_txn_id = ?", [row.id]).then(function (rows) { - global.mysql.query("DELETE FROM transactions WHERE id = ?", [rows[0].id]); - global.mysql.query("DELETE payments WHERE transaction_id = ?", [rows[0].id]); - global.mysql.query("UPDATE balance SET amount = amount+? WHERE payment_address = ? limit 1", [rows[0].xmr_amt, rows[0].address]); - }); - console.error("Failed transaction from ShapeShift " + JSON.stringify(returnData)); - } - }); - }); - }); - }); -} - -function updateXMRToCompletion() { - global.mysql.query("SELECT * FROM xmrtoTxn WHERE txnStatus NOT IN ('PAID', 'TIMED_OUT', 'NOT_FOUND', 'BTC_SENT')").then(function (rows) { - rows.forEach(function (row) { - xmrAPIClient.post('order_status_query/', {uuid: row.id}, function (err, res, body) { - if (err) { - console.log("Error in getting order status: " + JSON.stringify(err)); - return; - } - if (body.error_msg) { - console.log("Error in getting order status: " + body.error_msg); - return; - } - global.mysql.query("UPDATE xmrtoTxn SET txnStatus = ? WHERE id = ?", [body.state, row.id]).then(function () { - if (body.status === 'BTC_SENT') { - global.mysql.query("UPDATE xmrtoTxn SET transactionHash = ? WHERE id = ?", [body.btc_transaction_id, row.id]).then(function () { - global.mysql.query("UPDATE transactions SET confirmed = 1, confirmed_time = now(), btc_amt = ? WHERE exchange_txn_id = ?", [global.support.bitcoinDecimalToCoin(body.btc_amount), row.id]); - }); - } else if (body.status === 'TIMED_OUT' || body.status === 'NOT_FOUND') { - global.mysql.query("DELETE FROM xmrtoTxn WHERE id = ?", [row.id]); - global.mysql.query("SELECT id, xmr_amt, address FROM transactions WHERE exchange_txn_id = ?", [row.id]).then(function (rows) { - global.mysql.query("DELETE FROM transactions WHERE id = ?", [rows[0].id]); - global.mysql.query("DELETE payments WHERE transaction_id = ?", [rows[0].id]); - global.mysql.query("UPDATE balance SET amount = amount+? WHERE payment_address = ? limit 1", [rows[0].xmr_amt, rows[0].address]); - }); - console.error("Failed transaction from XMRto " + JSON.stringify(body)); - } - }); - }); - }); - }); -} - -function determineBestExchange() { - async.waterfall([ - function (callback) { - // Verify if the coin is active in ShapeShift first. - shapeshift.coins(function (err, coinData) { - if (err) { - return callback(err); - } else if (!coinData.hasOwnProperty(global.config.general.coinCode) || coinData[global.config.general.coinCode].status !== "available") { - return callback("Coin " + global.config.general.coinCode + " Is not available at this time on shapeshift."); - } else { - return callback(null); - } - }); - }, - function (callback) { - // Get the market information from shapeshift, which includes deposit limits, minimum deposits, rates, etc. - shapeshift.marketInfo(global.config.payout.shapeshiftPair, function (err, marketInfo) { - if (err) { - return callback(err); - } else if (!marketInfo.hasOwnProperty("rate")) { - return callback("Shapeshift did not return the rate."); - } else { - return callback(null, global.support.bitcoinDecimalToCoin(marketInfo.rate)); - } - }); - }, - function (ssValue, callback) { - xmrAPIClient.get('order_parameter_query/', function (err, res, body) { - console.log("XMR.to pricing body: " + JSON.stringify(body)); - if (err) { - return callback(err); - } else if (body.error_msg) { - return callback(body.error_msg); - } else { - return callback(null, ssValue, global.support.bitcoinDecimalToCoin(body.price)); - } - }); - } - ], function (err, ssValue, xmrToValue) { - if (err) { - return console.error("Error processing exchange value: " + JSON.stringify(err)); - } - debug("ShapeShift Value: " + global.support.bitcoinCoinToDecimal(ssValue) + " XMR.to Value: " + global.support.bitcoinCoinToDecimal(xmrToValue)); - if (ssValue >= xmrToValue) { - console.log("ShapeShift is the better BTC exchange, current rate: " + global.support.bitcoinCoinToDecimal(ssValue)); - bestExchange = 'shapeshift'; - global.mysql.query("UPDATE config SET item_value = 'shapeshift' where item='bestExchange'"); - global.mysql.query("UPDATE config SET item_value = ? where item='exchangeRate'", [ssValue]); - } else { - console.log("XMR.to is the better BTC exchange, current rate: " + global.support.bitcoinCoinToDecimal(xmrToValue)); - bestExchange = 'xmrto'; - global.mysql.query("UPDATE config SET item_value = 'xmrto' where item='bestExchange'"); - global.mysql.query("UPDATE config SET item_value = ? where item='exchangeRate'", [xmrToValue]); - } - }); -} - -function Payee(amount, address, paymentID, bitcoin) { - this.amount = amount; - this.address = address; - this.paymentID = paymentID; - this.bitcoin = bitcoin; - this.blockID = 0; - this.poolType = ''; - this.transactionID = 0; - this.sqlID = 0; - if (paymentID === null) { - this.id = address; - } else { - this.id = address + "." + paymentID; - } - this.fee = 0; - this.baseFee = global.support.decimalToCoin(global.config.payout.feeSlewAmount); - this.setFeeAmount = function () { - if (this.amount <= global.support.decimalToCoin(global.config.payout.walletMin)) { - this.fee = this.baseFee; - } else if (this.amount <= global.support.decimalToCoin(global.config.payout.feeSlewEnd)) { - let feeValue = this.baseFee / (global.support.decimalToCoin(global.config.payout.feeSlewEnd) - global.support.decimalToCoin(global.config.payout.walletMin)); - this.fee = this.baseFee - ((this.amount - global.support.decimalToCoin(global.config.payout.walletMin)) * feeValue); - } - this.fee = Math.floor(this.fee); - }; - - this.makePaymentWithID = function () { - let paymentDetails = { - destinations: [ - { - amount: this.amount - this.fee, - address: this.address - } - ], - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn, - payment_id: this.paymentID - }; - let identifier = this.id; - let amount = this.amount; - let address = this.address; - let paymentID = this.paymentID; - let payee = this; - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (body.fee && body.fee > 10) { - debug("Successful payment sent to: " + identifier); - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - [0, address, paymentID, amount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, 1]).then(function (result) { - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - }; - - this.makePaymentAsIntegrated = function () { - let paymentDetails = { - destinations: [ - { - amount: this.amount - this.fee, - address: this.address - } - ], - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn - }; - let identifier = this.id; - let amount = this.amount; - let address = this.address; - let payee = this; - - debug("Payment Details: " + JSON.stringify(paymentDetails)); - paymentQueue.push(paymentDetails, function (body) { - if (body.fee && body.fee > 10) { - debug("Successful payment sent to: " + identifier); - global.mysql.query("INSERT INTO transactions (bitcoin, address, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?)", - [0, address, amount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, 1]).then(function (result) { - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - }; - - this.makeBitcoinPayment = function () { - let functionalData = {address: this.address, amount: this.amount, fee: this.fee}; - let payee = this; - if (bestExchange === 'xmrto') { - xmrToQueue.push(functionalData, function (err, transactionID) { - if (err) { - return console.error("Error processing payment for " + functionalData.address); - } - payee.transactionID = transactionID; - payee.trackPayment(); - }); - } else { - shapeshiftQueue.push(functionalData, function (err, transactionID) { - if (err) { - return console.error("Error processing payment for " + functionalData.address); - } - payee.transactionID = transactionID; - payee.trackPayment(); - }); - } - }; - - this.trackPayment = function () { - global.mysql.query("UPDATE balance SET amount = amount - ? WHERE id = ?", [this.amount, this.sqlID]); - global.mysql.query("INSERT INTO payments (unlocked_time, paid_time, pool_type, payment_address, transaction_id, bitcoin, amount, payment_id, transfer_fee)" + - " VALUES (now(), now(), ?, ?, ?, ?, ?, ?, ?)", [this.poolType, this.address, this.transactionID, this.bitcoin, this.amount - this.fee, this.paymentID, this.fee]); - }; -} - -function makePayments() { - global.mysql.query("SELECT * FROM balance WHERE amount >= ?", [global.support.decimalToCoin(global.config.payout.walletMin)]).then(function (rows) { - console.log("Loaded all payees into the system for processing"); - let paymentDestinations = []; - let totalAmount = 0; - let roundCount = 0; - let payeeList = []; - let payeeObjects = {}; - rows.forEach(function (row) { - debug("Starting round for: " + JSON.stringify(row)); - let payee = new Payee(row.amount, row.payment_address, row.payment_id, row.bitcoin); - payeeObjects[row.payment_address] = payee; - global.mysql.query("SELECT payout_threshold FROM users WHERE username = ?", [payee.id]).then(function (userRow) { - roundCount += 1; - let threshold = 0; - if (userRow.length !== 0) { - threshold = userRow[0].payout_threshold; - } - payee.poolType = row.pool_type; - payee.sqlID = row.id; - if (payee.poolType === "fees" && payee.address === global.config.payout.feeAddress && payee.amount >= ((global.support.decimalToCoin(global.config.payout.feesForTXN) + global.support.decimalToCoin(global.config.payout.exchangeMin)))) { - debug("This is the fee address internal check for value"); - payee.amount -= global.support.decimalToCoin(global.config.payout.feesForTXN); - } else if (payee.address === global.config.payout.feeAddress && payee.poolType === "fees") { - debug("Unable to pay fee address."); - payee.amount = 0; - } - let remainder = payee.amount % (global.config.payout.denom * global.config.general.sigDivisor); - if (remainder !== 0) { - payee.amount -= remainder; - } - if (payee.amount > threshold) { - payee.setFeeAmount(); - if (payee.bitcoin === 0 && payee.paymentID === null && payee.amount !== 0 && payee.amount > 0 && payee.address.length !== 106) { - debug("Adding " + payee.id + " to the list of people to pay (OG Address). Payee balance: " + global.support.coinToDecimal(payee.amount)); - paymentDestinations.push({amount: payee.amount - payee.fee, address: payee.address}); - totalAmount += payee.amount; - payeeList.push(payee); - } else if (payee.bitcoin === 0 && payee.paymentID === null && payee.amount !== 0 && payee.amount > 0 && payee.address.length === 106 && (payee.amount >= global.support.decimalToCoin(global.config.payout.exchangeMin) || (payee.amount > threshold && threshold !== 0))) { - // Special code to handle integrated payment addresses. What a pain in the rear. - // These are exchange addresses though, so they need to hit the exchange payout amount. - debug("Adding " + payee.id + " to the list of people to pay (Integrated Address). Payee balance: " + global.support.coinToDecimal(payee.amount)); - payee.makePaymentAsIntegrated(); - } else if ((payee.amount >= global.support.decimalToCoin(global.config.payout.exchangeMin) || (payee.amount > threshold && threshold !== 0)) && payee.bitcoin === 0) { - debug("Adding " + payee.id + " to the list of people to pay (Payment ID Address). Payee balance: " + global.support.coinToDecimal(payee.amount)); - payee.makePaymentWithID(); - } else if ((payee.amount >= global.support.decimalToCoin(global.config.payout.exchangeMin) || (payee.amount > threshold && threshold !== 0)) && payee.bitcoin === 1) { - debug("Adding " + payee.id + " to the list of people to pay (Bitcoin Payout). Payee balance: " + global.support.coinToDecimal(payee.amount)); - payee.makeBitcoinPayment(); - } - } - debug("Went: " + roundCount + " With: " + paymentDestinations.length + " Possible destinations and: " + rows.length + " Rows"); - if (roundCount === rows.length && paymentDestinations.length > 0) { - while (paymentDestinations.length > 0) { - let paymentDetails = { - destinations: paymentDestinations.splice(0, global.config.payout.maxPaymentTxns), - priority: global.config.payout.priority, - mixin: global.config.payout.mixIn - }; - console.log("Paying out: " + paymentDetails.destinations.length + " people"); - paymentQueue.push(paymentDetails, function (body) { //jshint ignore:line - // This is the only section that could potentially contain multiple txns. Lets do this safely eh? - if (body.fee && body.fee > 10) { - debug("Made it to the SQL insert for transactions"); - let totalAmount = 0; - paymentDetails.destinations.forEach(function (payeeItem) { - totalAmount += payeeObjects[payeeItem.address].amount; - totalAmount += payeeObjects[payeeItem.address].fee; - }); - global.mysql.query("INSERT INTO transactions (bitcoin, address, payment_id, xmr_amt, transaction_hash, mixin, fees, payees) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - [0, null, null, totalAmount, body.tx_hash.match(hexChars)[0], global.config.payout.mixIn, body.fee, paymentDetails.destinations.length]).then(function (result) { - paymentDetails.destinations.forEach(function (payeeItem) { - payee = payeeObjects[payeeItem.address]; - payee.transactionID = result.insertId; - payee.trackPayment(); - }); - }); - } else { - console.error("Unknown error from the wallet."); - } - }); - } - } - }); - }); - }); -} - -function init() { - global.support.rpcWallet("store", [], function () { - }); - if (global.config.allowBitcoin) { - determineBestExchange(); - setInterval(updateXMRToCompletion, 90000); - setInterval(updateShapeshiftCompletion, 90000); - setInterval(determineBestExchange, 60000); - } - setInterval(function () { - global.support.rpcWallet("store", [], function () { - }); - }, 60000); - console.log("Setting the payment timer to: " + global.config.payout.timer + " minutes with a: " + global.config.payout.timerRetry + " minute delay if the wallet is out of money"); - makePayments(); -} - -init(); \ No newline at end of file