aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2021-08-09 20:55:17 -0700
committerAdam Soltys <[email protected]>2021-08-09 20:55:17 -0700
commit56559c7b9749fe62fe2fe0ba90725391d83b8bf7 (patch)
tree48d6a0630d05d6787b4410708a5efceff472636b
parent803ecab2b5c3a00d107372ea6757cd6ce0f8224d (diff)
parent8d6f65079868ae6134f593752e3380180591623d (diff)
downloadcoinos-server-56559c7b9749fe62fe2fe0ba90725391d83b8bf7.tar.gz
coinos-server-56559c7b9749fe62fe2fe0ba90725391d83b8bf7.zip
Merge branch 'v1.0.0'
-rw-r--r--.gitignore3
-rw-r--r--Dockerfile7
-rw-r--r--doc/fund-server-bitcoin-cli.md10
-rw-r--r--lib/mail.js32
-rw-r--r--lib/persist.js2
-rw-r--r--lib/send.js2
-rw-r--r--lib/sockets.js2
-rw-r--r--package.json2
-rw-r--r--routes/admin.js224
-rw-r--r--routes/bitcoin/receive.js48
-rw-r--r--routes/bitcoin/send.js55
-rw-r--r--routes/invoices.js4
-rw-r--r--routes/lightning/receive.js53
-rw-r--r--routes/liquid/fee.js9
-rw-r--r--routes/liquid/receive.js71
-rw-r--r--routes/liquid/send.js34
-rw-r--r--routes/lnurl.js10
-rw-r--r--routes/payments.js1
-rw-r--r--routes/referrals.js7
-rw-r--r--routes/send.js2
-rw-r--r--routes/users.js25
-rw-r--r--scripts/apiParse.js14
-rwxr-xr-xwatcher.sh20
23 files changed, 280 insertions, 357 deletions
diff --git a/.gitignore b/.gitignore
index 58f3c4fe..ab73f32c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,6 @@ lnurl-server.sqlite3
watcher.log
config
mysql
+build.json
+build.sh
+watcher.sh
diff --git a/Dockerfile b/Dockerfile
index 582778e2..e5f9f986 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,16 +1,13 @@
-FROM node:slim
+FROM node:alpine
ARG NODE_ENV=production
ENV NODE_ENV $NODE_ENV
-RUN apt-get update
-RUN apt-get install git make gcc g++ python libzmq3-dev -y
+RUN apk add git
COPY . /app
WORKDIR /app
RUN yarn install
-ENV SHELL /bin/bash
-
CMD ["yarn", "start"]
diff --git a/doc/fund-server-bitcoin-cli.md b/doc/fund-server-bitcoin-cli.md
index 3c5b6ef5..5b096f0f 100644
--- a/doc/fund-server-bitcoin-cli.md
+++ b/doc/fund-server-bitcoin-cli.md
@@ -14,11 +14,19 @@ docker exec -it bitcoin bash
bitcoin-cli -regtest -datadir=/config -rpcwallet=coinosdev getnewaddress
# mine a block to the new address
-bitcoin-cli -regtest -datadir=/config generatetoaddress 101 theaddressgneratedabove
+bitcoin-cli -regtest -datadir=/config generatetoaddress 101 theaddressgeneratedabove
# verify you got the reward:
bitcoin-cli -regtest -datadir=/config -conf=./bitcoin.conf -rpcwallet=coinosdev getbalance
> 50.00000000
+
+# send 10 bitcoin to your account on the server
+# get the address to send to from ./receive, select 'Bitcoin'
+bitcoin-cli -regtest -datadir=/config -rpcwallet=coinosdev sendtoaddress [account-address] 10
+
+# confirm the transaction
+# (do the mining command again)
+bitcoin-cli -regtest -datadir=/config generatetoaddress 101 theaddressgeneratedabove
```
![](./img/50-bitcoin-server-balance.gif)
diff --git a/lib/mail.js b/lib/mail.js
index 705880d2..ca2c2b81 100644
--- a/lib/mail.js
+++ b/lib/mail.js
@@ -10,6 +10,38 @@ function openInbox(cb) {
imap.openBox("INBOX", true, cb);
}
+app.post(
+ "/contact-sil",
+ ah((req, res) => {
+ const mailgun = require("mailgun-js")(config.mailgun);
+ let data = {
+ subject: "Contact form",
+ text: JSON.stringify(req.body),
+ };
+
+ mailgun.messages().send(data);
+ res.send(req.body);
+ })
+);
+
+app.post(
+ "/contact",
+ ah((req, res) => {
+ const mailgun = require("mailgun-js")(config.mailgun);
+ let data = {
+ subject: "Contact form",
+ text: JSON.stringify(req.body),
+ };
+
+ mailgun.messages().send(data);
+ res.send(req.body);
+ })
+);
+
imap.once("ready", function() {
openInbox(function(err, box) {
if (err) throw err;
diff --git a/lib/persist.js b/lib/persist.js
index 54e7e209..a2febf68 100644
--- a/lib/persist.js
+++ b/lib/persist.js
@@ -7,8 +7,6 @@ module.exports = (path, initial = {}) => {
} catch(e) {}
}
- // console.log("initial", path, initial);
-
return new Proxy(initial, {
set(obj, prop, value) {
fs.writeFileSync(
diff --git a/lib/send.js b/lib/send.js
index c54985d3..92b2eda3 100644
--- a/lib/send.js
+++ b/lib/send.js
@@ -6,7 +6,7 @@ send = async (amount, memo, hash, user) => {
let routingInfo = payreq.tags.find(t => t.tagName === "routing_info");
if (
routingInfo &&
- routingInfo.data.find(d => d.fee_proportional_millionths > 100)
+ routingInfo.data.find(d => d.fee_proportional_millionths > 1000)
)
throw new Error("Fee rate too high");
diff --git a/lib/sockets.js b/lib/sockets.js
index 931a9d23..bd59ee38 100644
--- a/lib/sockets.js
+++ b/lib/sockets.js
@@ -96,7 +96,7 @@ wss.on("connection", function(ws, req) {
lastSeen[token] = new Date();
try {
- if (!token || token === "null") return ws.close();
+ if (!token || token === "null" || !jwt.decode(token)) return ws.close();
const username = jwt.decode(token).username;
if (!username) throw new Error("Invalid JWT token");
diff --git a/package.json b/package.json
index 22833f29..f4db1af1 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,7 @@
"passport-local": "1.0.0",
"pino": "^5.17.0",
"pino-pretty": "^4.8.0",
- "pm2": "^4.5.6",
+ "pm2": "^5.1.0",
"query-string": "^6.13.1",
"sequelize": "^5.21.3",
"sqlite3": "^5.0.2",
diff --git a/routes/admin.js b/routes/admin.js
index c401c724..c7b7578d 100644
--- a/routes/admin.js
+++ b/routes/admin.js
@@ -35,20 +35,12 @@ router.get(
.select('username', 'email', 'phone', 'verified', knex.raw('LEFT(createdAt,10) as created_at'))
.from('users')
- if (starts_with) {
- search = search + '%'
- } else if (contains) {
- search = '%' + search + '%'
- }
+ var timeCondition = parseInput.addTimeSearch(req.query, 'users.createdAt')
+ var userCondition = parseInput.addUserSearch(req.query)
- if (search) {
- users = users
- .where(function() {
- this.where('username', 'like', search)
- this.orWhere('email', 'like', search)
- })
- }
- debug('search ? ' + search)
+ if (timeCondition) users = users.whereRaw(timeCondition)
+ if (userCondition) users = users.whereRaw(userCondition)
+
// Alternative Sequelize query syntax
// await db.User.findAll({
// attributes: ['username', 'email', 'phone', 'verified', 'createdAt']
@@ -101,6 +93,11 @@ router.get(
// ]
// })
+ var timeCondition = parseInput.addTimeSearch(req.query, 'referrals.updatedAt')
+ var userCondition = parseInput.addUserSearch(req.query, 'sponsor')
+
+ if (timeCondition) referrals = referrals.whereRaw(timeCondition)
+ if (userCondition) referrals = referrals.whereRaw(userCondition)
debug('Referrals: ' + JSON.stringify(referrals))
return res.send({referrals: referrals})
@@ -141,20 +138,12 @@ router.get(
.leftJoin('users', 'users.email', 'waiting_list.email')
.where('waiting_list.id', '>', 0)
- if (starts_with) {
- search = search + '%'
- } else if (contains) {
- search = '%' + search + '%'
- }
+ var timeCondition = parseInput.addTimeSearch(req.query, 'waiting_list.updated_at')
+ var userCondition = parseInput.addUserSearch(req.query)
+
+ if (timeCondition) queue = queue.whereRaw(timeCondition)
+ if (userCondition) queue = queue.whereRaw(userCondition)
- if (search) {
- queue = queue
- .where(function() {
- this.where('waiting_list.email', 'like', search)
- this.orWhere('users.username', 'like', search)
- })
- }
- debug('search ? ' + search)
const found = await queue
debug('Waiting list: ' + JSON.stringify(found))
@@ -195,19 +184,12 @@ router.get(
.where('balance', '>', 0)
}
- if (starts_with) {
- search = search + '%'
- } else if (contains) {
- search = '%' + search + '%'
- }
+ var timeCondition = parseInput.addTimeSearch(req.query, 'accounts.updatedAt')
+ var userCondition = parseInput.addUserSearch(req.query)
+
+ if (timeCondition) accounts = accounts.whereRaw(timeCondition)
+ if (userCondition) accounts = accounts.whereRaw(userCondition)
- if (search) {
- accounts = accounts
- .where(function() {
- this.where('users.email', 'like', search)
- this.orWhere('users.username', 'like', search)
- })
- }
debug('search ? ' + search)
const found = await accounts
@@ -270,21 +252,11 @@ router.get(
debug(types[i] + ' since ' + since)
}
}
+
if (since) transactions = transactions.havingRaw('invoices + payments + deposits + orders > ?', [0])
- if (starts_with) {
- search = search + '%'
- } else if (contains) {
- search = '%' + search + '%'
- }
-
- if (search) {
- transactions = transactions
- .where(function() {
- this.where('users.email', 'like', search)
- this.orWhere('users.username', 'like', search)
- })
- }
+ var userCondition = parseInput.addUserSearch(req.query)
+ if (userCondition) transactions = transactions.whereRaw(userCondition)
transactions = transactions
.groupBy('users.id')
@@ -338,27 +310,16 @@ router.get(
.leftJoin('users as u1', 'a1.user_id', 'u1.id')
.leftJoin('users as u2', 'a2.user_id', 'u2.id')
- if (since) {
- orders = orders
- .where('orders.updatedAt', '>=', since)
- }
+ var timeCondition = parseInput.addTimeSearch(req.query, 'orders.updatedAt')
+ if (timeCondition) orders = orders.whereRaw(timeCondition)
- if (starts_with) {
- search = search + '%'
- } else if (contains) {
- search = '%' + search + '%'
- }
-
- if (search) {
- orders = orders
- .where( function () {
- this.where('u1.email', 'like', search)
- this.orWhere('u1.username', 'like', search)
- this.orWhere('u2.username', 'like', search)
- this.orWhere('u2.email', 'like', search)
- })
- }
- debug('orders since ' + since)
+ var userCondition1 = parseInput.addUserSearch(req.query, 'u1')
+ var userCondition2 = parseInput.addUserSearch(req.query, 'u2')
+
+ if (userCondition1) orders = orders.where( function () {
+ this.whereRaw(userCondition1)
+ this.orWhere(knex.raw(userCondition2))
+ })
var found = await orders
debug('orders: ' + JSON.stringify(found))
@@ -403,26 +364,11 @@ router.get(
.leftJoin('accounts', 'invoices.account_id', 'accounts.id')
.leftJoin('users', 'accounts.user_id', 'users.id')
- if (since) {
- invoices = invoices
- .where('invoices.updatedAt', '>=', since)
- }
-
- debug('invoices since ' + since)
-
- if (starts_with) {
- search = search + '%'
- } else if (contains) {
- search = '%' + search + '%'
- }
+ var timeCondition = parseInput.addTimeSearch(req.query, 'invoices.updatedAt')
+ var userCondition = parseInput.addUserSearch(req.query)
- if (search) {
- invoices = invoices
- .where(function() {
- this.where('users.email', 'like', search)
- this.orWhere('users.username', 'like', search)
- })
- }
+ if (timeCondition) invoices = invoices.whereRaw(timeCondition)
+ if (userCondition) invoices = invoices.whereRaw(userCondition)
var found = await invoices
debug('invoices: ' + JSON.stringify(found))
@@ -468,26 +414,11 @@ router.get(
debug('dtype: ' + deposits.constructor + ' : ' + typeof(deposits))
- if (since) {
- deposits = deposits
- .where('deposits.updatedAt', '>=', since)
- }
-
- debug('deposits since ' + since)
-
- if (starts_with) {
- search = search + '%'
- } else if (contains) {
- search = '%' + search + '%'
- }
+ var timeCondition = parseInput.addTimeSearch(req.query, 'deposits.updatedAt')
+ var userCondition = parseInput.addUserSearch(req.query)
- if (search) {
- deposits = deposits
- .where(function() {
- this.where('users.email', 'like', search)
- this.orWhere('users.username', 'like', search)
- })
- }
+ if (timeCondition) deposits = deposits.whereRaw(timeCondition)
+ if (userCondition) deposits = deposits.whereRaw(userCondition)
var found = await deposits
debug('deposits: ' + JSON.stringify(found))
@@ -530,27 +461,11 @@ router.get(
.from('withdrawals')
.leftJoin('users', 'withdrawals.user_id', 'users.id')
- if (since) {
- withdrawals = withdrawals
- .where('withdrawals.updatedAt', '>=', since)
- }
-
- debug('withdrawals since ' + since)
-
-
- if (starts_with) {
- search = search + '%'
- } else if (contains) {
- search = '%' + search + '%'
- }
+ var timeCondition = parseInput.addTimeSearch(req.query, 'withdrawals.updatedAt')
+ var userCondition = parseInput.addUserSearch(req.query)
- if (search) {
- withdrawals = withdrawals
- .where(function() {
- this.where('users.email', 'like', search)
- this.orWhere('users.username', 'like', search)
- })
- }
+ if (timeCondition) withdrawals = withdrawals.whereRaw(timeCondition)
+ if (userCondition) withdrawals = withdrawals.whereRaw(userCondition)
var found = await withdrawals
debug('withdrawals: ' + JSON.stringify(found))
@@ -595,27 +510,12 @@ router.get(
.leftJoin('accounts', 'payments.account_id', 'accounts.id')
.leftJoin('users', 'accounts.user_id', 'users.id')
- if (since) {
- payments = payments
- .where('payments.updatedAt', '>=', since)
- }
-
- debug('payments since ' + since)
-
+ var timeCondition = parseInput.addTimeSearch(req.query, 'payments.updatedAt')
+ var userCondition = parseInput.addUserSearch(req.query)
- if (starts_with) {
- search = search + '%'
- } else if (contains) {
- search = '%' + search + '%'
- }
+ if (timeCondition) payments = payments.whereRaw(timeCondition)
+ if (userCondition) payments = payments.whereRaw(userCondition)
- if (search) {
- payments = payments
- .where(function() {
- this.where('users.email', 'like', search)
- this.orWhere('users.username', 'like', search)
- })
- }
var found = await payments
debug('payments: ' + JSON.stringify(found))
return res.send({payments: found})
@@ -658,7 +558,9 @@ router.get(
// 'payments.network',
// knex.raw('LEFT(hash,20) as hash'),
// knex.raw('Left(payments.updatedAt,16) as transferred')
- )
+ // knex.raw( parseInput.readableDate('Max(payments.updatedAt)', 'last_changed') )
+ knex.raw( 'DATE_FORMAT(Max(payments.updatedAt), ?) AS last_changed', "%M %d, %Y" )
+ )
.from('payments')
.leftJoin('accounts', 'payments.account_id', 'accounts.id')
.leftJoin('users', 'payments.user_id', 'users.id') // should really point to accounts
@@ -666,30 +568,16 @@ router.get(
// .groupBy('payments.currency')
// .groupBy('payments.network')
- if (since) {
- kyc = kyc
- .where('payments.updatedAt', '>=', since)
- }
-
- debug('payments since ' + since)
+ var timeCondition = parseInput.addTimeSearch(req.query, 'payments.updatedAt')
+ var userCondition = parseInput.addUserSearch(req.query)
- if (starts_with) {
- search = search + '%'
- } else if (contains) {
- search = '%' + search + '%'
- }
+ if (timeCondition) kyc = kyc.whereRaw(timeCondition)
+ if (userCondition) kyc = kyc.whereRaw(userCondition)
- if (search) {
- kyc = kyc
- .where(function() {
- this.where('users.email', 'like', search)
- this.orWhere('users.username', 'like', search)
- })
- }
var found = await kyc.having('max', '>=', threshold)
debug('payments: ' + JSON.stringify(found))
- return res.send({kyc_transactions: found})
+ return res.send({found: found})
})
);
diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js
index 67ccdb45..603db47b 100644
--- a/routes/bitcoin/receive.js
+++ b/routes/bitcoin/receive.js
@@ -18,6 +18,8 @@ const network =
config.bitcoin.network === "mainnet" ? "bitcoin" : config.bitcoin.network
];
+const queue = {};
+
zmqRawTx.on("message", async (topic, message, sequence) => {
const hex = message.toString("hex");
let tx = bitcoin.Transaction.fromHex(message);
@@ -27,7 +29,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
if (payments.includes(hash)) return;
Promise.all(
- tx.outs.map(async o => {
+ tx.outs.map(async (o) => {
try {
const { value } = o;
@@ -46,20 +48,20 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
let user = await db.User.findOne({
where: {
- username: addresses[address]
- }
+ username: addresses[address],
+ },
});
const invoice = await db.Invoice.findOne({
where: {
user_id: user.id,
- network: "bitcoin"
+ network: "bitcoin",
},
order: [["id", "DESC"]],
include: {
model: db.Account,
- as: "account"
- }
+ as: "account",
+ },
});
if (!invoice) return;
@@ -104,7 +106,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
confirmed,
address,
network: "bitcoin",
- invoice_id: invoice.id
+ invoice_id: invoice.id,
});
payment = payment.get({ plain: true });
payment.account = account.get({ plain: true });
@@ -123,19 +125,17 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
);
});
-let queue = {};
-
zmqRawBlock.on("message", async (topic, message, sequence) => {
- const payments = await db.Payment.findAll({
- where: { confirmed: false }
- });
+ const payments = await db.Payment.findAll({
+ where: { confirmed: false },
+ });
- let block = bitcoin.Block.fromHex(message.toString("hex"));
- block.transactions.map(tx => {
- let hash = reverse(tx.getHash()).toString("hex");
- if (payments.find(p => p.hash === hash)) queue[hash] = 1;
+ let block = bitcoin.Block.fromHex(message.toString("hex"));
+ block.transactions.map((tx) => {
+ let hash = reverse(tx.getHash()).toString("hex");
+ if (payments.find((p) => p.hash === hash)) queue[hash] = 1;
+ });
});
-});
setInterval(async () => {
try {
@@ -144,25 +144,25 @@ setInterval(async () => {
const hash = arr[i];
let account, address, user, total;
- await db.transaction(async transaction => {
+ await db.transaction(async (transaction) => {
let p = await db.Payment.findOne({
where: { hash, confirmed: 0, received: 1 },
include: [
{
model: db.Account,
- as: "account"
+ as: "account",
},
{
model: db.Invoice,
- as: "invoice"
+ as: "invoice",
},
{
model: db.User,
- as: "user"
- }
+ as: "user",
+ },
],
lock: transaction.LOCK.UPDATE,
- transaction
+ transaction,
});
if (p && p.address) address = p.address;
@@ -211,7 +211,7 @@ setInterval(async () => {
address: c.address,
amount: total - 100,
user,
- limit: total
+ limit: total,
});
}
}
diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js
index cab79e06..470889b3 100644
--- a/routes/bitcoin/send.js
+++ b/routes/bitcoin/send.js
@@ -1,4 +1,3 @@
-const bitcoin = require("bitcoinjs-lib");
const btc = config.liquid.btcasset;
module.exports = ah(async (req, res) => {
@@ -32,10 +31,10 @@ module.exports = ah(async (req, res) => {
total = total - change + fee;
let amount = total - fee;
- let params;
+ let account, params;
try {
await db.transaction(async transaction => {
- let account = await db.Account.findOne({
+ account = await db.Account.findOne({
where: {
id: user.account_id
},
@@ -62,38 +61,38 @@ module.exports = ah(async (req, res) => {
await account.decrement({ balance: total }, { transaction });
await account.reload({ transaction });
+ });
- params = {
- amount: -amount,
- fee,
- memo,
- account_id: account.id,
- user_id: user.id,
- rate: app.get("rates")[user.currency],
- currency: user.currency,
- address,
- confirmed: true,
- received: false,
- network: "bitcoin"
- };
+ params = {
+ amount: -amount,
+ fee,
+ memo,
+ account_id: account.id,
+ user_id: user.id,
+ rate: app.get("rates")[user.currency],
+ currency: user.currency,
+ address,
+ confirmed: true,
+ received: false,
+ network: "bitcoin"
+ };
- if (config.bitcoin.walletpass)
- await bc.walletPassphrase(config.bitcoin.walletpass, 300);
+ if (config.bitcoin.walletpass)
+ await bc.walletPassphrase(config.bitcoin.walletpass, 300);
- hex = (await bc.signRawTransactionWithWallet(hex)).hex;
- params.hash = await bc.sendRawTransaction(hex);
+ hex = (await bc.signRawTransactionWithWallet(hex)).hex;
+ params.hash = await bc.sendRawTransaction(hex);
- let payment = await db.Payment.create(params, { transaction });
+ let payment = await db.Payment.create(params);
- payment = payment.get({ plain: true });
- payment.account = account.get({ plain: true });
+ payment = payment.get({ plain: true });
+ payment.account = account.get({ plain: true });
- emit(user.username, "payment", payment);
- res.send(payment);
+ emit(user.username, "payment", payment);
+ res.send(payment);
- payments.push(params.hash);
- l.info("sent bitcoin", user.username, total);
- });
+ payments.push(params.hash);
+ l.info("sent bitcoin", user.username, total);
} catch (e) {
l.error("error sending bitcoin", e.message);
return res.status(500).send(e.message);
diff --git a/routes/invoices.js b/routes/invoices.js
index c188811e..51906b8c 100644
--- a/routes/invoices.js
+++ b/routes/invoices.js
@@ -27,6 +27,10 @@ app.post(
let { liquidAddress, invoice, user, tx } = req.body;
let { blindkey } = invoice;
+ if (invoice.amount < 0) throw new Error("amount out of range");
+ if (invoice.tip > invoice.amount || invoice.tip > 1000000 || invoice.tip < 0)
+ throw new Error("tip amount out of range");
+
if (liquidAddress) {
l.info("conversion request for", liquidAddress, invoice.text);
convert[invoice.text] = { address: liquidAddress, tx };
diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js
index 0e98cd93..d974860e 100644
--- a/routes/lightning/receive.js
+++ b/routes/lightning/receive.js
@@ -1,21 +1,18 @@
-const handlePayment = async msg => {
+const handlePayment = async (msg) => {
+ if (!msg.settled) return;
let account, total, user;
- try {
- await db.transaction(async transaction => {
- if (!msg.settled) return;
- const invoice = await db.Invoice.findOne({
- where: {
- text: msg.payment_request
- }
- });
+ const invoice = await db.Invoice.findOne({
+ where: {
+ text: msg.payment_request,
+ },
+ });
- if (!invoice)
- return l.warn(
- "received lightning with no invoice",
- msg.payment_request
- );
+ if (!invoice)
+ return l.warn("received lightning with no invoice", msg.payment_request);
+ try {
+ await db.transaction(async (transaction) => {
const { text: hash, currency, memo, rate, tip, user_id } = invoice;
const amount = parseInt(msg.amt_paid_sat) - tip;
if (amount > 10000000 || amount < 0)
@@ -25,14 +22,14 @@ const handlePayment = async msg => {
where: {
user_id,
asset: config.liquid.btcasset,
- pubkey: null
+ pubkey: null,
},
include: {
model: db.User,
- as: "user"
+ as: "user",
},
lock: transaction.LOCK.UPDATE,
- transaction
+ transaction,
});
({ user } = account);
@@ -52,7 +49,8 @@ const handlePayment = async msg => {
received: true,
confirmed: true,
network: "lightning",
- tip
+ tip,
+ invoice_id: invoice.id,
},
{ transaction }
);
@@ -85,7 +83,12 @@ const handlePayment = async msg => {
let c = convert[msg.payment_request];
if (msg.payment_request && c) {
- l.info("lightning detected for conversion request", msg.payment_request, c.address, user.username);
+ l.info(
+ "lightning detected for conversion request",
+ msg.payment_request,
+ c.address,
+ user.username
+ );
user.account = account;
@@ -94,7 +97,7 @@ const handlePayment = async msg => {
address: c.address,
amount: total - 100,
user,
- limit: total
+ limit: total,
});
} catch (e) {
l.error("problem sending liquid payment", e.message, e.stack);
@@ -106,14 +109,14 @@ const handlePayment = async msg => {
};
if (config.lna.clightning) {
- const poll = async ln => {
- const wait = async i => {
+ const poll = async (ln) => {
+ const wait = async (i) => {
const {
bolt11: payment_request,
pay_index,
status,
msatoshi_received,
- payment_preimage: r_preimage
+ payment_preimage: r_preimage,
} = await ln.waitanyinvoice(i);
let settled = status === "paid";
@@ -123,13 +126,13 @@ if (config.lna.clightning) {
payment_request,
settled,
amt_paid_sat,
- r_preimage
+ r_preimage,
});
wait(pay_index);
};
const { invoices } = await ln.listinvoices();
- wait(Math.max(...invoices.map(i => i.pay_index).filter(n => n)));
+ wait(Math.max(...invoices.map((i) => i.pay_index).filter((n) => n)));
};
poll(lna);
diff --git a/routes/liquid/fee.js b/routes/liquid/fee.js
index 2070873a..fad69f13 100644
--- a/routes/liquid/fee.js
+++ b/routes/liquid/fee.js
@@ -3,11 +3,6 @@ const buildTx = require("../../lib/buildliquidtx");
liquidTx = async ({ address, asset, amount, feeRate, replaceable, user }) => {
let tx, fee;
let node = lq;
- /*
- if (asset === config.liquid.btcasset) {
- node = rare;
- }
- */
if (user.account.pubkey) {
let psbt = await buildTx({
@@ -64,6 +59,8 @@ liquidTx = async ({ address, asset, amount, feeRate, replaceable, user }) => {
}
);
+ l.info("funding tx for fee estimate", tx);
+
tx = await node.fundRawTransaction(tx, params);
let blinded = await node.blindRawTransaction(tx.hex);
@@ -81,7 +78,7 @@ module.exports = ah(async (req, res) => {
let tx = await liquidTx({ ...req.body, user: req.user })
res.send(tx);
} catch (e) {
- l.error("error estimating liquid fee", e.message, e.stack);
+ l.error("error estimating liquid fee", e.message);
return res.status(500).send(e.message);
}
});
diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js
index 3a6aab10..2396755f 100644
--- a/routes/liquid/receive.js
+++ b/routes/liquid/receive.js
@@ -15,7 +15,7 @@ const getAccount = async (params, transaction) => {
let account = await db.Account.findOne({
where: params,
lock: transaction.LOCK.UPDATE,
- transaction
+ transaction,
});
if (account) {
@@ -37,12 +37,12 @@ const getAccount = async (params, transaction) => {
const existing = await db.Account.findOne({
where: {
asset,
- pubkey
+ pubkey,
},
order: [["id", "ASC"]],
limit: 1,
lock: transaction.LOCK.UPDATE,
- transaction
+ transaction,
});
if (existing) {
@@ -65,6 +65,8 @@ const zmqRawTx = zmq.socket("sub");
zmqRawTx.connect(config.liquid.zmqrawtx);
zmqRawTx.subscribe("rawtx");
+const queue = {};
+
zmqRawTx.on("message", async (topic, message, sequence) => {
const hex = message.toString("hex");
@@ -80,7 +82,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
if (payments.includes(blinded.txid)) return;
Promise.all(
- tx.vout.map(async o => {
+ tx.vout.map(async (o) => {
try {
if (!(o.scriptPubKey && o.scriptPubKey.addresses)) return;
@@ -92,14 +94,14 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
Object.keys(addresses).includes(address) &&
!change.includes(address)
) {
- await db.transaction(async transaction => {
+ await db.transaction(async (transaction) => {
let user = await getUser(addresses[address], transaction);
let invoice = await db.Invoice.findOne({
where: {
unconfidential: address,
user_id: user.id,
- network: "liquid"
+ network: "liquid",
},
order: [["id", "DESC"]],
});
@@ -110,10 +112,10 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
let account = await db.Account.findOne({
where: {
- id: invoice.account_id
+ id: invoice.account_id,
},
lock: transaction.LOCK.UPDATE,
- transaction
+ transaction,
});
if (
@@ -131,7 +133,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
asset,
pubkey: account.pubkey,
pending: value,
- index: 0
+ index: 0,
},
transaction
);
@@ -162,7 +164,8 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
tip,
confirmed,
address,
- network: "liquid"
+ network: "liquid",
+ invoice_id: invoice.id,
},
{ transaction }
);
@@ -185,12 +188,10 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
);
});
-let queue = {};
-
zmqRawBlock.on("message", async (topic, message, sequence) => {
try {
const payments = await db.Payment.findAll({
- where: { confirmed: 0 }
+ where: { confirmed: 0 },
});
const block = Block.fromHex(message.toString("hex"), true);
@@ -200,9 +201,9 @@ zmqRawBlock.on("message", async (topic, message, sequence) => {
hash = await lq.getBlockHash(block.height);
json = await lq.getBlock(hash, 2);
- json.tx.map(async tx => {
+ json.tx.map(async (tx) => {
if (issuances[tx.txid]) {
- await db.transaction(async transaction => {
+ await db.transaction(async (transaction) => {
const {
user_id,
asset,
@@ -210,7 +211,7 @@ zmqRawBlock.on("message", async (topic, message, sequence) => {
asset_payment_id,
token,
token_amount,
- token_payment_id
+ token_payment_id,
} = issuances[tx.txid];
const user = await getUserById(user_id);
@@ -218,7 +219,7 @@ zmqRawBlock.on("message", async (topic, message, sequence) => {
let account = await db.Account.findOne({
where: { user_id, asset },
lock: transaction.LOCK.UPDATE,
- transaction
+ transaction,
});
account.balance = asset_amount * SATS;
account.pending = 0;
@@ -228,10 +229,10 @@ zmqRawBlock.on("message", async (topic, message, sequence) => {
where: { id: asset_payment_id },
include: {
model: db.Account,
- as: "account"
+ as: "account",
},
lock: transaction.LOCK.UPDATE,
- transaction
+ transaction,
});
payment.confirmed = true;
@@ -246,7 +247,7 @@ zmqRawBlock.on("message", async (topic, message, sequence) => {
account = await db.Account.findOne({
where: { user_id, asset: token },
lock: transaction.LOCK.UPDATE,
- transaction
+ transaction,
});
account.balance = token_amount * SATS;
account.pending = 0;
@@ -256,10 +257,10 @@ zmqRawBlock.on("message", async (topic, message, sequence) => {
where: { id: token_payment_id },
include: {
model: db.Account,
- as: "account"
+ as: "account",
},
lock: transaction.LOCK.UPDATE,
- transaction
+ transaction,
});
payment.confirmed = true;
@@ -272,7 +273,7 @@ zmqRawBlock.on("message", async (topic, message, sequence) => {
emit(user.username, "payment", payment);
}
});
- } else if (payments.find(p => p.hash === tx.txid)) queue[tx.txid] = 1;
+ } else if (payments.find((p) => p.hash === tx.txid)) queue[tx.txid] = 1;
});
} catch (e) {
return console.log(e);
@@ -286,26 +287,26 @@ setInterval(async () => {
for (let i = 0; i < arr.length; i++) {
const hash = arr[i];
- let account, address, user, total;
- await db.transaction(async transaction => {
- let p = await db.Payment.findOne({
+ let account, address, user, total, p;
+ await db.transaction(async (transaction) => {
+ p = await db.Payment.findOne({
where: { hash, confirmed: 0, received: 1 },
include: [
{
model: db.Account,
- as: "account"
+ as: "account",
},
{
model: db.Invoice,
- as: "invoice"
+ as: "invoice",
},
{
model: db.User,
- as: "user"
- }
+ as: "user",
+ },
],
lock: transaction.LOCK.UPDATE,
- transaction
+ transaction,
});
({ account, address, user } = p);
@@ -338,7 +339,7 @@ setInterval(async () => {
);
notify(user, `${total} SAT payment confirmed`);
- await callWebhook(p.invoice, p);
+ callWebhook(p.invoice, p);
} else {
l.warn("couldn't find liquid payment", hash);
}
@@ -347,7 +348,7 @@ setInterval(async () => {
});
let c = convert[address];
- if (address && c) {
+ if (address && c && p.account.asset === network.assetHash) {
l.info(
"liquid detected for conversion request",
address,
@@ -361,11 +362,11 @@ setInterval(async () => {
address: c.address,
amount: total - 100,
user,
- limit: total
+ limit: total,
});
}
}
} catch (e) {
l.error("problem processing queued liquid transaction", e.message, e.stack);
}
-}, 1000);
+});
diff --git a/routes/liquid/send.js b/routes/liquid/send.js
index 19b7344f..5abc692f 100644
--- a/routes/liquid/send.js
+++ b/routes/liquid/send.js
@@ -1,5 +1,6 @@
const btc = config.liquid.btcasset;
const lcad = config.liquid.cadasset;
+const { Transaction } = require("@asoltys/liquidjs-lib");
sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
if (amount > 10000000) throw new Error("Amount too large");
@@ -48,7 +49,8 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
const assets = Object.keys(totals);
const payments = [];
- return db.transaction(async transaction => {
+ let main, signed;
+ await db.transaction(async transaction => {
for (let i = 0; i < assets.length; i++) {
let asset = assets[i];
let amount = totals[asset];
@@ -75,12 +77,12 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
await faucet.reload({ transaction });
await faucet.save({ transaction });
}
-
- total += fee - covered;
}
+
+ total += fee - covered;
}
- if (limit && total > limit)
+ if (limit && total > limit + fee)
throw new Error("Tx amount exceeds authorized amount");
if (asset !== btc || total) {
@@ -132,16 +134,11 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
}
}
- if (config.liquid.walletpass)
- await lq.walletPassphrase(config.liquid.walletpass, 300);
-
- let blinded = await lq.blindRawTransaction(tx.hex);
- let signed = await lq.signRawTransactionWithWallet(blinded);
- let txid = await lq.sendRawTransaction(signed.hex);
-
- l.info("sent liquid tx", txid, address);
+ signed = await lq.signRawTransactionWithWallet(
+ await lq.blindRawTransaction(tx.hex)
+ );
+ let txid = Transaction.fromHex(signed.hex).getId();
- let main;
for (let i = 0; i < assets.length; i++) {
p = payments[i];
if (p) {
@@ -157,15 +154,22 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
emit(user.username, "account", main.account);
emit(user.username, "payment", main);
- return main;
});
+
+ if (config.liquid.walletpass)
+ await lq.walletPassphrase(config.liquid.walletpass, 300);
+
+ let txid = await lq.sendRawTransaction(signed.hex);
+ l.info("sent liquid tx", txid, address);
+
+ return main;
};
module.exports = ah(async (req, res) => {
let { user } = req;
try {
- res.send(await sendLiquid({...req.body, user }));
+ res.send(await sendLiquid({ ...req.body, user }));
} catch (e) {
l.error("problem sending liquid", user.username, e.message);
return res.status(500).send(e);
diff --git a/routes/lnurl.js b/routes/lnurl.js
index adf4df7c..67f581d1 100644
--- a/routes/lnurl.js
+++ b/routes/lnurl.js
@@ -129,16 +129,6 @@ app.get(
maxSendable = maxSendable || 1000000000;
if (parseInt(amount)) minSendable = maxSendable = amount * 1000;
- let invoices = await db.Invoice.findAll({
- where: {
- amount
- },
- order: [["id", "DESC"]],
- limit: 1
- });
-
- if (invoices.length) await invoices[0].destroy();
-
try {
const result = await lnurlServer.generateNewUrl("payRequest", {
minSendable,
diff --git a/routes/payments.js b/routes/payments.js
index 70b711da..efb01079 100644
--- a/routes/payments.js
+++ b/routes/payments.js
@@ -96,6 +96,7 @@ ah(async () => {
if (config.lna.clightning) {
lna = require("clightning-client")(config.lna.dir);
} else {
+ lnd = require("../lib/lnd");
lna = lnd.default;
lnp = [
"addInvoice",
diff --git a/routes/referrals.js b/routes/referrals.js
index 3bcce5b2..11cf8590 100644
--- a/routes/referrals.js
+++ b/routes/referrals.js
@@ -244,6 +244,7 @@ router.post(
debug('email: ' + email)
debug('phone: ' + phone)
+ debug('user_id: ' + user_id)
await knex.table('waiting_list')
.insert({
@@ -259,15 +260,17 @@ router.post(
router.get(
"/joinQueue",
ah(async (req, res) => {
- const {email, phone} = req.query;
+ const {email, phone, user_id} = req.query;
debug('email: ' + email)
debug('phone: ' + phone)
+ debug('user: ' + user_id)
await knex('waiting_list')
.insert({
email: email,
- phone: phone
+ phone: phone,
+ user_id: user_id
})
res.send({success: true, message: 'Added ' + email + ' to waiting list ' + phone})
diff --git a/routes/send.js b/routes/send.js
index 579e70b4..3aec9fb6 100644
--- a/routes/send.js
+++ b/routes/send.js
@@ -45,7 +45,7 @@ module.exports = ah(async (req, res, next) => {
};
if (!username) {
- return res.status(500).send("Vouchers temporarily disabled");
+ throw new Error("Vouchers temporarily disabled");
l.info("creating redeemable payment");
params.redeemcode = uuidv4();
params.hash = `${req.get("origin")}/redeem/${params.redeemcode}`;
diff --git a/routes/users.js b/routes/users.js
index 71f4b89a..23f016c7 100644
--- a/routes/users.js
+++ b/routes/users.js
@@ -148,7 +148,8 @@ app.post(
return res.status(500).send("Username taken");
} else {
sockets[username] = sockets[user.username];
- if (user.username !== username) l.info("changing username", user.username, username);
+ if (user.username !== username)
+ l.info("changing username", user.username, username);
user.username = username;
token = jwt.sign({ username }, config.jwt);
@@ -323,10 +324,7 @@ app.post(
(user.password &&
!(await bcrypt.compare(req.body.password, user.password)))
) {
- l.warn(
- "invalid username or password attempt",
- req.body.username
- );
+ l.warn("invalid username or password attempt", req.body.username);
return res.status(401).end();
}
@@ -426,11 +424,24 @@ app.get(
: config.liquid.network
];
type = "p2sh";
-
+
// async request to node to bump its internal index but don't use result
- lq.getNewAddress().catch(console.error);
+ lq.getNewAddress().catch(e =>
+ l.warn("Problem bumping liquid address index", e.message)
+ );
i = parseInt(app.get("lqAddressIndex"));
+
+ if (!i) {
+ const { hdkeypath } = await lq.getAddressInfo(
+ await lq.getNewAddress()
+ );
+ const parts = hdkeypath.split("/");
+ i = parts[parts.length - 1].slice(0, -1);
+ }
+
+ if (!i) throw new Error("Problem generating address");
+
hd = fromBase58(config.liquid.masterkey, n).derivePath(`m/0'/0'/${i}'`);
app.set("lqAddressIndex", i + 1);
} else {
diff --git a/scripts/apiParse.js b/scripts/apiParse.js
index 427f34cd..138a82f4 100644
--- a/scripts/apiParse.js
+++ b/scripts/apiParse.js
@@ -1,9 +1,10 @@
var debug = require('debug')('debug')
-const addUserSearch = async function (input) {
+const addUserSearch = function (input, table) {
debug('add User Search')
var {search, starts_with, contains} = input
+ if (!table) { table = 'Users' }
// if (since) cmd = cmd.havingRaw('invoices + payments + deposits + orders > ?', [0])
if (search) {
@@ -13,7 +14,7 @@ const addUserSearch = async function (input) {
search = '%' + search + '%'
}
- var condition = "(Users.email like '" + search + " OR Users.username like '" + search + "'"
+ var condition = "(" + table + ".email like '" + search + "' OR " + table + ".username like '" + search + "')"
debug('condition: ' + condition)
return condition
@@ -22,14 +23,14 @@ const addUserSearch = async function (input) {
}
}
-const addTimeSearch = async function (input, field) {
+const addTimeSearch = function (input, field) {
debug('add time Search')
if (!field) { field = 'updatedAt' }
var {since} = input
if (since) {
- condition = "WHERE " + field + " >= " + since
+ condition = field + " >= '" + since + "'"
debug('condition: ' + condition)
return condition
@@ -38,5 +39,8 @@ const addTimeSearch = async function (input, field) {
}
}
-module.exports = {addUserSearch: addUserSearch, addTimeSearch: addTimeSearch}
+module.exports = {
+ addUserSearch: addUserSearch,
+ addTimeSearch: addTimeSearch,
+}
diff --git a/watcher.sh b/watcher.sh
deleted file mode 100755
index 3fb60993..00000000
--- a/watcher.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-
-sats=100000000
-threshold=$1
-while true
-do
- ln=$(lncli --lnddir=/root/.lnda --network=mainnet --chain=bitcoin --rpcserver=localhost:10001 channelbalance | jr .balance)
- bc=$(bitcoin-cli getbalance)
- el=$(elements-cli getbalance | jr .bitcoin)
- total=$(node -pe "$ln + $bc * $sats + $el * $sats")
- low=$(node -pe "$total < $threshold")
- echo $(date -Is) ln $ln bc $bc el $el tot $total
- if "$low"; then
- echo "Threshold hit, setting new threshold"
- threshold=$total
- # yarn pm2 stop 0 > /dev/null
- node /root/mailgun/index.js
- fi
- sleep 10
-done