91df73be75e9fe340ca0dc31cc543d101dbad57ebf4fc224d5d1f3d7d801aba8.json raw
1 {"ast":null,"code":"var __assign = this && this.__assign || function () {\n __assign = Object.assign || function (t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n };\n return __assign.apply(this, arguments);\n};\nimport { encodeBase64ToJson, encodeBase64toUint8, encodeJsonToBase64, encodeUint8toBase64Url } from './base64.js';\nimport { TOKEN_PREFIX, TOKEN_VERSION } from './utils/Constants.js';\nimport { bytesToHex, hexToBytes } from '@noble/curves/abstract/utils';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { decodeCBOR, encodeCBOR } from './cbor.js';\nimport { PaymentRequest } from './model/PaymentRequest.js';\nimport { pointFromHex } from '@cashu/crypto/modules/common';\nimport { verifyDLEQProof_reblind } from '@cashu/crypto/modules/client/NUT12';\n/**\n * Splits the amount into denominations of the provided @param keyset\n * @param value amount to split\n * @param keyset keys to look up split amounts\n * @param split? optional custom split amounts\n * @param order? optional order for split amounts (default: \"asc\")\n * @returns Array of split amounts\n * @throws Error if @param split amount is greater than @param value amount\n */\nexport function splitAmount(value, keyset, split, order) {\n if (split) {\n if (split.reduce(function (a, b) {\n return a + b;\n }, 0) > value) {\n throw new Error(\"Split is greater than total amount: \".concat(split.reduce(function (a, b) {\n return a + b;\n }, 0), \" > \").concat(value));\n }\n split.forEach(function (amt) {\n if (!hasCorrespondingKey(amt, keyset)) {\n throw new Error('Provided amount preferences do not match the amounts of the mint keyset.');\n }\n });\n value = value - split.reduce(function (curr, acc) {\n return curr + acc;\n }, 0);\n } else {\n split = [];\n }\n var sortedKeyAmounts = getKeysetAmounts(keyset);\n sortedKeyAmounts.forEach(function (amt) {\n var q = Math.floor(value / amt);\n for (var i = 0; i < q; ++i) split === null || split === void 0 ? void 0 : split.push(amt);\n value %= amt;\n });\n return split.sort(function (a, b) {\n return order === 'desc' ? b - a : a - b;\n });\n}\n/**\n * Creates a list of amounts to keep based on the proofs we have and the proofs we want to reach.\n * @param proofsWeHave complete set of proofs stored (from current mint)\n * @param amountToKeep amount to keep\n * @param keys keys of current keyset\n * @param targetCount the target number of proofs to reach\n * @returns an array of amounts to keep\n */\nexport function getKeepAmounts(proofsWeHave, amountToKeep, keys, targetCount) {\n // determines amounts we need to reach the targetCount for each amount based on the amounts of the proofs we have\n // it tries to select amounts so that the proofs we have and the proofs we want reach the targetCount\n var amountsWeWant = [];\n var amountsWeHave = proofsWeHave.map(function (p) {\n return p.amount;\n });\n var sortedKeyAmounts = getKeysetAmounts(keys, 'asc');\n sortedKeyAmounts.forEach(function (amt) {\n var countWeHave = amountsWeHave.filter(function (a) {\n return a === amt;\n }).length;\n var countWeWant = Math.max(targetCount - countWeHave, 0);\n for (var i = 0; i < countWeWant; ++i) {\n if (amountsWeWant.reduce(function (a, b) {\n return a + b;\n }, 0) + amt > amountToKeep) {\n break;\n }\n amountsWeWant.push(amt);\n }\n });\n // use splitAmount to fill the rest between the sum of amountsWeHave and amountToKeep\n var amountDiff = amountToKeep - amountsWeWant.reduce(function (a, b) {\n return a + b;\n }, 0);\n if (amountDiff) {\n var remainingAmounts = splitAmount(amountDiff, keys);\n remainingAmounts.forEach(function (amt) {\n amountsWeWant.push(amt);\n });\n }\n var sortedAmountsWeWant = amountsWeWant.sort(function (a, b) {\n return a - b;\n });\n return sortedAmountsWeWant;\n}\n/**\n * returns the amounts in the keyset sorted by the order specified\n * @param keyset to search in\n * @param order order to sort the amounts in\n * @returns the amounts in the keyset sorted by the order specified\n */\nexport function getKeysetAmounts(keyset, order) {\n if (order === void 0) {\n order = 'desc';\n }\n if (order == 'desc') {\n return Object.keys(keyset).map(function (k) {\n return parseInt(k);\n }).sort(function (a, b) {\n return b - a;\n });\n }\n return Object.keys(keyset).map(function (k) {\n return parseInt(k);\n }).sort(function (a, b) {\n return a - b;\n });\n}\n/**\n * Checks if the provided amount is in the keyset.\n * @param amount amount to check\n * @param keyset to search in\n * @returns true if the amount is in the keyset, false otherwise\n */\nexport function hasCorrespondingKey(amount, keyset) {\n return amount in keyset;\n}\n/**\n * Converts a bytes array to a number.\n * @param bytes to convert to number\n * @returns number\n */\nexport function bytesToNumber(bytes) {\n return hexToNumber(bytesToHex(bytes));\n}\n/**\n * Converts a hex string to a number.\n * @param hex to convert to number\n * @returns number\n */\nexport function hexToNumber(hex) {\n return BigInt(\"0x\".concat(hex));\n}\n/**\n * Converts a number to a hex string of 64 characters.\n * @param number (bigint) to conver to hex\n * @returns hex string start-padded to 64 characters\n */\nexport function numberToHexPadded64(number) {\n return number.toString(16).padStart(64, '0');\n}\nfunction isValidHex(str) {\n return /^[a-f0-9]*$/i.test(str);\n}\n/**\n * Checks wether a proof or a list of proofs contains a non-hex id\n * @param p Proof or list of proofs\n * @returns boolean\n */\nexport function hasNonHexId(p) {\n if (Array.isArray(p)) {\n return p.some(function (proof) {\n return !isValidHex(proof.id);\n });\n }\n return isValidHex(p.id);\n}\n//used for json serialization\nexport function bigIntStringify(_key, value) {\n return typeof value === 'bigint' ? value.toString() : value;\n}\n/**\n * Helper function to encode a v3 cashu token\n * @param token to encode\n * @returns encoded token\n */\nexport function getEncodedTokenV3(token) {\n var v3TokenObj = {\n token: [{\n mint: token.mint,\n proofs: token.proofs\n }]\n };\n if (token.unit) {\n v3TokenObj.unit = token.unit;\n }\n if (token.memo) {\n v3TokenObj.memo = token.memo;\n }\n return TOKEN_PREFIX + TOKEN_VERSION + encodeJsonToBase64(v3TokenObj);\n}\n/**\n * Helper function to encode a cashu token (defaults to v4 if keyset id allows it)\n * @param token\n * @param [opts]\n */\nexport function getEncodedToken(token, opts) {\n var nonHex = hasNonHexId(token.proofs);\n if (nonHex || (opts === null || opts === void 0 ? void 0 : opts.version) === 3) {\n if ((opts === null || opts === void 0 ? void 0 : opts.version) === 4) {\n throw new Error('can not encode to v4 token if proofs contain non-hex keyset id');\n }\n return getEncodedTokenV3(token);\n }\n return getEncodedTokenV4(token);\n}\nexport function getEncodedTokenV4(token) {\n // Make sure each DLEQ has its blinding factor\n token.proofs.forEach(function (p) {\n if (p.dleq && p.dleq.r == undefined) {\n throw new Error('Missing blinding factor in included DLEQ proof');\n }\n });\n var nonHex = hasNonHexId(token.proofs);\n if (nonHex) {\n throw new Error('can not encode to v4 token if proofs contain non-hex keyset id');\n }\n var idMap = {};\n var mint = token.mint;\n for (var i = 0; i < token.proofs.length; i++) {\n var proof = token.proofs[i];\n if (idMap[proof.id]) {\n idMap[proof.id].push(proof);\n } else {\n idMap[proof.id] = [proof];\n }\n }\n var tokenTemplate = {\n m: mint,\n u: token.unit || 'sat',\n t: Object.keys(idMap).map(function (id) {\n return {\n i: hexToBytes(id),\n p: idMap[id].map(function (p) {\n var _a;\n return __assign({\n a: p.amount,\n s: p.secret,\n c: hexToBytes(p.C)\n }, p.dleq && {\n d: {\n e: hexToBytes(p.dleq.e),\n s: hexToBytes(p.dleq.s),\n r: hexToBytes((_a = p.dleq.r) !== null && _a !== void 0 ? _a : '00')\n }\n });\n })\n };\n })\n };\n if (token.memo) {\n tokenTemplate.d = token.memo;\n }\n var encodedData = encodeCBOR(tokenTemplate);\n var prefix = 'cashu';\n var version = 'B';\n var base64Data = encodeUint8toBase64Url(encodedData);\n return prefix + version + base64Data;\n}\n/**\n * Helper function to decode cashu tokens into object\n * @param token an encoded cashu token (cashuAey...)\n * @returns cashu token object\n */\nexport function getDecodedToken(token) {\n // remove prefixes\n var uriPrefixes = ['web+cashu://', 'cashu://', 'cashu:', 'cashu'];\n uriPrefixes.forEach(function (prefix) {\n if (!token.startsWith(prefix)) {\n return;\n }\n token = token.slice(prefix.length);\n });\n return handleTokens(token);\n}\n/**\n * Helper function to decode different versions of cashu tokens into an object\n * @param token an encoded cashu token (cashuAey...)\n * @returns cashu Token object\n */\nexport function handleTokens(token) {\n var version = token.slice(0, 1);\n var encodedToken = token.slice(1);\n if (version === 'A') {\n var parsedV3Token = encodeBase64ToJson(encodedToken);\n if (parsedV3Token.token.length > 1) {\n throw new Error('Multi entry token are not supported');\n }\n var entry = parsedV3Token.token[0];\n var tokenObj = {\n mint: entry.mint,\n proofs: entry.proofs,\n unit: parsedV3Token.unit || 'sat'\n };\n if (parsedV3Token.memo) {\n tokenObj.memo = parsedV3Token.memo;\n }\n return tokenObj;\n } else if (version === 'B') {\n var uInt8Token = encodeBase64toUint8(encodedToken);\n var tokenData = decodeCBOR(uInt8Token);\n var proofs_1 = [];\n tokenData.t.forEach(function (t) {\n return t.p.forEach(function (p) {\n proofs_1.push(__assign({\n secret: p.s,\n C: bytesToHex(p.c),\n amount: p.a,\n id: bytesToHex(t.i)\n }, p.d && {\n dleq: {\n r: bytesToHex(p.d.r),\n s: bytesToHex(p.d.s),\n e: bytesToHex(p.d.e)\n }\n }));\n });\n });\n var decodedToken = {\n mint: tokenData.m,\n proofs: proofs_1,\n unit: tokenData.u || 'sat'\n };\n if (tokenData.d) {\n decodedToken.memo = tokenData.d;\n }\n return decodedToken;\n }\n throw new Error('Token version is not supported');\n}\n/**\n * Returns the keyset id of a set of keys\n * @param keys keys object to derive keyset id from\n * @returns\n */\nexport function deriveKeysetId(keys) {\n var pubkeysConcat = Object.entries(keys).sort(function (a, b) {\n return +a[0] - +b[0];\n }).map(function (_a) {\n var pubKey = _a[1];\n return hexToBytes(pubKey);\n }).reduce(function (prev, curr) {\n return mergeUInt8Arrays(prev, curr);\n }, new Uint8Array());\n var hash = sha256(pubkeysConcat);\n var hashHex = Buffer.from(hash).toString('hex').slice(0, 14);\n return '00' + hashHex;\n}\nexport function mergeUInt8Arrays(a1, a2) {\n // sum of individual array lengths\n var mergedArray = new Uint8Array(a1.length + a2.length);\n mergedArray.set(a1);\n mergedArray.set(a2, a1.length);\n return mergedArray;\n}\nexport function sortProofsById(proofs) {\n return proofs.sort(function (a, b) {\n return a.id.localeCompare(b.id);\n });\n}\nexport function isObj(v) {\n return typeof v === 'object';\n}\nexport function checkResponse(data) {\n if (!isObj(data)) return;\n if ('error' in data && data.error) {\n throw new Error(data.error);\n }\n if ('detail' in data && data.detail) {\n throw new Error(data.detail);\n }\n}\nexport function joinUrls() {\n var parts = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n parts[_i] = arguments[_i];\n }\n return parts.map(function (part) {\n return part.replace(/(^\\/+|\\/+$)/g, '');\n }).join('/');\n}\nexport function sanitizeUrl(url) {\n return url.replace(/\\/$/, '');\n}\nexport function sumProofs(proofs) {\n return proofs.reduce(function (acc, proof) {\n return acc + proof.amount;\n }, 0);\n}\nexport function decodePaymentRequest(paymentRequest) {\n return PaymentRequest.fromEncodedRequest(paymentRequest);\n}\nvar MessageNode = /** @class */function () {\n function MessageNode(message) {\n this._value = message;\n this._next = null;\n }\n Object.defineProperty(MessageNode.prototype, \"value\", {\n get: function () {\n return this._value;\n },\n set: function (message) {\n this._value = message;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(MessageNode.prototype, \"next\", {\n get: function () {\n return this._next;\n },\n set: function (node) {\n this._next = node;\n },\n enumerable: false,\n configurable: true\n });\n return MessageNode;\n}();\nexport { MessageNode };\nvar MessageQueue = /** @class */function () {\n function MessageQueue() {\n this._first = null;\n this._last = null;\n this._size = 0;\n }\n Object.defineProperty(MessageQueue.prototype, \"first\", {\n get: function () {\n return this._first;\n },\n set: function (messageNode) {\n this._first = messageNode;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(MessageQueue.prototype, \"last\", {\n get: function () {\n return this._last;\n },\n set: function (messageNode) {\n this._last = messageNode;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(MessageQueue.prototype, \"size\", {\n get: function () {\n return this._size;\n },\n set: function (v) {\n this._size = v;\n },\n enumerable: false,\n configurable: true\n });\n MessageQueue.prototype.enqueue = function (message) {\n var newNode = new MessageNode(message);\n if (this._size === 0 || !this._last) {\n this._first = newNode;\n this._last = newNode;\n } else {\n this._last.next = newNode;\n this._last = newNode;\n }\n this._size++;\n return true;\n };\n MessageQueue.prototype.dequeue = function () {\n if (this._size === 0 || !this._first) return null;\n var prev = this._first;\n this._first = prev.next;\n prev.next = null;\n this._size--;\n return prev.value;\n };\n return MessageQueue;\n}();\nexport { MessageQueue };\n/**\n * Removes all traces of DLEQs from a list of proofs\n * @param proofs The list of proofs that dleq should be stripped from\n */\nexport function stripDleq(proofs) {\n return proofs.map(function (p) {\n var newP = __assign({}, p);\n delete newP['dleq'];\n delete newP['dleqValid'];\n return newP;\n });\n}\n/**\n * Checks that the proof has a valid DLEQ proof according to\n * keyset `keys`\n * @param proof The proof subject to verification\n * @param keyset The Mint's keyset to be used for verification\n * @returns true if verification succeeded, false otherwise\n * @throws Error if @param proof does not match any key in @param keyset\n */\nexport function hasValidDleq(proof, keyset) {\n var _a;\n if (proof.dleq == undefined) {\n return false;\n }\n var dleq = {\n e: hexToBytes(proof.dleq.e),\n s: hexToBytes(proof.dleq.s),\n r: hexToNumber((_a = proof.dleq.r) !== null && _a !== void 0 ? _a : '00')\n };\n if (!hasCorrespondingKey(proof.amount, keyset.keys)) {\n throw new Error(\"undefined key for amount \".concat(proof.amount));\n }\n var key = keyset.keys[proof.amount];\n if (!verifyDLEQProof_reblind(new TextEncoder().encode(proof.secret), dleq, pointFromHex(proof.C), pointFromHex(key))) {\n return false;\n }\n return true;\n}\n//# sourceMappingURL=utils.js.map","map":null,"metadata":{},"sourceType":"module","externalDependencies":[]}