From b5d2ddf2bc4bc10e6983fa13df3631589975c2b6 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Fri, 27 Mar 2020 18:55:03 -0400 Subject: [PATCH] handle encoding/decoding spontpays --- services/gunDB/contact-api/schema.js | 107 +++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/services/gunDB/contact-api/schema.js b/services/gunDB/contact-api/schema.js index 435c0ec4..9f2035ef 100644 --- a/services/gunDB/contact-api/schema.js +++ b/services/gunDB/contact-api/schema.js @@ -1,6 +1,11 @@ /** * @format */ +const logger = require('winston') +const isFinite = require('lodash/isFinite') +const isNumber = require('lodash/isNumber') +const isNaN = require('lodash/isNaN') + /** * @typedef {object} HandshakeRequest * @prop {string} from Public key of the requestor. @@ -410,3 +415,105 @@ exports.isOrderResponse = o => { return obj.type === 'err' || obj.type === 'invoice' } + +/** + * @typedef {import('./schema-types').EncSpontPayment} EncSpontPayment + */ + +const ENC_SPONT_PAYMENT_PREFIX = '$$__SHOCKWALLET__SPONT__PAYMENT__' + +/** + * @param {string} s + * @returns {s is EncSpontPayment} + */ +const isEncodedSpontPayment = s => s.indexOf(ENC_SPONT_PAYMENT_PREFIX) === 0 + +exports.isEncodedSpontPayment = isEncodedSpontPayment + +/** + * @typedef {object} SpontaneousPayment + * @prop {number} amt + * @prop {string} memo + * @prop {string} preimage + */ + +/** + * + * @param {EncSpontPayment} sp + * @throws {Error} If decoding fails. + * @returns {SpontaneousPayment} + */ +exports.decodeSpontPayment = sp => { + try { + const [preimage, amtStr, memo] = sp + .slice(ENC_SPONT_PAYMENT_PREFIX.length) + .split('__') + + if (typeof preimage !== 'string') { + throw new TypeError('Could not parse preimage') + } + + if (typeof amtStr !== 'string') { + throw new TypeError('Could not parse amt') + } + + if (typeof memo !== 'string') { + throw new TypeError('Could not parse memo') + } + + const amt = Number(amtStr) + + if (!isNumber(amt)) { + throw new TypeError(`Could parse amount as a number, not a number?`) + } + + if (isNaN(amt)) { + throw new TypeError(`Could not amount as a number, got NaN.`) + } + + if (!isFinite(amt)) { + throw new TypeError( + `Amount was correctly parsed, but got a non finite number.` + ) + } + + return { + amt, + memo, + preimage + } + } catch (err) { + logger.debug(`Encoded spontaneous payment: ${sp}`) + logger.error(err) + throw err + } +} + +/** + * + * @param {number} amt + * @param {string} memo + * @param {string} preimage + * @returns {EncSpontPayment} + */ +exports.encodeSpontaneousPayment = (amt, memo, preimage) => { + if (amt <= 0) { + throw new RangeError('Amt must be greater than zero') + } + + if (memo.length < 1) { + throw new TypeError('Memo must be populated') + } + + if (preimage.length < 1) { + throw new TypeError('preimage must be populated') + } + + const enc = `${ENC_SPONT_PAYMENT_PREFIX}__${amt}__${memo}__${preimage}` + + if (isEncodedSpontPayment(enc)) { + return enc + } + + throw new Error('isEncodedSpontPayment(enc) false') +}