diff options
| author | Adam Soltys <[email protected]> | 2021-08-03 01:02:31 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2021-08-03 01:02:31 -0700 |
| commit | 2f52a91c5babde9e374dd9c532448f565bcbfeee (patch) | |
| tree | 6900b8ed5b76cd4f7119aa9a6628ab268430a66f | |
| parent | df86f50b1f08f24574c15eccf3fbe0daf5c42a5e (diff) | |
| parent | 6abfe155c5bb3845f59775b95eeb9d4034aa92b8 (diff) | |
| download | coinos-server-2f52a91c5babde9e374dd9c532448f565bcbfeee.tar.gz coinos-server-2f52a91c5babde9e374dd9c532448f565bcbfeee.zip | |
Merge branch 'taxi' into dev
| -rw-r--r-- | docker-compose.yml | 1 | ||||
| -rwxr-xr-x | mine.sh | 8 | ||||
| -rw-r--r-- | routes/assets.js | 234 | ||||
| -rw-r--r-- | routes/liquid/taxi.js | 85 | ||||
| -rw-r--r-- | routes/payments.js | 1 | ||||
| -rw-r--r-- | sampleconfig/liquid/elements.conf | 2 |
6 files changed, 218 insertions, 113 deletions
diff --git a/docker-compose.yml b/docker-compose.yml index 9e898822..febdba4f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,7 @@ services: container_name: app image: asoltys/coinos-server ports: + - '3118:3118' - '3119:3119' environment: NODE_ENV: development diff --git a/mine.sh b/mine.sh new file mode 100755 index 00000000..0df5b6ba --- /dev/null +++ b/mine.sh @@ -0,0 +1,8 @@ +#!/bin/bash + + +while true +do + docker exec -it liquid elements-cli -datadir=/config generatetoaddress 1 $(docker exec -it liquid elements-cli -datadir=/config getnewaddress) + sleep 8 +done diff --git a/routes/assets.js b/routes/assets.js index 076c7057..3f483a28 100644 --- a/routes/assets.js +++ b/routes/assets.js @@ -1,5 +1,6 @@ const axios = require("axios"); const crypto = require("crypto"); +const fs = require("fs"); let fetchAssets; (fetchAssets = async () => { @@ -7,13 +8,13 @@ let fetchAssets; const { data: assets } = await axios.get( "https://assets.blockstream.info/" ); - var liquid_assets = require('./../assets.json') + var liquid_assets = require("./../assets.json"); app.set("assets", liquid_assets); } catch (e) { - var liquid_assets = require('./../assets.json') + var liquid_assets = require("./../assets.json"); if (liquid_assets) { app.set("assets", liquid_assets); - console.debug('using static assets...' + e.message); + console.debug("using static assets..." + e.message); } else { l.error("error fetching assets", e.message); res.status(500).send("error fetching assets"); @@ -27,7 +28,6 @@ app.get( "/assets", ah(async (req, res) => { if (app.get("assets")) { - const assets = app.get("assets"); const accounts = await db.Account.findAll({ @@ -61,7 +61,7 @@ app.get( res.send(assets); } else { - console.log('error getting blockstream assets'); + console.log("error getting blockstream assets"); res.status(500).send("Problem fetching blockstream asset registry data"); } }) @@ -74,20 +74,30 @@ app.post( try { const sha256 = crypto.createHash("sha256"); const { id: user_id } = req.user; - const token_address = await lq.getNewAddress("", "legacy"); - const asset_address = await lq.getNewAddress("", "legacy"); const blind = false; - const info = await lq.getAddressInfo(asset_address); - const { pubkey: issuer_pubkey } = info; const { + address, domain, name, asset_amount, + filename, token_amount, precision, + pubkey, ticker } = req.body; + + const asset_address = address + ? address + : await lq.getNewAddress("", "legacy"); + + const token_address = + token_amount && (await lq.getNewAddress("", "legacy")); + + const issuer_pubkey = pubkey + ? pubkey + : (await lq.getAddressInfo(asset_address)).pubkey; const version = 0; const contract = { @@ -98,8 +108,10 @@ app.post( ticker, version }; - - l.info("attempting issuance", req.user.username, contract); + + if (filename) contract.filename = filename; + + l.info("attempting issuance", req.user.username, contract, "address", address, "pubkey", pubkey); sha256.update(JSON.stringify(contract)); const hash = sha256.digest("hex"); @@ -108,7 +120,7 @@ app.post( .reverse() .join(""); const rawtx = await lq.createRawTransaction([], { data: "00" }); - const funded = await lq.fundRawTransaction(rawtx, { feeRate: 0.000003 }); + const funded = await lq.fundRawTransaction(rawtx, { feeRate: 0.000002 }); const params = { asset_amount, asset_address, @@ -136,133 +148,131 @@ app.post( const brt = await lq.blindRawTransaction(hex, true, [], false); const srt = await lq.signRawTransactionWithWallet(brt); const allowed = (await lq.testMempoolAccept([srt.hex]))[0].allowed; - if (allowed) { - const txid = await lq.sendRawTransaction(srt.hex); - - await db.transaction(async transaction => { - let account = await db.Account.findOne({ - where: { - user_id, - asset: config.liquid.btcasset, - pubkey: null - }, - include: { - model: db.User, - as: "user" - }, - lock: transaction.LOCK.UPDATE, - transaction - }); + fs.writeFileSync('tx', srt.hex); + if (!allowed) throw new Error("issuance rejected by mempool"); + const txid = await lq.sendRawTransaction(srt.hex); - let { user } = account; + await db.transaction(async transaction => { + let account = await db.Account.findOne({ + where: { + user_id, + asset: config.liquid.btcasset, + pubkey: null + }, + include: { + model: db.User, + as: "user" + }, + transaction + }); - if (Math.round(funded.fee * SATS) > account.balance) { - l.error( - "amount exceeds balance", - asset_amount, - funded.fee, - account.balance - ); - throw new Error( - `Insufficient funds to pay fee of ${funded.fee} BTC` - ); - } + let { user } = account; - await account.decrement( - { balance: Math.round(funded.fee * SATS) }, - { transaction } + if (Math.round(funded.fee * SATS) > account.balance) { + l.error( + "amount exceeds balance", + asset_amount, + funded.fee, + account.balance ); - await account.reload({ transaction }); - emit(user.username, "account", account); + throw new Error(`Insufficient funds to pay fee of ${funded.fee} BTC`); + } + + await account.decrement( + { balance: Math.round(funded.fee * SATS) }, + { transaction } + ); + await account.reload({ transaction }); + emit(user.username, "account", account); + if (address) return; + account = await db.Account.create( + { + asset, + contract, + domain, + user_id, + ticker, + precision, + name, + balance: 0, + network: "liquid", + pending: params.asset_amount * SATS + }, + { transaction } + ); + + emit(user.username, "account", account); + l.info( + "issued asset", + user.username, + params.asset_amount, + ticker, + name + ); + + 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 + }; + + if (token_amount) { account = await db.Account.create( { - asset, - contract, - domain, + asset: token, user_id, - ticker, - precision, - name, + domain, + ticker: `${ticker}REISSUANCETOKEN`, + precision: 8, + name: `${name} Reissuance Token`, balance: 0, - network: "liquid", - pending: params.asset_amount * SATS + pending: token_amount * SATS }, { transaction } ); - emit(user.username, "account", account); - l.info( - "issued asset", - user.username, - params.asset_amount, - ticker, - name - ); - const asset_payment = await db.Payment.create( + const token_payment = await db.Payment.create( { account_id: account.id, user_id, hash: txid, - amount: params.asset_amount * SATS, + amount: token_amount * SATS, received: true, confirmed: false, - address: asset_address, + address: token_address, network: "liquid" }, { transaction } ); - emit(user.username, "payment", asset_payment); + emit(user.username, "payment", token_payment); - issuances[txid] = { - user_id, - asset, - asset_amount: params.asset_amount, - asset_payment_id: asset_payment.id - }; - - if (token_amount) { - account = await db.Account.create( - { - asset: token, - user_id, - domain, - ticker: `${ticker}REISSUANCETOKEN`, - precision: 8, - name: `${name} Reissuance Token`, - balance: 0, - pending: 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); - - 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; + } + }); - res.send(issuances[txid]); - } + res.send(issuances[txid] ? issuances[txid] : { asset }); } catch (e) { - l.error("asset issuance failed", e.message); + l.error("asset issuance failed", e.message, e.stack); res.status(500).send(e.message); } }) diff --git a/routes/liquid/taxi.js b/routes/liquid/taxi.js new file mode 100644 index 00000000..14da9411 --- /dev/null +++ b/routes/liquid/taxi.js @@ -0,0 +1,85 @@ +const { + address: Address, + ECPair, + Psbt, + payments, + networks +} = require("@asoltys/liquidjs-lib"); +const wretch = require("wretch"); +const fetch = require("node-fetch"); +wretch().polyfills({ fetch }); +const url = prod + ? "https://blockstream.info/liquid/api" + : "http://electrs-liquid:3002"; +const electrs = wretch().url(url); +const network = networks.regtest; + +const key = ECPair.fromPrivateKey(Buffer.from(config.taxi, "hex")); + +module.exports = ah(async (req, res) => { + let { user } = req; + let { psbt } = req.body; + + try { + if (user.username !== "silhouettes") { + throw new Error("taxi service only available to select customers"); + } + + let redeem = payments.p2wpkh({ + pubkey: key.publicKey, + network + }); + + let out = payments.p2sh({ + redeem, + network + }); + + let utxos = await electrs + .url(`/address/${out.address}/utxo`) + .get() + .json(); + + let tx = utxos.find(tx => tx.value >= 150); + + let hex = await electrs + .url(`/tx/${tx.txid}/hex`) + .get() + .text(); + + let raw = Psbt.fromBase64(psbt) + .addInput({ + hash: tx.txid, + index: tx.vout, + redeemScript: redeem.output, + nonWitnessUtxo: Buffer.from(hex, "hex") + }) + .addOutput({ + asset: network.assetHash, + nonce: Buffer.alloc(1, 0), + script: Buffer.alloc(0), + value: 150 + }) + .addOutput({ + asset: network.assetHash, + nonce: Buffer.alloc(1), + script: out.output, + value: tx.value - 150 + }) + .signInput(1, key) + .finalizeInput(1) + .extractTransaction() + .toHex(); + + let txid = await electrs + .url("/tx") + .body(raw) + .post() + .text(); + + res.send({ txid }); + } catch (e) { + console.log(e); + return res.status(500).send(e); + } +}); diff --git a/routes/payments.js b/routes/payments.js index a4bae562..a749e333 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -142,6 +142,7 @@ ah(async () => { app.get("/liquid/generate", auth, require("./liquid/generate")); app.post("/liquid/fee", auth, require("./liquid/fee")); app.post("/liquid/send", auth, require("./liquid/send")); + app.post("/taxi", auth, require("./liquid/taxi")); require("./liquid/receive"); setTimeout(async () => { diff --git a/sampleconfig/liquid/elements.conf b/sampleconfig/liquid/elements.conf index bfd01638..ce93b307 100644 --- a/sampleconfig/liquid/elements.conf +++ b/sampleconfig/liquid/elements.conf @@ -7,7 +7,7 @@ rpcuser=admin1 rpcpassword=123 rpcbind=0.0.0.0 rpcallowip=0.0.0.0/0 -rcpwallet=a +rpcwallet=a validatepegin=0 initialfreecoins=2100000000000000 |
