diff --git a/Dockerfile b/Dockerfile index f9744752..4c27f653 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,5 +16,5 @@ RUN npm install # Bundle app source EXPOSE 8080 -CMD [ "node", "./dist/index.js" ] +CMD npm start diff --git a/package-lock.json b/package-lock.json index f08eb9eb..958a0679 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "yoroi-cardano-backend", - "version": "2.1.0", + "version": "2.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -31,9 +31,9 @@ } }, "@emurgo/cardano-serialization-lib-nodejs": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-9.1.0.tgz", - "integrity": "sha512-4gW+KqejTSm/rkNwWxK/WUJvlifWqFx5ShgCtWmPuTZ/YJAZSpROI8DP+pqTakG0gGWdxPB3BnVJIPrczNwmtA==" + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-9.1.3.tgz", + "integrity": "sha512-oFfWfGZ8HBpDKpK+/UsSqkMbVLSEYSJuWdvzVcziqBJ3FRM3MK2vd9P8woMkRP5WjC2LsnKpC9f+fgrogtlApA==" }, "@eslint/eslintrc": { "version": "0.2.1", @@ -3677,7 +3677,8 @@ "prettier": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==" + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "dev": true }, "process-nextick-args": { "version": "2.0.1", diff --git a/package.json b/package.json index 14f418e5..be9f8273 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yoroi-cardano-backend", - "version": "2.1.0", + "version": "2.2.0", "description": "Wrapped for cardano-db-sync and cardano-graphql with endpoints useful for light wallets", "main": "src/index.ts", "scripts": { @@ -22,8 +22,8 @@ } }, "dependencies": { - "@emurgo/cardano-serialization-lib-nodejs": "^9.1.0", "aws-sdk": "^2.1056.0", + "@emurgo/cardano-serialization-lib-nodejs": "9.1.3", "axios": "^0.21.1", "bech32": "^1.1.4", "bunyan": "^1.8.15", @@ -38,7 +38,6 @@ "mocha": "^8.2.0", "pg": "^8.4.2", "pm2": "^4.5.0", - "prettier": "^2.5.1", "semver-compare": "^1.0.0", "ts-node": "^9.0.0", "tsc-watch": "^4.2.9", @@ -65,6 +64,7 @@ "eslint-config-airbnb-typescript": "^9.0.0", "eslint-plugin-import": "^2.22.1", "husky": "^4.3.0", + "prettier": "^2.5.1", "ramda": "^0.27.1" }, "engines": { diff --git a/src/services/signedTransaction.ts b/src/services/signedTransaction.ts index 1f30eace..26aadd9a 100644 --- a/src/services/signedTransaction.ts +++ b/src/services/signedTransaction.ts @@ -6,11 +6,12 @@ import { calculateTxId } from "../utils"; const submissionEndpoint: string = config.get("server.txSubmissionEndpoint"); // THIS IS FOR CARDANO-WALLET, CBOR IS FOR CARDANO-SUBMIT-API (1.27.0). -const contentType = config.get("usingQueueEndpoint") === "true" - ? "application/json" - : `application/${process.env.TX_SUBMIT_CONTENT_TYPE || "octet-stream"}`; +const contentType = + config.get("usingQueueEndpoint") === "true" + ? "application/json" + : `application/${process.env.TX_SUBMIT_CONTENT_TYPE || "octet-stream"}`; const contentTypeHeaders = { - "Content-Type": contentType + "Content-Type": contentType, }; // const contentTypeHeaders = {"Content-Type": "application/cbor"}; @@ -22,15 +23,15 @@ const submitToQueue = async (req: Request, res: Response) => { const signedTxQueueEndpoint = config.get("server.signedTxQueueEndpoint"); await axios({ - method: "post" - , url: `${signedTxQueueEndpoint}api/submit/tx` - , data: { + method: "post", + url: `${signedTxQueueEndpoint}api/submit/tx`, + data: { txId: txId, - signedTx: buffer.toString("base64") - } - , headers: contentTypeHeaders + signedTx: buffer.toString("base64"), + }, + headers: contentTypeHeaders, }); - res.status(200).send({txId}); + res.status(200).send({ txId }); } catch (err) { console.error(err); res.status(500).send("Error submitting the TX"); @@ -42,29 +43,36 @@ const submit = async (req: Request, res: Response) => { const LOGGING_MSG_HOLDER: [any, any] = [null, null]; try { const endpointResponse: any = await axios({ - method: "post" - , url: submissionEndpoint - , data: buffer - , headers: contentTypeHeaders - }).then(r => { - try { - const {status, statusText, data} = r || {}; - LOGGING_MSG_HOLDER[0] = `FULL: ${JSON.stringify({status, statusText, data})}`; - } catch (e) { + method: "post", + url: submissionEndpoint, + data: buffer, + headers: contentTypeHeaders, + }).then( + (r) => { try { - LOGGING_MSG_HOLDER[0] = `FULL_ERR: ${r} | ${e}`; - } catch (ee) { - LOGGING_MSG_HOLDER[0] = `FULL_ERR_ERR: ${ee}`; + const { status, statusText, data } = r || {}; + LOGGING_MSG_HOLDER[0] = `FULL: ${JSON.stringify({ + status, + statusText, + data, + })}`; + } catch (e) { + try { + LOGGING_MSG_HOLDER[0] = `FULL_ERR: ${r} | ${e}`; + } catch (ee) { + LOGGING_MSG_HOLDER[0] = `FULL_ERR_ERR: ${ee}`; + } + } + return r; + }, + (err) => { + try { + LOGGING_MSG_HOLDER[1] = `ERR: ${JSON.stringify(err)}`; + } catch (e) { + LOGGING_MSG_HOLDER[1] = `ERR_ERR: ${err}`; } } - return r; - }, err => { - try { - LOGGING_MSG_HOLDER[1] = `ERR: ${JSON.stringify(err)}`; - } catch (e) { - LOGGING_MSG_HOLDER[1] = `ERR_ERR: ${err}`; - } - }); + ); if (endpointResponse?.status === 202) { if (endpointResponse.data.Left) { const msg = `Transaction was rejected: ${endpointResponse.data.Left}`; @@ -74,23 +82,31 @@ const submit = async (req: Request, res: Response) => { res.send([]); return; } else { - const {status, statusText, data} = endpointResponse || {}; - throw Error(`I did not understand the response from the submission endpoint: ${JSON.stringify({ - status, - statusText, - data, - err: LOGGING_MSG_HOLDER[1], - })}`); + const { status, statusText, data } = endpointResponse || {}; + throw Error( + `I did not understand the response from the submission endpoint: ${JSON.stringify( + { + status, + statusText, + data, + err: LOGGING_MSG_HOLDER[1], + } + )}` + ); } } catch (error: any) { - const msg = `Error trying to send transaction: ${error} - ${JSON.stringify(LOGGING_MSG_HOLDER)}`; + const msg = `Error trying to send transaction: ${error} - ${JSON.stringify( + LOGGING_MSG_HOLDER + )}`; throw Error(msg); } }; -export const handleSignedTx = async (req: Request, res: Response): Promise => { - if (!req.body.signedTx) - throw new Error("No signedTx in body"); +export const handleSignedTx = async ( + req: Request, + res: Response +): Promise => { + if (!req.body.signedTx) throw new Error("No signedTx in body"); if (config.get("usingQueueEndpoint") === "true") { await submitToQueue(req, res); diff --git a/src/services/txStatus.ts b/src/services/txStatus.ts index 4d4a7bc1..c6216f0f 100644 --- a/src/services/txStatus.ts +++ b/src/services/txStatus.ts @@ -32,34 +32,34 @@ export const handleTxStatus = const result = await pool.query(txStatusQuery, [txHashes]); - const response: any = {}; - const depth: {[key: string]: number} = {}; + const response: any = {}; + const depth: { [key: string]: number } = {}; for (const item of result.rows) { depth[item.tx_id] = item.depth; } - response.depth = depth; + response.depth = depth; - if (config.get("usingQueueEndpoint") === "true") { - try { - const result = await axios({ - method: "post", - url: `${signedTxQueueEndpoint}api/getTxsStatus`, - data: { - txHashes: txHashes - } - }); + if (config.get("usingQueueEndpoint") === "true") { + try { + const result = await axios({ + method: "post", + url: `${signedTxQueueEndpoint}api/getTxsStatus`, + data: { + txHashes: txHashes, + }, + }); - const submissionStatus: {[key: string]: string} = {}; - for (const status of result.data) { - submissionStatus[status.id] = status.status; + const submissionStatus: { [key: string]: string } = {}; + for (const status of result.data) { + submissionStatus[status.id] = status.status; + } + response.submissionStatus = submissionStatus; + } finally { + // ignore errors } - response.submissionStatus = submissionStatus; - } finally { - // ignore errors } - } - res.send(response); -}; \ No newline at end of file + res.send(response); + }; diff --git a/src/utils/mappers.ts b/src/utils/mappers.ts index 22dd74b8..2130b1a6 100644 --- a/src/utils/mappers.ts +++ b/src/utils/mappers.ts @@ -15,6 +15,7 @@ import { GeneralTransactionMetadata, TransactionMetadatum, BigNum, + MetadataMap, } from "@emurgo/cardano-serialization-lib-nodejs"; const MAX_INT = "2147483647"; @@ -133,14 +134,25 @@ function buildMetadataObj( const keyWasm = BigNum.from_str(key); // the cbor inserted into SQL is not the full metadata for the transaction // instead, each row is a CBOR map with a single entry - const singletonMap = TransactionMetadatum.from_bytes( - Buffer.from( - // need to cutoff the \\x prefix added by SQL - metadataMap[key].substring(2), - "hex" - ) - ); - const map = singletonMap.as_map(); + let singletonMap; + let map; + try { + singletonMap = TransactionMetadatum.from_bytes( + Buffer.from( + // need to cutoff the \\x prefix added by SQL + metadataMap[key].substring(2), + "hex" + ) + ); + map = singletonMap.as_map(); + } catch { + map = MetadataMap.new(); + map.insert_str( + "error", + TransactionMetadatum.new_text("failed to deserialize") + ); + } + const keys = map.keys(); for (let i = 0; i < keys.len(); i++) { const cborKey = keys.get(i); @@ -150,7 +162,9 @@ function buildMetadataObj( cborKey.free(); } keyWasm.free(); - singletonMap.free(); + if (singletonMap) { + singletonMap.free(); + } map.free(); keys.free(); }