aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2020-10-12 00:39:45 -0700
committerAdam Soltys <[email protected]>2020-10-12 00:39:45 -0700
commita90d6cc97470696ade30f237b050b8b329858a17 (patch)
treed2b0144a6076d799aa779a731f61e7c9c864f6a7
parentd7e5d530bd37f611beb1884c0587593fb9fb5880 (diff)
downloadcoinos-server-a90d6cc97470696ade30f237b050b8b329858a17.tar.gz
coinos-server-a90d6cc97470696ade30f237b050b8b329858a17.zip
javascript address generation
-rw-r--r--lib/register.js28
-rw-r--r--package.json1
-rw-r--r--routes/bitcoin/receive.js5
-rw-r--r--routes/invoices.js2
-rw-r--r--routes/payments.js14
-rw-r--r--routes/users.js113
-rw-r--r--yarn.lock12
7 files changed, 127 insertions, 48 deletions
diff --git a/lib/register.js b/lib/register.js
index 7502c626..23e20a72 100644
--- a/lib/register.js
+++ b/lib/register.js
@@ -12,34 +12,6 @@ register = async (user, ip, requireChallenge) => {
user.password = await bcrypt.hash(user.password, 1);
}
- if (config.bitcoin) {
- if (config.bitcoin.walletpass)
- await bc.walletPassphrase(config.bitcoin.walletpass, 300);
-
- user.address = await bc.getNewAddress("", "bech32");
- addresses[user.address] = user.username;
- }
-
- if (config.liquid) {
- if (config.liquid.walletpass)
- await lq.walletPassphrase(config.liquid.walletpass, 300);
-
- user.confidential = await lq.getNewAddress();
- user.liquid = (await lq.getAddressInfo(user.confidential)).unconfidential;
- addresses[user.liquid] = user.username;
- }
-
- if (
- requireChallenge &&
- (!challenge[ip] ||
- user.response.toLowerCase() !== challenge[ip].toLowerCase())
- ) {
- l.info("failed challenge", ip, user.response, challenge[ip]);
- throw new Error("Failed challenge");
- }
-
- delete challenge[ip];
-
let countries = {
CA: "CAD",
US: "USD",
diff --git a/package.json b/package.json
index 746e4c6a..53668ac7 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
},
"dependencies": {
"@grpc/proto-loader": "^0.5.3",
+ "async-mutex": "^0.2.4",
"axios": "^0.19.0",
"bcrypt": "^5.0.0",
"bip32": "^2.0.5",
diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js
index 12eb760e..e0e3828b 100644
--- a/routes/bitcoin/receive.js
+++ b/routes/bitcoin/receive.js
@@ -77,11 +77,6 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
if (config.bitcoin.walletpass)
await bc.walletPassphrase(config.bitcoin.walletpass, 300);
- user.address = await bc.getNewAddress("", "bech32");
- await user.save();
-
- addresses[user.address] = user.username;
-
let totalOutputs = tx.outs.reduce((a, b) => a + b.value, 0);
let totalInputs = 0;
for (let i = 0; i < tx.ins.length; i++) {
diff --git a/routes/invoices.js b/routes/invoices.js
index f084b4c3..443c1565 100644
--- a/routes/invoices.js
+++ b/routes/invoices.js
@@ -62,7 +62,7 @@ app.post("/invoice", ah(async (req, res, next) => {
addresses[invoice.address] = user.username;
if (invoice.unconfidential) {
addresses[invoice.unconfidential] = user.username;
- await lq.importBlindingKey(invoice.address, blindkey);
+ if (blindkey) await lq.importBlindingKey(invoice.address, blindkey);
}
res.send(invoice);
} catch(e) {
diff --git a/routes/payments.js b/routes/payments.js
index 11242667..cf9e1d00 100644
--- a/routes/payments.js
+++ b/routes/payments.js
@@ -113,6 +113,13 @@ ah(async () => {
app.post("/bitcoin/fee", auth, require("./bitcoin/fee"));
app.post("/bitcoin/send", auth, require("./bitcoin/send"));
require("./bitcoin/receive");
+
+ setTimeout(async () => {
+ const address = await bc.getNewAddress();
+ const { hdkeypath } = await bc.getAddressInfo(address);
+ const parts = hdkeypath.split('/');
+ app.set("bcAddressIndex", parts[parts.length - 1].slice(0, -1));
+ }, 50);
}
if (config.liquid) {
@@ -126,6 +133,13 @@ ah(async () => {
app.post("/liquid/fee", auth, require("./liquid/fee"));
app.post("/liquid/send", auth, require("./liquid/send"));
require("./liquid/receive");
+
+ setTimeout(async () => {
+ const address = await lq.getNewAddress();
+ const { hdkeypath } = await lq.getAddressInfo(address);
+ const parts = hdkeypath.split('/');
+ app.set("lqAddressIndex", parts[parts.length - 1].slice(0, -1));
+ }, 50);
}
app.get(
diff --git a/routes/users.js b/routes/users.js
index d40ad5a8..6e9678fe 100644
--- a/routes/users.js
+++ b/routes/users.js
@@ -6,6 +6,11 @@ const textToImage = require("text-to-image");
const randomWord = require("random-words");
const getAccount = require("../lib/account");
const Sequelize = require("sequelize");
+const bitcoin = require("bitcoinjs-lib");
+const liquid = require("liquidjs-lib");
+const { fromBase58, fromPrivateKey } = require("bip32");
+const { Mutex } = require("async-mutex");
+const bip32 = require("bip32");
const pick = (O, ...K) => K.reduce((o, k) => ((o[k] = O[k]), o), {});
require("../lib/whitelist");
@@ -259,7 +264,16 @@ app.post(
"/accounts",
auth,
ah(async (req, res) => {
- const { name, seed, pubkey, ticker, precision, path, privkey, network } = req.body;
+ const {
+ name,
+ seed,
+ pubkey,
+ ticker,
+ precision,
+ path,
+ privkey,
+ network
+ } = req.body;
const { user } = req;
let account = await db.Account.create({
@@ -384,24 +398,84 @@ app.post(
app.get(
"/address",
ah(async (req, res) => {
- const { network, type } = req.query;
+ let { network, type } = req.query;
let address;
- if (network === "bitcoin") {
- if (!config.bitcoin)
- return res.status(500).send("Bitcoin not configured");
+ type = {
+ bech32: "p2wpkh",
+ "p2sh-segwit": "p2sh",
+ legacy: "p2pkh"
+ }[type];
- if (config.bitcoin.walletpass)
- await bc.walletPassphrase(config.bitcoin.walletpass, 300);
+ let hd, i, p, n;
+ const mutex = new Mutex();
+ const release = await mutex.acquire();
+ try {
+ if (network === "bitcoin") {
+ if (!config.bitcoin)
+ return res.status(500).send("Bitcoin not configured");
+ p = bitcoin.payments;
+ n = prod ? bitcoin.networks["bitcoin"] : bitcoin.networks["regtest"];
- address = await bc.getNewAddress("", type || "bech32");
- } else if (network === "liquid") {
- if (!config.liquid) return res.status(500).send("Liquid not configured");
+ i = parseInt(app.get("bcAddressIndex"));
+ hd = fromBase58(config.bitcoin.masterkey, n).derivePath(
+ `m/0'/0'/${i}'`
+ );
+ app.set("bcAddressIndex", i + 1);
+ } else if (network === "liquid") {
+ p = liquid.payments;
+ n =
+ liquid.networks[
+ config.liquid.network === "mainnet"
+ ? "liquid"
+ : config.liquid.network
+ ];
+ type = "p2sh";
- if (config.liquid.walletpass)
- await lq.walletPassphrase(config.liquid.walletpass, 300);
+ i = parseInt(app.get("lqAddressIndex"));
+ hd = fromBase58(config.liquid.masterkey, n).derivePath(`m/0'/0'/${i}'`);
+ app.set("lqAddressIndex", i + 1);
+ } else {
+ throw new Error("Unsupported network");
+ }
+ } finally {
+ release();
+ }
+
+ if (type !== "p2sh") {
+ ({ address } = p[type]({
+ pubkey: hd.publicKey,
+ network: n
+ }));
+ } else {
+ if (network === "liquid") {
+ const p2wpkh = p.p2wpkh({
+ pubkey: hd.publicKey,
+ network: n
+ });
+
+ const blindkey = fromPrivateKey(
+ Buffer.from(config.liquid.blindkey, "hex"),
+ hd.chainCode,
+ n
+ );
+
+ ({ confidentialAddress: address } = p[type]({
+ redeem: p2wpkh,
+ network: n,
+ blindkey: blindkey.publicKey
+ }));
- address = await lq.getNewAddress("", type || "bech32");
+ lq.importBlindingKey(address, blindkey.privateKey.toString('hex'));
+ } else {
+ ({ address } = p[type]({
+ redeem: p.p2wpkh({
+ pubkey: hd.publicKey,
+ network: n
+ }),
+ network: n
+ }));
+ }
}
res.send(address);
@@ -429,7 +503,18 @@ app.post(
try {
await db.Account.update(
- { name, ticker, precision, domain, seed, pubkey, path, hide, index, privkey },
+ {
+ name,
+ ticker,
+ precision,
+ domain,
+ seed,
+ pubkey,
+ path,
+ hide,
+ index,
+ privkey
+ },
{
where: { id, user_id: user.id }
}
diff --git a/yarn.lock b/yarn.lock
index d42edd09..b5b6c58a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -534,6 +534,13 @@ async-listener@^0.6.0:
semver "^5.3.0"
shimmer "^1.1.0"
+async-mutex@^0.2.4:
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.2.4.tgz#f6ea5f9cc73147f395f86fa573a2af039fe63082"
+ integrity sha512-fcQKOXUKMQc57JlmjBCHtkKNrfGpHyR7vu18RfuLfeTAf4hK9PgOadPR5cDrBQ682zasrLUhJFe7EKAHJOduDg==
+ dependencies:
+ tslib "^2.0.0"
+
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
@@ -5548,6 +5555,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==
+tslib@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c"
+ integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==
+
tsscmp@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"