aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2021-09-24 02:19:30 -0400
committerAdam Soltys <[email protected]>2021-09-24 02:19:30 -0400
commit18814242ad055ecd6f9de1d23209958e12aee69c (patch)
treef9abc8b8716b5587c8a71700df62ebfe2098f4f6
parentfd44b77a4ddac5beef34f65be8e5558f4b4291f9 (diff)
downloadcoinos-server-18814242ad055ecd6f9de1d23209958e12aee69c.tar.gz
coinos-server-18814242ad055ecd6f9de1d23209958e12aee69c.zip
always create account on issuance
-rw-r--r--db/migrations/20210814193811_fix_db_conflicts.js16
-rw-r--r--db/migrations/20210821013757_cull_usernames.js11
-rw-r--r--index.js2
-rw-r--r--lib/buildliquidtx.js31
-rw-r--r--lib/rates.js1
-rw-r--r--lib/send.js4
-rw-r--r--routes/assets.js88
-rw-r--r--routes/bitcoin/receive.js12
-rw-r--r--routes/lightning/receive.js2
-rw-r--r--routes/lightning/send.js2
-rw-r--r--routes/liquid/receive.js2
-rw-r--r--routes/liquid/send.js256
-rw-r--r--routes/lnurl.js4
-rw-r--r--routes/payments.js11
14 files changed, 230 insertions, 212 deletions
diff --git a/db/migrations/20210814193811_fix_db_conflicts.js b/db/migrations/20210814193811_fix_db_conflicts.js
deleted file mode 100644
index 37ff2bbc..00000000
--- a/db/migrations/20210814193811_fix_db_conflicts.js
+++ /dev/null
@@ -1,16 +0,0 @@
-
-exports.up = function(knex) {
- return Promise.all([
- knex.raw("UPDATE waiting_list set created_at = '2021-01-01', updated_at='2021-01-01' WHERE updated_at IS NULL OR created_at IS NULL"),
- knex.raw("ALTER TABLE waiting_list MODIFY created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP"),
- knex.raw("ALTER TABLE waiting_list MODIFY updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP"),
-
- knex.raw("UPDATE referrals set created_at = '2021-01-01', updated_at='2021-01-01' WHERE updated_at IS NULL OR created_at IS NULL"),
- knex.raw("ALTER TABLE referrals MODIFY created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP"),
- knex.raw("ALTER TABLE referrals MODIFY updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP")
- ])
-};
-
-exports.down = function(knex) {
-
-};
diff --git a/db/migrations/20210821013757_cull_usernames.js b/db/migrations/20210821013757_cull_usernames.js
deleted file mode 100644
index 5d2a4672..00000000
--- a/db/migrations/20210821013757_cull_usernames.js
+++ /dev/null
@@ -1,11 +0,0 @@
-
-exports.up = function(knex) {
- return Promise.all([
- knex.raw("UPDATE users SET username = REPLACE(username, ' ', '')"), // just in case valid users have trailing spaces in their username
- knex.raw("DELETE FROM users WHERE !(username REGEXP '^[a-zA-Z0-9\.\_\@\-]{3,32}$')"),
- ])
-};
-
-exports.down = function(knex) {
-
-};
diff --git a/index.js b/index.js
index e0a5a059..430a2333 100644
--- a/index.js
+++ b/index.js
@@ -116,7 +116,7 @@ app.use((err, req, res, next) => {
});
server.listen(config.port, () =>
- console.log(`CoinOS Server listening on port ${config.port}`)
+ l.info(`CoinOS Server listening on port ${config.port}`)
);
process.on("SIGINT", process.exit);
diff --git a/lib/buildliquidtx.js b/lib/buildliquidtx.js
index 7bebb548..aab8e000 100644
--- a/lib/buildliquidtx.js
+++ b/lib/buildliquidtx.js
@@ -7,6 +7,7 @@ const api = prod
: "http://localhost:3002";
const SATS = 100000000;
const network = prod ? liquid.networks["liquid"] : liquid.networks["regtest"];
+const { Op } = require("sequelize");
module.exports = async ({
address,
@@ -26,13 +27,29 @@ module.exports = async ({
feeRate = Math.round(feeRate / 100);
if (asset !== btc) feeRate = 0;
- const payments = await db.Payment.findAll({
- where: {
- received: true,
- account_id: user.account_id,
- network: "liquid"
- }
- });
+ let payments;
+ if (asset === btc) {
+ payments = await db.Payment.findAll({
+ where: {
+ received: true,
+ account_id: user.account_id,
+ network: "liquid"
+ }
+ });
+ } else {
+ payments = await db.Payment.findAll({
+ where: {
+ "$account.pubkey": { [Op.ne]: null },
+ received: true,
+ user_id: user.id,
+ network: "liquid"
+ },
+ include: {
+ model: db.Account,
+ as: "account"
+ }
+ });
+ }
let utxos = [];
for (let i = 0; i < payments.length; i++) {
diff --git a/lib/rates.js b/lib/rates.js
index 598fc041..55dc1ea5 100644
--- a/lib/rates.js
+++ b/lib/rates.js
@@ -59,6 +59,7 @@ setInterval(() => {
}, 1000);
setInterval(() => {
+ l.info("refreshing binance socket");
binance.terminate();
binance = require("./binance")();
}, 360000);
diff --git a/lib/send.js b/lib/send.js
index 293473d9..e08e9033 100644
--- a/lib/send.js
+++ b/lib/send.js
@@ -2,6 +2,8 @@ const bolt11 = require("bolt11");
const { Op } = require("sequelize");
send = async (amount, memo, hash, user) => {
+ l.info("attempting lightning payment", user.username, amount, hash);
+
let payreq = bolt11.decode(hash);
let routingInfo = payreq.tags.find(t => t.tagName === "routing_info");
if (
@@ -59,7 +61,7 @@ send = async (amount, memo, hash, user) => {
fee_limit: { fixed: Math.min(10000, account.balance) },
});
- if (!m) throw new Error("lightning payment failed");
+ if (!m) throw new Error(`lightning payment failed ${amount} ${hash}`);
if (m.payment_error) throw new Error(m.payment_error);
({
diff --git a/routes/assets.js b/routes/assets.js
index 72d4c329..b33e43b4 100644
--- a/routes/assets.js
+++ b/routes/assets.js
@@ -204,7 +204,6 @@ app.post(
await account.reload({ transaction });
emit(user.username, "account", account);
- if (address) return;
account = await db.Account.create(
{
asset,
@@ -216,7 +215,7 @@ app.post(
name,
balance: 0,
network: "liquid",
- pending: params.asset_amount * SATS
+ pending: address ? 0 : params.asset_amount * SATS
},
{ transaction }
);
@@ -227,30 +226,33 @@ app.post(
user.username,
params.asset_amount,
ticker,
- name
+ name,
+ account.id
);
- const asset_payment = await db.Payment.create(
- {
- account_id: account.id,
- user_id,
- hash: txid,
- amount: params.asset_amount * SATS,
- received: true,
- confirmed: false,
- address: asset_address,
- network: "liquid"
- },
- { transaction }
- );
- emit(user.username, "payment", asset_payment);
+ if (!address) {
+ const asset_payment = await db.Payment.create(
+ {
+ account_id: account.id,
+ user_id,
+ hash: txid,
+ amount: params.asset_amount * SATS,
+ received: true,
+ confirmed: false,
+ address: asset_address,
+ network: "liquid"
+ },
+ { transaction }
+ );
+ emit(user.username, "payment", asset_payment);
- issuances[txid] = {
- user_id,
- asset,
- asset_amount: params.asset_amount,
- asset_payment_id: asset_payment.id
- };
+ issuances[txid] = {
+ user_id,
+ asset,
+ asset_amount: params.asset_amount,
+ asset_payment_id: asset_payment.id
+ };
+ }
if (token_amount) {
account = await db.Account.create(
@@ -262,30 +264,32 @@ app.post(
precision: 8,
name: `${name} Reissuance Token`,
balance: 0,
- pending: token_amount * SATS
+ pending: address ? 0 : token_amount * SATS
},
{ transaction }
);
emit(user.username, "account", account);
- const token_payment = await db.Payment.create(
- {
- account_id: account.id,
- user_id,
- hash: txid,
- amount: token_amount * SATS,
- received: true,
- confirmed: false,
- address: token_address,
- network: "liquid"
- },
- { transaction }
- );
- emit(user.username, "payment", token_payment);
+ if (!address) {
+ const token_payment = await db.Payment.create(
+ {
+ account_id: account.id,
+ user_id,
+ hash: txid,
+ amount: token_amount * SATS,
+ received: true,
+ confirmed: false,
+ address: token_address,
+ network: "liquid"
+ },
+ { transaction }
+ );
+ emit(user.username, "payment", token_payment);
- issuances[txid].token = token;
- issuances[txid].token_amount = token_amount;
- issuances[txid].token_payment_id = token_payment.id;
+ issuances[txid].token = token;
+ issuances[txid].token_amount = token_amount;
+ issuances[txid].token_payment_id = token_payment.id;
+ }
}
});
@@ -309,6 +313,8 @@ app.post(
}
});
+ l.info("registering", asset, account.contract);
+
try {
const { data: result } = await axios.post(
"https://assets.blockstream.info/",
diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js
index 327d1a0c..c14e636c 100644
--- a/routes/bitcoin/receive.js
+++ b/routes/bitcoin/receive.js
@@ -76,6 +76,16 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
let { account } = invoice;
+ if (account.asset !== config.liquid.btcasset) {
+ account = await db.Account.findOne({
+ where: {
+ user_id: user.id,
+ asset: config.liquid.btcasset,
+ pubkey: null
+ }
+ });
+ }
+
account.pending += value;
await account.save();
@@ -208,7 +218,7 @@ setInterval(async () => {
);
user.account = account;
- await sendLiquid({
+ sendLiquid({
address: c.address,
amount: total - 100,
user,
diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js
index d974860e..ffc0ae03 100644
--- a/routes/lightning/receive.js
+++ b/routes/lightning/receive.js
@@ -93,7 +93,7 @@ const handlePayment = async (msg) => {
user.account = account;
try {
- await sendLiquid({
+ sendLiquid({
address: c.address,
amount: total - 100,
user,
diff --git a/routes/lightning/send.js b/routes/lightning/send.js
index f3c0da46..f6bd1b36 100644
--- a/routes/lightning/send.js
+++ b/routes/lightning/send.js
@@ -5,7 +5,7 @@ module.exports = ah(async (req, res) => {
try {
res.send(await send(amount, memo, payreq, user));
} catch (e) {
- l.error("problem sending lightning payment", user.username, e.message, e.stack);
+ l.error("problem sending lightning payment", user.username, e.message);
res.status(500).send(e.message);
}
});
diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js
index 31cddbef..bc4293d3 100644
--- a/routes/liquid/receive.js
+++ b/routes/liquid/receive.js
@@ -358,7 +358,7 @@ setInterval(async () => {
user.account = p.account;
- await sendLiquid({
+ sendLiquid({
address: c.address,
amount: total - 100,
user,
diff --git a/routes/liquid/send.js b/routes/liquid/send.js
index 0c0b2012..f5c46a6f 100644
--- a/routes/liquid/send.js
+++ b/routes/liquid/send.js
@@ -3,165 +3,169 @@ const lcad = config.liquid.cadasset;
const { Transaction } = require("@asoltys/liquidjs-lib");
sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
- l.info("sending liquid", amount, address);
- if (!tx) {
- ({ tx } = await liquidTx({
- address,
- asset,
- amount,
- feeRate: 100,
- replaceable: false,
- user
- }));
- }
+ try {
+ l.info("sending liquid", amount, address);
+ if (!tx) {
+ ({ tx } = await liquidTx({
+ address,
+ asset,
+ amount,
+ feeRate: 200,
+ replaceable: false,
+ user
+ }));
+ }
- const isChange = async address =>
- (await lq.getAddressInfo(address)).ismine &&
- !Object.keys(addresses).includes(address);
+ const isChange = async address =>
+ (await lq.getAddressInfo(address)).ismine &&
+ !Object.keys(addresses).includes(address);
- let totals = {};
- let change = {};
- let fee = 0;
+ let totals = {};
+ let change = {};
+ let fee = 0;
- let { vout } = await lq.decodeRawTransaction(tx.hex);
+ let { vout } = await lq.decodeRawTransaction(tx.hex);
- for (let i = 0; i < vout.length; i++) {
- let {
- asset,
- value,
- scriptPubKey: { type, addresses }
- } = vout[i];
+ for (let i = 0; i < vout.length; i++) {
+ let {
+ asset,
+ value,
+ scriptPubKey: { type, addresses }
+ } = vout[i];
- if (type === "fee") fee = toSats(value);
- else {
- if (!totals[asset]) totals[asset] = change[asset] = 0;
- totals[asset] += toSats(value);
+ if (type === "fee") fee = toSats(value);
+ else {
+ if (!totals[asset]) totals[asset] = change[asset] = 0;
+ totals[asset] += toSats(value);
- if (addresses) {
- if (await isChange(addresses[0])) {
- change[asset] += toSats(value);
+ if (addresses) {
+ if (await isChange(addresses[0])) {
+ change[asset] += toSats(value);
+ }
}
}
}
- }
- const assets = Object.keys(totals);
- const payments = [];
+ const assets = Object.keys(totals);
+ const payments = [];
+
+ let main, signed;
+ await db.transaction(async transaction => {
+ for (let i = 0; i < assets.length; i++) {
+ let asset = assets[i];
+ let amount = totals[asset];
+ if (change[asset]) amount -= change[asset];
+ let total = amount;
+
+ if (asset === btc) {
+ let covered = 0;
+ let nonbtc = assets.filter(a => a !== btc);
+ if (nonbtc.length === 1) {
+ let faucet = await db.Account.findOne({
+ where: {
+ asset: nonbtc[0],
+ user_id: null
+ },
+ lock: transaction.LOCK.UPDATE,
+ 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];
- if (change[asset]) amount -= change[asset];
- let total = amount;
+ if (faucet) {
+ covered = faucet.balance;
+ if (covered > fee) covered = fee;
+ await faucet.decrement({ balance: covered }, { transaction });
+ await faucet.reload({ transaction });
+ await faucet.save({ transaction });
+ }
+ }
+
+ total += fee - covered;
+ }
+
+ if (limit && total > limit + fee)
+ throw new Error("Tx amount exceeds authorized amount");
- if (asset === btc) {
- let covered = 0;
- let nonbtc = assets.filter(a => a !== btc);
- if (nonbtc.length === 1) {
- let faucet = await db.Account.findOne({
+ if (asset !== btc || total) {
+ l.info("creating liquid payment", user.username, asset, total, fee);
+
+ let account = await db.Account.findOne({
where: {
- asset: nonbtc[0],
- user_id: null
+ user_id: user.id,
+ asset,
+ pubkey: null
},
lock: transaction.LOCK.UPDATE,
+ order: [["balance", "DESC"]],
transaction
});
- if (faucet) {
- covered = faucet.balance;
- if (covered > fee) covered = fee;
- await faucet.decrement({ balance: covered }, { transaction });
- await faucet.reload({ transaction });
- await faucet.save({ transaction });
+ if (total > account.balance) {
+ l.warn("amount exceeds balance", {
+ total,
+ fee,
+ balance: account.balance
+ });
+ throw new Error(
+ `Insufficient funds, need ${total} ${
+ account.ticker === "BTC" ? "SAT" : account.ticker
+ }, have ${account.balance}`
+ );
}
- }
- total += fee - covered;
- }
+ await account.decrement({ balance: total }, { transaction });
+ await account.reload({ transaction });
- if (limit && total > limit + fee)
- throw new Error("Tx amount exceeds authorized amount");
-
- if (asset !== btc || total) {
- l.info("creating liquid payment", user.username, asset, total, fee);
-
- let account = await db.Account.findOne({
- where: {
+ let payment = {
+ amount: -amount,
+ account_id: account.id,
+ fee,
+ memo,
user_id: user.id,
- asset,
- pubkey: null
- },
- lock: transaction.LOCK.UPDATE,
- order: [["balance", "DESC"]],
- transaction
- });
+ rate: app.get("rates")[user.currency],
+ currency: user.currency,
+ address,
+ confirmed: true,
+ received: false,
+ network: "liquid"
+ };
- if (total > account.balance) {
- l.warn("amount exceeds balance", {
- total,
- fee,
- balance: account.balance
- });
- throw new Error(
- `Insufficient funds, need ${total} ${
- account.ticker === "BTC" ? "SAT" : account.ticker
- }, have ${account.balance}`
- );
+ payment.account = account;
+ payments.push(payment);
}
-
- await account.decrement({ balance: total }, { transaction });
- await account.reload({ transaction });
-
- let payment = {
- amount: -amount,
- account_id: account.id,
- fee,
- memo,
- user_id: user.id,
- rate: app.get("rates")[user.currency],
- currency: user.currency,
- address,
- confirmed: true,
- received: false,
- network: "liquid"
- };
-
- payment.account = account;
- payments.push(payment);
}
- }
- signed = await lq.signRawTransactionWithWallet(
- await lq.blindRawTransaction(tx.hex)
- );
- let txid = Transaction.fromHex(signed.hex).getId();
+ signed = await lq.signRawTransactionWithWallet(
+ await lq.blindRawTransaction(tx.hex)
+ );
+ let txid = Transaction.fromHex(signed.hex).getId();
- for (let i = 0; i < assets.length; i++) {
- p = payments[i];
- if (p) {
- let { account } = p;
- p.hash = txid;
- p = await db.Payment.create(p, { transaction });
- if (account.ticker !== "BTC" || !main) {
- main = p.get({ plain: true });
- main.account = account.get({ plain: true });
+ for (let i = 0; i < assets.length; i++) {
+ p = payments[i];
+ if (p) {
+ let { account } = p;
+ p.hash = txid;
+ p = await db.Payment.create(p, { transaction });
+ if (account.ticker !== "BTC" || !main) {
+ main = p.get({ plain: true });
+ main.account = account.get({ plain: true });
+ }
}
}
- }
- emit(user.username, "account", main.account);
- emit(user.username, "payment", main);
- });
+ emit(user.username, "account", main.account);
+ emit(user.username, "payment", main);
+ });
- if (config.liquid.walletpass)
- await lq.walletPassphrase(config.liquid.walletpass, 300);
+ 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);
+ let txid = await lq.sendRawTransaction(signed.hex);
+ l.info("sent liquid tx", txid, address);
- return main;
+ return main;
+ } catch (e) {
+ l.error("problem sending liquid", e.message);
+ }
};
module.exports = ah(async (req, res) => {
diff --git a/routes/lnurl.js b/routes/lnurl.js
index feceb913..b07aeeab 100644
--- a/routes/lnurl.js
+++ b/routes/lnurl.js
@@ -117,6 +117,7 @@ app.post(
app.get(
"/lnurlp/:username",
ah(async (req, res, next) => {
+ throw new Error("LNURL payments temporarily disabled due to a server issue. Sep. 2, 2021. Join our Telegram channel https://t.me/coinoswallet for updates");
const { username } = req.params;
let user = await db.User.findOne({
where: {
@@ -152,6 +153,7 @@ app.get(
app.get(
"/pay/:username",
ah(async (req, res, next) => {
+ throw new Error("LNURL payments temporarily disabled due to a server issue. Sep. 2, 2021. Join our Telegram channel https://t.me/coinoswallet for updates");
const { username } = req.params;
let user = await db.User.findOne({
where: {
@@ -185,6 +187,7 @@ app.post(
"/pay",
auth,
ah(async (req, res, next) => {
+ throw new Error("LNURL payments temporarily disabled due to a server issue. Sep. 2, 2021. Join our Telegram channel https://t.me/coinoswallet for updates");
const { user } = req;
const {
amount,
@@ -194,7 +197,6 @@ app.post(
let url = `${callback}${callback.includes("?") ? "&" : "?"}amount=${amount *
1000}${comment ? "&comment=" + comment : ""}`;
- console.log(url);
try {
const parts = callback.split("/");
diff --git a/routes/payments.js b/routes/payments.js
index 58b176d0..7ecfb36f 100644
--- a/routes/payments.js
+++ b/routes/payments.js
@@ -71,7 +71,8 @@ ah(async () => {
.map(i => ({
amount: parseInt(i.amt_paid_sat),
preimage: i.r_preimage.toString("hex"),
- pr: i.payment_request.toString("hex")
+ pr: i.payment_request.toString("hex"),
+ createdAt: new Date(i.settle_date * 1000)
}));
const twoDaysAgo = new Date(new Date().setDate(new Date().getDate() - 2));
@@ -84,13 +85,13 @@ ah(async () => {
let missed = recent.filter(i => !settled.includes(i.preimage));
for (let i = 0; i < missed.length; i++) {
- let { amount, preimage, pr: text } = missed[i];
+ let { amount, preimage, pr: text, createdAt } = missed[i];
let invoice = await db.Invoice.findOne({
where: { text },
include: {
model: db.User,
as: "user"
- },
+ }
});
if (invoice && invoice.user_id) {
@@ -115,7 +116,9 @@ ah(async () => {
confirmed: true,
network: "lightning",
tip: invoice.tip,
- invoice_id: invoice.id
+ invoice_id: invoice.id,
+ createdAt,
+ updatedAt: createdAt
});
await account.increment({ balance: amount });