aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2020-08-31 15:39:50 -0700
committerAdam Soltys <[email protected]>2020-08-31 15:39:50 -0700
commit5e6e9e32e512ef3e65ecff1db33d10376fdafffc (patch)
treecc9adf371fd612586b9fd4158ea764359d9af5ff
parentf17fb75a9fa222a63df84a5a7a9ff911bb5f9765 (diff)
downloadcoinos-server-tdex.tar.gz
coinos-server-tdex.zip
tdex wiptdex
-rw-r--r--index.js1
-rw-r--r--package.json1
-rw-r--r--routes/assets.js2
-rw-r--r--routes/swaps.js799
-rw-r--r--yarn.lock309
5 files changed, 789 insertions, 323 deletions
diff --git a/index.js b/index.js
index 526d7383..103dbdbe 100644
--- a/index.js
+++ b/index.js
@@ -59,6 +59,7 @@ if (config.lnurl) {
}
app.use((err, req, res, next) => {
+ throw err;
const details = {
path: req.path,
body: req.body,
diff --git a/package.json b/package.json
index 0ffa6c27..c9802121 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
"random-words": "^1.1.1",
"request": "~2.88.0",
"sequelize": "^5.21.3",
+ "tdex-sdk": "^0.1.0",
"text-to-image": "^2.3.0",
"uuid": "^3.3.2",
"web-push": "^3.4.4",
diff --git a/routes/assets.js b/routes/assets.js
index 35177d6c..66a4526c 100644
--- a/routes/assets.js
+++ b/routes/assets.js
@@ -2,6 +2,7 @@ const axios = require("axios");
const crypto = require("crypto");
app.get("/assets", ah(async (req, res) => {
+ l.info("hello");
try {
const { data: assets } = await axios.get(
"https://assets.blockstream.info/"
@@ -69,7 +70,6 @@ app.post("/assets", auth, ah(async (req, res) => {
params.asset_amount = asset_amount / (SATS / 10 ** precision);
- l.info("asset_amount", params.asset_amount);
if (token_amount) {
params.token_amount = token_amount;
params.token_address = token_address;
diff --git a/routes/swaps.js b/routes/swaps.js
index 71c35733..9632d321 100644
--- a/routes/swaps.js
+++ b/routes/swaps.js
@@ -5,15 +5,31 @@ const fs = require("fs");
const { spawn } = require("child_process");
const leveldb = level("leveldb");
const getAccount = require("../lib/account");
+const { Swap, WatchOnlyWallet, fetchUtxos, networks } = require("tdex-sdk");
+const liquid = require("liquidjs-lib");
+const network = prod ? networks["liquid"] : networks["regtest"];
const assets = {
b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23: "bitcoin",
- "4eebe36eb0819e6daa5dd3c97733251ff4eb728c810d949365d6dacaad5ef6e8": "tether",
+ "4eebe36eb0819e6daa5dd3c97733251ff4eb728c810d949365d6dacaad5ef6e8": "tether"
};
-const swapsdir = 'swaps/';
-if (!fs.existsSync(swapsdir)){
- fs.mkdirSync(swapsdir);
+const swapsdir = "swaps/";
+if (!fs.existsSync(swapsdir)) {
+ fs.mkdirSync(swapsdir);
+}
+
+function writeBinary(path, data) {
+ return new Promise((resolve, reject) => {
+ try {
+ const stream = fs.createWriteStream(path);
+ stream.write(data);
+ stream.end();
+ resolve();
+ } catch (err) {
+ reject(err);
+ }
+ });
}
const timeout = 20000;
@@ -37,15 +53,15 @@ const createProposal = (a1, v1, a2, v2) =>
);
const proc = cli("propose", a1, v1, a2, v2);
- proc.stdout.on("data", (data) => {
+ proc.stdout.on("data", data => {
resolve(data.toString());
});
- proc.stderr.on("error", (err) => {
+ proc.stderr.on("error", err => {
l.error("proposal error", err.toString());
reject(err.toString());
});
-
+
proc.on("close", (code, signal) => {
let msg = (code && code.toString()) || (signal && signal.toString());
reject(new Error(`Liquid swap tool process closed unexpectedly: ${msg}`));
@@ -56,18 +72,21 @@ const createProposal = (a1, v1, a2, v2) =>
reject(new Error(`Liquid swap tool process exited unexpectedly: ${msg}`));
});
- setTimeout(() => reject(new Error("Liquid swap tool timed out"), proc), timeout);
+ setTimeout(
+ () => reject(new Error("Liquid swap tool timed out"), proc),
+ timeout
+ );
});
-const getInfo = (filename) =>
+const getInfo = filename =>
new Promise((resolve, reject) => {
const proc = cli("info", swapsdir + filename);
- proc.stdout.on("data", (data) => {
+ proc.stdout.on("data", data => {
resolve(data.toString());
});
- proc.stderr.on("data", (err) => {
+ proc.stderr.on("data", err => {
l.error("info error", err.toString());
reject(err.toString());
});
@@ -82,324 +101,466 @@ const getInfo = (filename) =>
reject(new Error(`Liquid swap tool process exited unexpectedly: ${msg}`));
});
- setTimeout(() => reject(new Error("Liquid swap tool timed out"), proc), timeout);
- });
-
-app.delete("/proposal/:id", auth, ah(async (req, res) => {
- const { id } = req.params;
- await db.Proposal.destroy({
- where: {
- id,
- user_id: req.user.id,
- },
+ setTimeout(
+ () => reject(new Error("Liquid swap tool timed out"), proc),
+ timeout
+ );
});
- res.end();
-}));
-
-app.get("/proposal", auth, ah(async (req, res) => {
- try {
- const { user } = req;
- const { a1, v1, a2, v2 } = req.query;
- const b = await lq.getBalance();
- Object.keys(b).map((asset) => {
- assets[asset] = asset;
- });
- assets["ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"] = "tether";
- assets["6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d"] = "bitcoin";
- assets["a0c358a0f6947864af3a06f3f6a2aeb304df7fd95c922f2f22d7412399ce7691"] = "adamcoin";
-
- if (!assets[a1]) throw new Error("unsupported asset");
- if (v1 > b[assets[a1]]) throw new Error("insufficient server funds");
- const account = await db.Account.findOne({
+app.delete(
+ "/proposal/:id",
+ auth,
+ ah(async (req, res) => {
+ const { id } = req.params;
+ await db.Proposal.destroy({
where: {
- user_id: user.id,
- asset: a1,
- },
+ id,
+ user_id: req.user.id
+ }
});
- if (v1 > account.balance) throw new Error("insufficient funds");
+ res.end();
+ })
+);
- l.info(
- `proposal requested to swap ${v1} ${assets[a1]} for ${v2} ${assets[a2]}`
- );
+app.get(
+ "/proposal",
+ auth,
+ ah(async (req, res) => {
+ try {
+ const { user } = req;
+ const { a1, v1, a2, v2 } = req.query;
+ const b = await lq.getBalance();
- let text = await createProposal(a1, v1, a2, v2);
- text = text.replace(/\s+/g, "").trim();
+ Object.keys(b).map(asset => {
+ assets[asset] = asset;
+ });
+ assets[
+ "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
+ ] = "tether";
+ assets[config.liquid.btcasset] = "bitcoin";
+ assets[
+ "a0c358a0f6947864af3a06f3f6a2aeb304df7fd95c922f2f22d7412399ce7691"
+ ] = "adamcoin";
- const proposal = await db.Proposal.create({
- a1,
- a2,
- v1: Math.round(v1 * SATS),
- v2: Math.round(v2 * SATS),
- user_id: user.id,
- text,
- });
+ l.info("a1", a1, assets);
+ if (!assets[a1]) throw new Error("unsupported asset");
+ if (v1 > b[assets[a1]]) throw new Error("insufficient server funds");
+ const account = await db.Account.findOne({
+ where: {
+ user_id: user.id,
+ asset: a1
+ }
+ });
+ if (v1 > account.balance) throw new Error("insufficient funds");
- res.send({ proposal });
- } catch (e) {
- l.error(e.message);
- res.status(500).send({ error: e.message });
- }
-}));
+ l.info(
+ `proposal requested to swap ${v1} ${assets[a1]} for ${v2} ${assets[a2]}`
+ );
-app.post("/accept", optionalAuth, ah(async (req, res) => {
- try {
- const { id, text } = req.body;
+ /*
+ let text = await createProposal(a1, v1, a2, v2);
+ text = text.replace(/\s+/g, "").trim();
+ */
- const proposal = await db.Proposal.findOne({
- where: {
- id,
- accepted: false,
- },
- include: {
- model: db.User,
- as: "user",
- },
- });
+ const woWallet = new WatchOnlyWallet({
+ address: (await lq.getAddressInfo(await lq.getNewAddress("", "bech32")))
+ .unconfidential,
+ network
+ });
- if (!proposal) throw new Error("Proposal not found");
+ let utxos = (
+ await lq.listUnspent(0, 9999999, [], false, { asset: a1 })
+ ).map(({ txid, vout, amount, asset }) => ({
+ txid,
+ vout,
+ value: Math.round(amount * SATS),
+ asset
+ }));
- const filename = `proposal-${id}.txt`;
+ const emptyPsbt = WatchOnlyWallet.createTx();
+ let psbtBase64 = woWallet.updateTx(
+ emptyPsbt,
+ utxos,
+ Math.round(v1 * SATS),
+ Math.round(v2 * SATS),
+ a1,
+ a2
+ );
- fs.writeFileSync(swapsdir + filename, proposal.text);
- let info = JSON.parse(await getInfo(filename));
+ let { Psbt } = liquid;
+ let psbtObj = Psbt.fromBase64(psbtBase64);
+ console.log(psbtBase64);
+ console.log("data", psbtObj.data);
+ psbtObj.data.outputs.map(o => {
+ console.log("output", o);
+ });
- const { user } = req;
+ const swap = new Swap();
+ const text = swap.request({
+ psbtBase64,
+ amountToBeSent: Math.round(v1 * SATS),
+ amountToReceive: Math.round(v2 * SATS),
+ assetToBeSent: a1,
+ assetToReceive: a2
+ });
- if (user) {
- let [fee, rate, asset] = parse(info);
- const leg1 = info.legs.find((leg) => !leg.incoming && leg.funded);
- const leg2 = info.legs.find((leg) => leg.incoming && !leg.funded);
- await db.transaction(async (transaction) => {
- const l1a1 = await getAccount(leg1.asset, user);
- const l1a2 = await getAccount(leg1.asset, proposal.user);
+ let filename = swapsdir + "swap_request.bin";
+ fs.writeFileSync(filename, text);
- let amount = Math.round(leg1.amount * SATS);
- if (amount > l1a2.balance)
- throw new Error(`Proposer has insufficient funds: ${amount}, ${l1a2.balance}`);
+ const proposal = await db.Proposal.create({
+ a1,
+ a2,
+ v1: Math.round(v1 * SATS),
+ v2: Math.round(v2 * SATS),
+ user_id: user.id,
+ text: text.toString()
+ });
- l1a1.balance += amount;
- l1a2.balance -= amount;
+ let swapRequest,
+ serializedSwapRequest,
+ walletInstance,
+ swapAccept,
+ swapAcceptFile;
- let l1a1p = await db.Payment.create({
- hash: "Internal Transfer",
- amount,
- account_id: l1a1.id,
- memo: "Atomic Swap",
- user_id: user.id,
- currency: user.currency,
- rate,
- confirmed: true,
- received: true,
- network: "COINOS",
- });
+ serializedSwapRequest = await fs.readFileSync(filename);
+ const json = Swap.parse({
+ message: serializedSwapRequest,
+ type: "SwapRequest"
+ });
+ swapRequest = JSON.parse(json);
+ console.log(
+ `SwapRequest message: ${JSON.stringify(swapRequest, undefined, 2)}`
+ );
- let l1a2p = await db.Payment.create({
- hash: "Internal Transfer",
- amount: -amount,
- account_id: l1a2.id,
- memo: "Atomic Swap",
- user_id: proposal.user_id,
- currency: proposal.user.currency,
- rate,
- confirmed: true,
- received: false,
- network: "COINOS",
- });
+ const toWallet = new WatchOnlyWallet({
+ address: (await lq.getAddressInfo(await lq.getNewAddress("", "bech32")))
+ .unconfidential,
+ network
+ });
- const l2a1 = await getAccount(leg2.asset, user);
- const l2a2 = await getAccount(leg2.asset, proposal.user);
+ utxos = (await lq.listUnspent(0, 9999999, [], false, { asset: a2 })).map(
+ ({ txid, vout, amount, asset }) => ({
+ txid,
+ vout,
+ value: Math.round(amount * SATS),
+ asset
+ })
+ );
- amount = Math.round(leg2.amount * SATS);
- if (amount > l2a1.balance) throw new Error("Insufficient funds");
+ psbtBase64 = toWallet.updateTx(
+ swapRequest.transaction,
+ utxos,
+ Math.round(v2 * SATS),
+ Math.round(v1 * SATS),
+ a2,
+ a1
+ );
- l2a1.balance -= amount;
- l2a2.balance += amount;
+ const { btcasset: btc } = config.liquid;
- let l2a1p = await db.Payment.create({
- hash: "Internal Transfer",
- amount: -amount,
- account_id: l2a1.id,
- memo: "Atomic Swap",
- user_id: user.id,
- currency: user.currency,
- rate,
- confirmed: true,
- received: false,
- network: "COINOS",
- });
+ psbtObj = Psbt.fromBase64(swapRequest.transaction);
+ console.log("data", psbtObj.data);
+ psbtObj.data.outputs.map(o => {
+ console.log("output", o);
+ });
+ psbtObj.addOutput({
+ asset: btc,
+ script: Buffer.alloc(0),
+ value: 1000,
+ nonce: Buffer.alloc(1, 0)
+ });
- let l2a2p = await db.Payment.create({
- hash: "Internal Transfer",
- amount,
- account_id: l2a2.id,
- memo: "Atomic Swap",
- user_id: proposal.user_id,
- currency: proposal.user.currency,
- rate,
- confirmed: true,
- received: true,
- network: "COINOS",
- });
+ let { psbt } = await lq.walletSignPsbt(psbtObj.toBase64());
+ let tx = await lq.finalizePsbt(psbt);
+ console.log(tx);
+ await lq.sendRawTransaction(tx.hex);
- await l1a1.save({ transaction });
- await l1a2.save({ transaction });
- await l2a1.save({ transaction });
- await l2a2.save({ transaction });
+ // toWallet.sign(psbtBase64);
- proposal.accepted = true;
- await proposal.save({ transaction });
+ throw new Error("boo");
- l1a1p = l1a1p.get({ plain: true });
- l1a1p.account = l1a1.get({ plain: true });
- l1a2p = l1a2p.get({ plain: true });
- l1a2p.account = l1a2.get({ plain: true });
- l2a1p = l2a1p.get({ plain: true });
- l2a1p.account = l2a1.get({ plain: true });
- l2a2p = l2a2p.get({ plain: true });
- l2a2p.account = l2a2.get({ plain: true });
+ res.send({ proposal });
+ } catch (e) {
+ l.error(e.message);
+ throw e;
+ res.status(500).send({ error: e.message });
+ }
+ })
+);
+
+app.post(
+ "/accept",
+ optionalAuth,
+ ah(async (req, res) => {
+ try {
+ const { id, text } = req.body;
- emit(user.username, "account", l1a1);
- emit(user.username, "account", l2a1);
- emit(proposal.user.username, "account", l1a2);
- emit(proposal.user.username, "account", l2a2);
- emit(user.username, "payment", l1a1p);
- emit(user.username, "payment", l2a1p);
- emit(proposal.user.username, "payment", l1a2p);
- emit(proposal.user.username, "payment", l2a2p);
- emit(user.username, "proposal", proposal);
- emit(proposal.user.username, "proposal", proposal);
+ const proposal = await db.Proposal.findOne({
+ where: {
+ id,
+ accepted: false
+ },
+ include: {
+ model: db.User,
+ as: "user"
+ }
});
- } else if (text) {
- const filename = `acceptance-${id}.txt`;
- fs.writeFileSync(swapsdir + filename, text);
- info = JSON.parse(await getInfo(filename));
- let [fee, rate, asset] = parse(info);
- let { tx, u_address_p, u_address_r } = JSON.parse(
- Buffer.from(text, "base64").toString()
- );
- const sha256 = crypto.createHash("sha256");
- sha256.update(tx);
- const hash = sha256.digest("hex");
+ if (!proposal) throw new Error("Proposal not found");
- const leg1 = info.legs.find((leg) => !leg.incoming);
- const leg2 = info.legs.find((leg) => leg.incoming);
+ const filename = `proposal-${id}.txt`;
- const l1a2 = await getAccount(leg1.asset, proposal.user);
- const btc = await getAccount(config.liquid.btcasset, proposal.user);
+ fs.writeFileSync(swapsdir + filename, proposal.text);
+ let info = JSON.parse(await getInfo(filename));
- await db.transaction(async (transaction) => {
+ const { user } = req;
- let amount = Math.round(leg1.amount * SATS);
- fee = Math.round(fee * SATS);
+ if (user) {
+ let [fee, rate, asset] = parse(info);
+ const leg1 = info.legs.find(leg => !leg.incoming && leg.funded);
+ const leg2 = info.legs.find(leg => leg.incoming && !leg.funded);
+ await db.transaction(async transaction => {
+ const l1a1 = await getAccount(leg1.asset, user);
+ const l1a2 = await getAccount(leg1.asset, proposal.user);
- if (amount > l1a2.balance)
- throw new Error(`Proposer has insufficient funds: ${amount}, ${l1a2.balance}`);
+ let amount = Math.round(leg1.amount * SATS);
+ if (amount > l1a2.balance)
+ throw new Error(
+ `Proposer has insufficient funds: ${amount}, ${l1a2.balance}`
+ );
- if (fee > btc.balance)
- throw new Error(`Proposer has insufficient funds for fee: ${fee}, ${btc.balance}`);
+ l1a1.balance += amount;
+ l1a2.balance -= amount;
- l1a2.balance -= amount;
- btc.balance -= fee;
+ let l1a1p = await db.Payment.create({
+ hash: "Internal Transfer",
+ amount,
+ account_id: l1a1.id,
+ memo: "Atomic Swap",
+ user_id: user.id,
+ currency: user.currency,
+ rate,
+ confirmed: true,
+ received: true,
+ network: "COINOS"
+ });
- let payment = await db.Payment.create({
- hash,
- amount: -amount,
- account_id: l1a2.id,
- fee,
- memo: "Atomic Swap",
- user_id: proposal.user_id,
- currency: proposal.user.currency,
- rate,
- address: u_address_r,
- confirmed: true,
- received: false,
- network: "LBTC",
- });
+ let l1a2p = await db.Payment.create({
+ hash: "Internal Transfer",
+ amount: -amount,
+ account_id: l1a2.id,
+ memo: "Atomic Swap",
+ user_id: proposal.user_id,
+ currency: proposal.user.currency,
+ rate,
+ confirmed: true,
+ received: false,
+ network: "COINOS"
+ });
- amount = Math.round(leg2.amount * SATS);
+ const l2a1 = await getAccount(leg2.asset, user);
+ const l2a2 = await getAccount(leg2.asset, proposal.user);
- await db.Invoice.create({
- user_id: proposal.user_id,
- text: u_address_p,
- currency: proposal.user.currency,
- memo: "Atomic Swap",
- rate,
- amount,
- tip: 0,
- network: "LBTC",
- });
+ amount = Math.round(leg2.amount * SATS);
+ if (amount > l2a1.balance) throw new Error("Insufficient funds");
- addresses[u_address_p] = proposal.user.username;
+ l2a1.balance -= amount;
+ l2a2.balance += amount;
- await finalize(filename);
- await l1a2.save({ transaction });
- await btc.save({ transaction });
+ let l2a1p = await db.Payment.create({
+ hash: "Internal Transfer",
+ amount: -amount,
+ account_id: l2a1.id,
+ memo: "Atomic Swap",
+ user_id: user.id,
+ currency: user.currency,
+ rate,
+ confirmed: true,
+ received: false,
+ network: "COINOS"
+ });
- proposal.accepted = true;
- await proposal.save({ transaction });
+ let l2a2p = await db.Payment.create({
+ hash: "Internal Transfer",
+ amount,
+ account_id: l2a2.id,
+ memo: "Atomic Swap",
+ user_id: proposal.user_id,
+ currency: proposal.user.currency,
+ rate,
+ confirmed: true,
+ received: true,
+ network: "COINOS"
+ });
- payment = payment.get({ plain: true });
- payment.account = l1a2.get({ plain: true });
+ await l1a1.save({ transaction });
+ await l1a2.save({ transaction });
+ await l2a1.save({ transaction });
+ await l2a2.save({ transaction });
- emit(proposal.user.username, "payment", payment);
- emit(proposal.user.username, "account", l1a2);
- emit(proposal.user.username, "account", btc);
- emit(proposal.user.username, "proposal", proposal);
- });
- } else {
- throw new Error("no acceptance provided");
- }
+ proposal.accepted = true;
+ await proposal.save({ transaction });
- res.send(info);
- } catch (e) {
- l.error(e.message);
- res.status(500).send(e.message);
- }
-}));
+ l1a1p = l1a1p.get({ plain: true });
+ l1a1p.account = l1a1.get({ plain: true });
+ l1a2p = l1a2p.get({ plain: true });
+ l1a2p.account = l1a2.get({ plain: true });
+ l2a1p = l2a1p.get({ plain: true });
+ l2a1p.account = l2a1.get({ plain: true });
+ l2a2p = l2a2p.get({ plain: true });
+ l2a2p.account = l2a2.get({ plain: true });
-app.post("/acceptance", ah(async (req, res) => {
- const { acceptance: text } = req.body;
- l.info("acceptance received");
+ emit(user.username, "account", l1a1);
+ emit(user.username, "account", l2a1);
+ emit(proposal.user.username, "account", l1a2);
+ emit(proposal.user.username, "account", l2a2);
+ emit(user.username, "payment", l1a1p);
+ emit(user.username, "payment", l2a1p);
+ emit(proposal.user.username, "payment", l1a2p);
+ emit(proposal.user.username, "payment", l2a2p);
+ emit(user.username, "proposal", proposal);
+ emit(proposal.user.username, "proposal", proposal);
+ });
+ } else if (text) {
+ const filename = `acceptance-${id}.txt`;
+ fs.writeFileSync(swapsdir + filename, text);
- fs.writeFile(swapsdir + "accepted.txt", text, async (err) => {
- if (err) {
- return res.status(500).send(err);
- }
+ info = JSON.parse(await getInfo(filename));
+ let [fee, rate, asset] = parse(info);
+ let { tx, u_address_p, u_address_r } = JSON.parse(
+ Buffer.from(text, "base64").toString()
+ );
+ const sha256 = crypto.createHash("sha256");
+ sha256.update(tx);
+ const hash = sha256.digest("hex");
- try {
- let info = JSON.parse(
- await new Promise((resolve, reject) => {
- const proc = cli("info", swapsdir + "accepted.txt");
+ const leg1 = info.legs.find(leg => !leg.incoming);
+ const leg2 = info.legs.find(leg => leg.incoming);
+
+ const l1a2 = await getAccount(leg1.asset, proposal.user);
+ const btc = await getAccount(config.liquid.btcasset, proposal.user);
+
+ await db.transaction(async transaction => {
+ let amount = Math.round(leg1.amount * SATS);
+ fee = Math.round(fee * SATS);
+
+ if (amount > l1a2.balance)
+ throw new Error(
+ `Proposer has insufficient funds: ${amount}, ${l1a2.balance}`
+ );
+
+ if (fee > btc.balance)
+ throw new Error(
+ `Proposer has insufficient funds for fee: ${fee}, ${btc.balance}`
+ );
+
+ l1a2.balance -= amount;
+ btc.balance -= fee;
- proc.stdout.on("data", (data) => {
- resolve(data.toString());
+ let payment = await db.Payment.create({
+ hash,
+ amount: -amount,
+ account_id: l1a2.id,
+ fee,
+ memo: "Atomic Swap",
+ user_id: proposal.user_id,
+ currency: proposal.user.currency,
+ rate,
+ address: u_address_r,
+ confirmed: true,
+ received: false,
+ network: "LBTC"
});
- proc.stderr.on("data", (err) => {
- reject(err.toString());
+ amount = Math.round(leg2.amount * SATS);
+
+ await db.Invoice.create({
+ user_id: proposal.user_id,
+ text: u_address_p,
+ currency: proposal.user.currency,
+ memo: "Atomic Swap",
+ rate,
+ amount,
+ tip: 0,
+ network: "LBTC"
});
- setTimeout(() => reject(new Error("Liquid swap tool timed out"), proc), timeout);
- })
- );
+ addresses[u_address_p] = proposal.user.username;
+
+ await finalize(filename);
+ await l1a2.save({ transaction });
+ await btc.save({ transaction });
- const time = Math.floor(new Date()).toString();
- const [fee, rate, asset] = parse(info);
- if (!asset) throw new Error("unsupported asset");
- l.info("accepted", info, rate, asset);
+ proposal.accepted = true;
+ await proposal.save({ transaction });
- leveldb.put(time, JSON.stringify({ text, info, rate, asset }));
- l.info({ text, info, rate, asset });
+ payment = payment.get({ plain: true });
+ payment.account = l1a2.get({ plain: true });
+
+ emit(proposal.user.username, "payment", payment);
+ emit(proposal.user.username, "account", l1a2);
+ emit(proposal.user.username, "account", btc);
+ emit(proposal.user.username, "proposal", proposal);
+ });
+ } else {
+ throw new Error("no acceptance provided");
+ }
- res.send({ info, rate });
+ res.send(info);
} catch (e) {
- l.error(e);
- res.status(500).send({ error: e });
+ l.error(e.message);
+ res.status(500).send(e.message);
}
- });
-}));
+ })
+);
+
+app.post(
+ "/acceptance",
+ ah(async (req, res) => {
+ const { acceptance: text } = req.body;
+ l.info("acceptance received");
+
+ fs.writeFile(swapsdir + "accepted.txt", text, async err => {
+ if (err) {
+ return res.status(500).send(err);
+ }
+
+ try {
+ let info = JSON.parse(
+ await new Promise((resolve, reject) => {
+ const proc = cli("info", swapsdir + "accepted.txt");
+
+ proc.stdout.on("data", data => {
+ resolve(data.toString());
+ });
+
+ proc.stderr.on("data", err => {
+ reject(err.toString());
+ });
+
+ setTimeout(
+ () => reject(new Error("Liquid swap tool timed out"), proc),
+ timeout
+ );
+ })
+ );
+
+ const time = Math.floor(new Date()).toString();
+ const [fee, rate, asset] = parse(info);
+ if (!asset) throw new Error("unsupported asset");
+ l.info("accepted", info, rate, asset);
+
+ leveldb.put(time, JSON.stringify({ text, info, rate, asset }));
+ l.info({ text, info, rate, asset });
+
+ res.send({ info, rate });
+ } catch (e) {
+ l.error(e);
+ res.status(500).send({ error: e });
+ }
+ });
+ })
+);
checkQueue = async () => {
const ws = app.get("ws");
@@ -407,32 +568,32 @@ checkQueue = async () => {
leveldb
.createReadStream()
- .on("data", async function (data) {
+ .on("data", async function(data) {
txs.push({ ...JSON.parse(data.value), key: data.key });
})
- .on("end", async function (data) {
+ .on("end", async function(data) {
const rate = (a, b) => a.rate - b.rate;
const time = (a, b) => b.time - a.time;
- const pending = txs.filter((tx) => !tx.id);
- const completed = txs.filter((tx) => tx.id).sort(time);
+ const pending = txs.filter(tx => !tx.id);
+ const completed = txs.filter(tx => tx.id).sort(time);
const bitcoin = pending
- .filter((tx) => tx.asset === "bitcoin")
+ .filter(tx => tx.asset === "bitcoin")
.sort(rate)
.reverse();
const tether = pending
- .filter((tx) => tx.asset === "tether")
+ .filter(tx => tx.asset === "tether")
.sort(rate)
.reverse();
- const strip = (a) =>
+ const strip = a =>
a.map(({ id, key, info, rate, time }) => ({
id,
key,
info,
rate,
- time,
+ time
}));
ws &&
@@ -440,7 +601,7 @@ checkQueue = async () => {
JSON.stringify({
completed: strip(completed.slice(0, 3)),
bitcoin: strip(bitcoin.slice(0, 3)),
- tether: strip(tether.slice(0, 3)),
+ tether: strip(tether.slice(0, 3))
})
);
@@ -469,12 +630,12 @@ checkQueue = async () => {
});
};
-const parse = (info) => {
+const parse = info => {
const fee = info.legs[0].fee;
return [
fee,
(info.legs[1].amount / (info.legs[0].amount + fee)).toFixed(8),
- assets[info.legs[0].asset],
+ assets[info.legs[0].asset]
];
};
@@ -484,11 +645,11 @@ const finalize = (filename = "finalized.txt", text) => {
return new Promise((resolve, reject) => {
const proc = cli("finalize", swapsdir + filename, "-s");
- proc.stdout.on("data", (data) => {
+ proc.stdout.on("data", data => {
resolve(data.toString());
});
- proc.stderr.on("data", (err) => {
+ proc.stderr.on("data", err => {
reject(new Error(err.toString()));
});
@@ -502,39 +663,49 @@ const finalize = (filename = "finalized.txt", text) => {
reject(new Error(`Liquid swap tool process exited unexpectedly: ${msg}`));
});
- setTimeout(() => reject(new Error("Liquid swap tool timed out"), proc), timeout);
+ setTimeout(
+ () => reject(new Error("Liquid swap tool timed out"), proc),
+ timeout
+ );
});
};
-app.get("/proposals", optionalAuth, ah(async (req, res) => {
- try {
- if (req.user) {
- res.send(await db.Proposal.findAll());
- } else {
- res.send(
- await db.Proposal.findAll({
- attributes: { exclude: ["user_id"] },
- where: {
- accepted: false,
- },
- })
- );
+app.get(
+ "/proposals",
+ optionalAuth,
+ ah(async (req, res) => {
+ try {
+ if (req.user) {
+ res.send(await db.Proposal.findAll());
+ } else {
+ res.send(
+ await db.Proposal.findAll({
+ attributes: { exclude: ["user_id"] },
+ where: {
+ accepted: false
+ }
+ })
+ );
+ }
+ } catch (e) {
+ res.status(500).send(e.message);
}
- } catch (e) {
- res.status(500).send(e.message);
- }
-}));
-
-app.post("/publish", auth, ah(async (req, res) => {
- try {
- const { id } = req.body;
- await db.Proposal.update(
- { public: true },
- { where: { id, user_id: req.user.id } }
- );
- res.end();
- } catch (e) {
- res.status(500).send(e.message);
- }
-}));
+ })
+);
+app.post(
+ "/publish",
+ auth,
+ ah(async (req, res) => {
+ try {
+ const { id } = req.body;
+ await db.Proposal.update(
+ { public: true },
+ { where: { id, user_id: req.user.id } }
+ );
+ res.end();
+ } catch (e) {
+ res.status(500).send(e.message);
+ }
+ })
+);
diff --git a/yarn.lock b/yarn.lock
index b935cb10..43c72afb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,16 @@
# yarn lockfile v1
+"@grpc/grpc-js@^1.0.4":
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.1.5.tgz#2d0b261cd54a529f6b78ac0de9d6fd91a9a3129c"
+ integrity sha512-2huf5z85TdZI4nLmJQ9Zdfd+6vmIyBDs7B4L71bTaHKA9pRsGKAH24XaktMk/xneKJIqAgeIZtg1cyivVZtvrg==
+ dependencies:
+ "@grpc/proto-loader" "^0.6.0-pre14"
+ "@types/node" "^12.12.47"
+ google-auth-library "^6.0.0"
+ semver "^6.2.0"
+
"@grpc/proto-loader@^0.5.3":
version "0.5.5"
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.5.5.tgz#6725e7a1827bdf8e92e29fbf4e9ef0203c0906a9"
@@ -10,6 +20,17 @@
lodash.camelcase "^4.3.0"
protobufjs "^6.8.6"
+"@grpc/proto-loader@^0.6.0-pre14":
+ version "0.6.0-pre9"
+ resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.0-pre9.tgz#0c6fe42f6c5ef9ce1b3cef7be64d5b09d6fe4d6d"
+ integrity sha512-oM+LjpEjNzW5pNJjt4/hq1HYayNeQT+eGrOPABJnYHv7TyNPDNzkQ76rDYZF86X5swJOa4EujEMzQ9iiTdPgww==
+ dependencies:
+ "@types/long" "^4.0.1"
+ lodash.camelcase "^4.3.0"
+ long "^4.0.0"
+ protobufjs "^6.9.0"
+ yargs "^15.3.1"
+
"@hapi/bourne@^1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a"
@@ -236,6 +257,11 @@
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad"
integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==
+"@types/google-protobuf@^3.7.2":
+ version "3.7.3"
+ resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.7.3.tgz#429512e541bbd777f2c867692e6335ee08d1f6d4"
+ integrity sha512-FRwj40euE2bYkG+0X5w2nEA8yAzgJRcEa7RBd0Gsdkb9/tPM2pctVVAvnOUTbcXo2VmIHPo0Ae94Gl9vRHfKzg==
+
"@types/long@*", "@types/long@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
@@ -256,6 +282,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a"
integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==
+"@types/node@^12.12.47":
+ version "12.12.54"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.54.tgz#a4b58d8df3a4677b6c08bfbc94b7ad7a7a5f82d1"
+ integrity sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==
+
"@types/node@^13.7.0", "@types/node@^13.9.2", "@types/node@^13.9.8":
version "13.13.15"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.15.tgz#fe1cc3aa465a3ea6858b793fd380b66c39919766"
@@ -273,6 +304,13 @@ abbrev@1:
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+abort-controller@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
+ integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
+ dependencies:
+ event-target-shim "^5.0.0"
+
abstract-leveldown@^6.2.1:
version "6.3.0"
resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a"
@@ -390,7 +428,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"
-ansi-styles@^4.1.0:
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
@@ -481,6 +519,11 @@ array-unique@^0.3.2:
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+arrify@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
+ integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
+
ascli@~1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ascli/-/ascli-1.0.1.tgz#bcfa5974a62f18e81cabaeb49732ab4a88f906bc"
@@ -595,7 +638,7 @@ base-x@^3.0.2:
dependencies:
safe-buffer "^5.0.1"
-base64-js@^1.0.2:
+base64-js@^1.0.2, base64-js@^1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
@@ -643,7 +686,7 @@ bigi@^1.1.0, bigi@^1.4.0:
resolved "https://registry.yarnpkg.com/bigi/-/bigi-1.4.2.tgz#9c665a95f88b8b08fc05cfd731f561859d725825"
integrity sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU=
[email protected], bignumber.js@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075"
integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==
@@ -670,6 +713,10 @@ bip174@^1.0.1:
resolved "https://registry.yarnpkg.com/bip174/-/bip174-1.0.1.tgz#858a587f9529e22ee9b0572fd884e5783696824d"
integrity sha512-Mq2aFs1TdMfxBpYPg7uzjhsiXbAtoVq44TNjEWtvuZBiBgc3m7+n55orYMtTAxdg7jWbL4DtH0MKocJER4xERQ==
+"bip174@github:vulpemventures/bip174":
+ version "1.0.1"
+ resolved "https://codeload.github.com/vulpemventures/bip174/tar.gz/ef2559cf71f925a1adef9a83adb6b072128e83f2"
+
"bip174@https://github.com/asoltys/bip174":
version "1.0.1"
resolved "https://github.com/asoltys/bip174#498203635fa6202e3a32cd1a8e6e4dabc23dd614"
@@ -772,6 +819,11 @@ bl@^4.0.1:
inherits "^2.0.4"
readable-stream "^3.4.0"
+"blech32@github:vulpemventures/blech32":
+ version "1.0.0"
+ uid b42822d0496a27ed5a313395517e9029bcfccf2e
+ resolved "https://codeload.github.com/vulpemventures/blech32/tar.gz/b42822d0496a27ed5a313395517e9029bcfccf2e"
+
"blech32@https://github.com/vulpemventures/blech32":
version "1.0.0"
resolved "https://github.com/vulpemventures/blech32#b42822d0496a27ed5a313395517e9029bcfccf2e"
@@ -1148,6 +1200,15 @@ cliui@^5.0.0:
strip-ansi "^5.2.0"
wrap-ansi "^5.1.0"
+cliui@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
+ integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^6.2.0"
+
clone-response@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
@@ -1629,7 +1690,7 @@ ecc-jsbn@~0.1.1:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
[email protected], ecdsa-sig-formatter@^1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
@@ -1847,6 +1908,11 @@ etag@~1.8.1:
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
+event-target-shim@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
+ integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
+
[email protected], eventemitter2@^5.0.1, eventemitter2@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-5.0.1.tgz#6197a095d5fb6b57e8942f6fd7eaad63a09c9452"
@@ -1970,7 +2036,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
-extend@^3.0.0, extend@~3.0.2:
+extend@^3.0.0, extend@^3.0.2, extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
@@ -2024,6 +2090,11 @@ fast-safe-stringify@^2.0.7:
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==
+fast-text-encoding@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz#ec02ac8e01ab8a319af182dae2681213cfe9ce53"
+ integrity sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==
+
[email protected], fclone@~1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/fclone/-/fclone-1.0.11.tgz#10e85da38bfea7fc599341c296ee1d77266ee640"
@@ -2071,6 +2142,14 @@ [email protected], find-up@^3.0.0:
dependencies:
locate-path "^3.0.0"
+find-up@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+ integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+ dependencies:
+ locate-path "^5.0.0"
+ path-exists "^4.0.0"
+
findup-sync@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1"
@@ -2222,6 +2301,25 @@ gauge@~2.7.3:
strip-ansi "^3.0.1"
wide-align "^1.1.0"
+gaxios@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-3.1.0.tgz#95f65f5a335f61aff602fe124cfdba8524f765fa"
+ integrity sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==
+ dependencies:
+ abort-controller "^3.0.0"
+ extend "^3.0.2"
+ https-proxy-agent "^5.0.0"
+ is-stream "^2.0.0"
+ node-fetch "^2.3.0"
+
+gcp-metadata@^4.1.0:
+ version "4.1.4"
+ resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-4.1.4.tgz#3adadb9158c716c325849ee893741721a3c09e7e"
+ integrity sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==
+ dependencies:
+ gaxios "^3.0.0"
+ json-bigint "^1.0.0"
+
generate-function@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f"
@@ -2351,6 +2449,33 @@ global-prefix@^1.0.1:
is-windows "^1.0.1"
which "^1.2.14"
+google-auth-library@^6.0.0:
+ version "6.0.6"
+ resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-6.0.6.tgz#5102e5c643baab45b4c16e9752cd56b8861f3a82"
+ integrity sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==
+ dependencies:
+ arrify "^2.0.0"
+ base64-js "^1.3.0"
+ ecdsa-sig-formatter "^1.0.11"
+ fast-text-encoding "^1.0.0"
+ gaxios "^3.0.0"
+ gcp-metadata "^4.1.0"
+ gtoken "^5.0.0"
+ jws "^4.0.0"
+ lru-cache "^6.0.0"
+
+google-p12-pem@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-3.0.2.tgz#12d443994b6f4cd8c9e4ac479f2f18d4694cbdb8"
+ integrity sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==
+ dependencies:
+ node-forge "^0.9.0"
+
+google-protobuf@^3.11.4:
+ version "3.13.0"
+ resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.13.0.tgz#909c5983d75dd6101ed57c79e0528d000cdc3251"
+ integrity sha512-ZIf3qfLFayVrPvAjeKKxO5FRF1/NwRxt6Dko+fWEMuHwHbZx8/fcaAao9b0wCM6kr8qeg2te8XTpyuvKuD9aKw==
+
got@^9.6.0:
version "9.6.0"
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
@@ -2378,6 +2503,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
+grpc-web@~1.2.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/grpc-web/-/grpc-web-1.2.1.tgz#860051d705bf5baa7b81fcbd14030060bf16b7b9"
+ integrity sha512-ibBaJPzfMVuLPgaST9w0kZl60s+SnkPBQp6QKdpEr85tpc1gXW2QDqSne9xiyiym0logDfdUSm4aX5h9YBA2mw==
+
grpc@^1.24.2:
version "1.24.3"
resolved "https://registry.yarnpkg.com/grpc/-/grpc-1.24.3.tgz#92efe28dfc1250dca179b8133e40b4f2341473d9"
@@ -2390,6 +2520,16 @@ grpc@^1.24.2:
node-pre-gyp "^0.15.0"
protobufjs "^5.0.3"
+gtoken@^5.0.0:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-5.0.3.tgz#b76ef8e9a2fed6fef165e47f7d05b60c498e4d05"
+ integrity sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==
+ dependencies:
+ gaxios "^3.0.0"
+ google-p12-pem "^3.0.0"
+ jws "^4.0.0"
+ mime "^2.2.0"
+
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
@@ -2889,6 +3029,11 @@ is-stream@^1.1.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+is-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
+ integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
+
is-symbol@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
@@ -2968,6 +3113,11 @@ [email protected]:
argparse "^1.0.7"
esprima "^4.0.0"
+jsbi@^3.1.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.1.3.tgz#f024b340032f7c7caaa6ca4b32b55e8d33f6e897"
+ integrity sha512-nBJqA0C6Qns+ZxurbEoIR56wyjiUszpNy70FHvxO5ervMoCbZVE3z3kxr5nKGhlxr/9MhKTSUBs7cAwwuf3g9w==
+
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
@@ -2980,6 +3130,13 @@ json-bigint@^0.2.0:
dependencies:
bignumber.js "^4.0.0"
+json-bigint@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1"
+ integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==
+ dependencies:
+ bignumber.js "^9.0.0"
+
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
@@ -3263,6 +3420,29 @@ [email protected]:
varuint-bitcoin "^1.0.4"
wif "^2.0.1"
+liquidjs-lib@provable-things/liquidjs-lib:
+ version "5.1.6"
+ resolved "https://codeload.github.com/provable-things/liquidjs-lib/tar.gz/97673986c4233dee61f98dc59b5256ed2a8f313d"
+ dependencies:
+ axios "^0.19.2"
+ bech32 "^1.1.2"
+ bip174 "github:vulpemventures/bip174"
+ bip32 "^2.0.4"
+ bip66 "^1.1.0"
+ bitcoin-ops "^1.4.0"
+ blech32 "github:vulpemventures/blech32"
+ bs58check "^2.0.0"
+ create-hash "^1.1.0"
+ create-hmac "^1.1.3"
+ merkle-lib "^2.0.10"
+ pushdata-bitcoin "^1.0.1"
+ randombytes "^2.0.1"
+ secp256k1-zkp "github:vulpemventures/secp256k1-zkp"
+ tiny-secp256k1 "^1.1.1"
+ typeforce "^1.11.3"
+ varuint-bitcoin "^1.0.4"
+ wif "^2.0.1"
+
"lnurl@https://github.com/asoltys/lnurl-node":
version "0.7.1"
resolved "https://github.com/asoltys/lnurl-node#e07eb53bb087aba5eba7b7cd82fd5f3cd2d0bd2e"
@@ -3286,6 +3466,13 @@ locate-path@^3.0.0:
p-locate "^3.0.0"
path-exists "^3.0.0"
+locate-path@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+ integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+ dependencies:
+ p-locate "^4.1.0"
+
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
@@ -3383,6 +3570,13 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
+
ltgt@^2.1.2:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5"
@@ -3524,6 +3718,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+mime@^2.2.0:
+ version "2.4.6"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1"
+ integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==
+
mimic-response@^1.0.0, mimic-response@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
@@ -3794,6 +3993,16 @@ [email protected]:
object.getownpropertydescriptors "^2.0.3"
semver "^5.7.0"
+node-fetch@^2.3.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
+ integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
+
+node-forge@^0.9.0:
+ version "0.9.1"
+ resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.1.tgz#775368e6846558ab6676858a4d8c6e8d16c677b5"
+ integrity sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==
+
node-gyp-build@~4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb"
@@ -4075,7 +4284,7 @@ p-cancelable@^1.0.0:
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
-p-limit@^2.0.0:
+p-limit@^2.0.0, p-limit@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
@@ -4089,6 +4298,13 @@ p-locate@^3.0.0:
dependencies:
p-limit "^2.0.0"
+p-locate@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+ integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+ dependencies:
+ p-limit "^2.2.0"
+
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
@@ -4186,6 +4402,11 @@ path-exists@^3.0.0:
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
+path-exists@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@@ -4449,7 +4670,7 @@ protobufjs@^5.0.3:
glob "^7.0.5"
yargs "^3.10.0"
-protobufjs@^6.8.6:
+protobufjs@^6.8.6, protobufjs@^6.9.0:
version "6.10.1"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.10.1.tgz#e6a484dd8f04b29629e9053344e3970cccf13cd2"
integrity sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==
@@ -4896,6 +5117,14 @@ sax@^1.2.4:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
+"secp256k1-zkp@github:vulpemventures/secp256k1-zkp":
+ version "1.0.0"
+ uid "7e0d8aeddda593cf0ed8ad18c0c0607283bd7848"
+ resolved "https://codeload.github.com/vulpemventures/secp256k1-zkp/tar.gz/7e0d8aeddda593cf0ed8ad18c0c0607283bd7848"
+ dependencies:
+ "@types/node" "^13.9.2"
+ long "^4.0.0"
+
"secp256k1-zkp@https://github.com/vulpemventures/secp256k1-zkp":
version "1.0.0"
resolved "https://github.com/vulpemventures/secp256k1-zkp#7e0d8aeddda593cf0ed8ad18c0c0607283bd7848"
@@ -5262,7 +5491,7 @@ string-width@^3.0.0, string-width@^3.1.0:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"
-string-width@^4.0.0, string-width@^4.1.0:
+string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==
@@ -5409,6 +5638,26 @@ tarn@^3.0.0:
resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.0.tgz#a4082405216c0cce182b8b4cb2639c52c1e870d4"
integrity sha512-PKUnlDFODZueoA8owLehl8vLcgtA8u4dRuVbZc92tspDYZixjJL6TqYOmryf/PfP/EBX+2rgNcrj96NO+RPkdQ==
+tdex-protobuf@tdex-network/tdex-protobuf#master:
+ version "1.0.0"
+ resolved "https://codeload.github.com/tdex-network/tdex-protobuf/tar.gz/1d7548f4a8a7db0a1b4c53a9e2e368c5bc79048f"
+ dependencies:
+ grpc-web "~1.2.0"
+
+tdex-sdk@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/tdex-sdk/-/tdex-sdk-0.1.0.tgz#576b93c3e362f80783b4bd30e8a3e6537a405318"
+ integrity sha512-Nour3aMIFoboEKFe/3T5nkcIwNd1hDPguQ3+jrfbh522JuzJ0Qh3m6EDq2VA+PM+UFNeAgrp/0hPVdZxV5zbfA==
+ dependencies:
+ "@grpc/grpc-js" "^1.0.4"
+ "@types/google-protobuf" "^3.7.2"
+ axios "^0.19.2"
+ google-protobuf "^3.11.4"
+ jsbi "^3.1.2"
+ liquidjs-lib provable-things/liquidjs-lib
+ tdex-protobuf tdex-network/tdex-protobuf#master
+ tslib "^2.0.0"
+
term-size@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753"
@@ -5514,6 +5763,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.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e"
+ integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==
+
tsscmp@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"
@@ -5826,6 +6080,15 @@ wrap-ansi@^5.1.0:
string-width "^3.0.0"
strip-ansi "^5.0.0"
+wrap-ansi@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
+ integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
@@ -5893,6 +6156,11 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
version "0.3.0"
resolved "https://registry.yarnpkg.com/yamljs/-/yamljs-0.3.0.tgz#dc060bf267447b39f7304e9b2bfbe8b5a7ddb03b"
@@ -5909,6 +6177,14 @@ [email protected], yargs-parser@^13.1.2:
camelcase "^5.0.0"
decamelize "^1.2.0"
+yargs-parser@^18.1.2:
+ version "18.1.3"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
+ integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
version "1.6.0"
resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f"
@@ -5934,6 +6210,23 @@ [email protected], yargs@^13.3.0:
y18n "^4.0.0"
yargs-parser "^13.1.2"
+yargs@^15.3.1:
+ version "15.4.1"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
+ integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
+ dependencies:
+ cliui "^6.0.0"
+ decamelize "^1.2.0"
+ find-up "^4.1.0"
+ get-caller-file "^2.0.1"
+ require-directory "^2.1.1"
+ require-main-filename "^2.0.0"
+ set-blocking "^2.0.0"
+ string-width "^4.2.0"
+ which-module "^2.0.0"
+ y18n "^4.0.0"
+ yargs-parser "^18.1.2"
+
yargs@^3.10.0:
version "3.32.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995"