UNPKG

@stricahq/typhonjs

Version:

Pure JS Cardano Wallet library

277 lines (276 loc) 12.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createPlutusDataCbor = exports.createAuxiliaryDataCbor = exports.getMaximumTokenSets = exports.getAddressFromString = exports.decodeBech32 = exports.getAddressFromHex = exports.calculateMinUtxoAmountBabbage = exports.calculateMinUtxoAmount = exports.getOutputValueSize = void 0; const buffer_1 = require("buffer"); const cbors = __importStar(require("@stricahq/cbors")); const bignumber_js_1 = __importDefault(require("bignumber.js")); const _ = require("lodash"); const bs58_1 = __importDefault(require("bs58")); const bech32_1 = require("bech32"); const constants_1 = require("../constants"); const BaseAddress_1 = __importDefault(require("../address/BaseAddress")); const ByronAddress_1 = __importDefault(require("../address/ByronAddress")); const EnterpriseAddress_1 = __importDefault(require("../address/EnterpriseAddress")); const PointerAddress_1 = __importDefault(require("../address/PointerAddress")); const helpers_1 = require("./helpers"); const types_1 = require("../types"); const RewardAddress_1 = __importDefault(require("../address/RewardAddress")); const encoder_1 = require("./encoder"); const getOutputValueSize = (adaAmount, tokens) => { const encodedAmount = tokens.length > 0 ? [adaAmount, (0, encoder_1.encodeOutputTokens)(tokens)] : adaAmount; return cbors.Encoder.encode(encodedAmount).byteLength; }; exports.getOutputValueSize = getOutputValueSize; const calculateMinUtxoAmount = (tokens, lovelacePerUtxoWord, hasPlutusDataHash) => { const uniqueTokens = (0, helpers_1.getUniqueTokens)(tokens); const roundupBytesToWords = (x) => Math.floor((x + 7) / 8); const coinSize = 2; let utxoEntrySizeWithoutVal = 27; if (hasPlutusDataHash) { utxoEntrySizeWithoutVal += 10; } const adaOnlyUtxoSize = utxoEntrySizeWithoutVal + coinSize; const tokenBundle = _(uniqueTokens) .groupBy(({ policyId }) => policyId) .value(); const uniqueAssetNames = uniqueTokens.reduce((result, token) => { result[token.assetName] = true; return result; }, {}); const policyCount = _.reduce(tokenBundle, (result) => { result += 1; return result; }, 0); const assetNameSize = _.reduce(uniqueAssetNames, (sum, status, assetName) => sum + Math.max(buffer_1.Buffer.from(assetName, "hex").length, 1), 0); const policyIdSize = 28; const size = 6 + roundupBytesToWords(uniqueTokens.length * 12 + assetNameSize + policyCount * policyIdSize); const minUtxo = lovelacePerUtxoWord.toNumber() * adaOnlyUtxoSize; if (uniqueTokens.length === 0) { return new bignumber_js_1.default(minUtxo); } const minUtxoWithTokens = lovelacePerUtxoWord.toNumber() * (utxoEntrySizeWithoutVal + size); return bignumber_js_1.default.max(minUtxo, minUtxoWithTokens); }; exports.calculateMinUtxoAmount = calculateMinUtxoAmount; const calculateMinUtxoAmountBabbage = (output, utxoCostPerByte) => { const minADA = new bignumber_js_1.default(160 + cbors.Encoder.encode((0, encoder_1.encodeOutput)(output)).length).multipliedBy(utxoCostPerByte); return minADA; }; exports.calculateMinUtxoAmountBabbage = calculateMinUtxoAmountBabbage; const getAddressFromHex = (hexAddress) => { const hexAddressString = hexAddress.toString("hex"); const typeHex = hexAddressString.toLowerCase().charAt(0); const networkId = Number(hexAddressString.toLowerCase().charAt(1)); let stakeCredential; let paymentCredential; switch (typeHex) { case "e": stakeCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(0, 56), "hex"), type: types_1.HashType.ADDRESS, }; return new RewardAddress_1.default(networkId, stakeCredential); case "f": stakeCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(0, 56), "hex"), type: types_1.HashType.SCRIPT, }; return new RewardAddress_1.default(networkId, stakeCredential); case "7": { paymentCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2), "hex"), type: types_1.HashType.SCRIPT, }; return new EnterpriseAddress_1.default(networkId, paymentCredential); } case "6": { paymentCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2), "hex"), type: types_1.HashType.ADDRESS, }; return new EnterpriseAddress_1.default(networkId, paymentCredential); } case "5": { paymentCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(0, 56), "hex"), type: types_1.HashType.SCRIPT, }; const vlq = hexAddressString.slice(2).slice(56); return new PointerAddress_1.default(networkId, paymentCredential, vlq); } case "4": { paymentCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(0, 56), "hex"), type: types_1.HashType.ADDRESS, }; const vlq = hexAddressString.slice(2).slice(56); return new PointerAddress_1.default(networkId, paymentCredential, vlq); } case "3": paymentCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(0, 56), "hex"), type: types_1.HashType.SCRIPT, }; stakeCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(56), "hex"), type: types_1.HashType.SCRIPT, }; return new BaseAddress_1.default(networkId, paymentCredential, stakeCredential); case "2": paymentCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(0, 56), "hex"), type: types_1.HashType.ADDRESS, }; stakeCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(56), "hex"), type: types_1.HashType.SCRIPT, }; return new BaseAddress_1.default(networkId, paymentCredential, stakeCredential); case "1": paymentCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(0, 56), "hex"), type: types_1.HashType.SCRIPT, }; stakeCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(56), "hex"), type: types_1.HashType.ADDRESS, }; return new BaseAddress_1.default(networkId, paymentCredential, stakeCredential); case "0": paymentCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(0, 56), "hex"), type: types_1.HashType.ADDRESS, }; stakeCredential = { hash: buffer_1.Buffer.from(hexAddressString.slice(2).slice(56), "hex"), type: types_1.HashType.ADDRESS, }; return new BaseAddress_1.default(networkId, paymentCredential, stakeCredential); case "8": return new ByronAddress_1.default(hexAddress); default: throw new Error("Unsupported address type"); } }; exports.getAddressFromHex = getAddressFromHex; const decodeBech32 = (bech32Address) => { const decoded = bech32_1.bech32.decode(bech32Address, 114); const decodedBech = bech32_1.bech32.fromWords(decoded.words); const decodedAddress = buffer_1.Buffer.from(decodedBech); return { prefix: decoded.prefix, value: decodedAddress, }; }; exports.decodeBech32 = decodeBech32; const getAddressFromString = (address) => { try { const byronAddress = buffer_1.Buffer.from(bs58_1.default.decode(address)); try { cbors.Decoder.decode(byronAddress); } catch (e) { throw new Error("Invalid Byron Address"); } return new ByronAddress_1.default(byronAddress); } catch (error) { try { const decodeAddr = (0, exports.decodeBech32)(address); if (decodeAddr.prefix === "addr" || decodeAddr.prefix === "addr_test" || decodeAddr.prefix === "stake" || decodeAddr.prefix === "stake_test") { return (0, exports.getAddressFromHex)(decodeAddr.value); } throw new Error("Invalid Address"); } catch (err) { throw new Error("Invalid Address"); } } }; exports.getAddressFromString = getAddressFromString; const getMaximumTokenSets = (oTokens, maxValueSizePP) => { const tokens = _.cloneDeep(oTokens); const result = []; while (tokens.length > 0) { const tokenArray = []; const tokenLengthFixed = tokens.length; for (let i = 0; i < tokenLengthFixed; i += 1) { const token = tokens.shift(); if (token) { // set default value as full token let newToken = token; // if the token amount is more than the max amount (int), only use max amount token // add remaining amount of tokens into another output set if (token.amount.gte(constants_1.maxTokenAmount)) { newToken = { assetName: token.assetName, policyId: token.policyId, amount: new bignumber_js_1.default(constants_1.maxTokenAmount), }; } // calculate the current token set size const tokenArrayOutputSize = (0, exports.getOutputValueSize)(new bignumber_js_1.default(constants_1.maxAdaAmount), [ ...tokenArray, newToken, ]); // only add the token to the current set if its under maxValueSize limit if (tokenArrayOutputSize < maxValueSizePP) { tokenArray.push(newToken); // if the above token used in this set had max value // add the remaining token amount for the next set if (token.amount.gte(constants_1.maxTokenAmount)) { token.amount = token.amount.minus(constants_1.maxTokenAmount); tokens.push(token); } } else { // add the popped token back to main list, since it didn't make it into the current set tokens.push(token); } // while modifying this func, make sure to handle the case above, no logic must follow this line } } result.push(tokenArray); } return result; }; exports.getMaximumTokenSets = getMaximumTokenSets; const createAuxiliaryDataCbor = (auxiliaryData) => { const encodedAuxData = (0, encoder_1.encodeAuxiliaryData)(auxiliaryData); return cbors.Encoder.encode(encodedAuxData); }; exports.createAuxiliaryDataCbor = createAuxiliaryDataCbor; const createPlutusDataCbor = (plutusData) => { const encodedPlutusData = (0, encoder_1.encodePlutusData)(plutusData); return cbors.Encoder.encode(encodedPlutusData); }; exports.createPlutusDataCbor = createPlutusDataCbor;