UNPKG

@unique-nft/utils

Version:

A tiny library to work with Substrate and Ethereum addresses and do some more

207 lines (201 loc) 7.12 kB
import "./chunk-N4PTXCJY.mjs"; import { Address, Address_exports } from "./chunk-6B63RM6C.mjs"; import { __export } from "./chunk-SMH5LAMQ.mjs"; // src/Royalties/types.ts var RoyaltyType = /* @__PURE__ */ ((RoyaltyType2) => { RoyaltyType2["DEFAULT"] = "DEFAULT"; RoyaltyType2["PRIMARY_ONLY"] = "PRIMARY_ONLY"; return RoyaltyType2; })(RoyaltyType || {}); // src/Royalties/utils.ts var utils_exports = {}; __export(utils_exports, { ROYALTIES_PROPERTY: () => ROYALTIES_PROPERTY, encodeAddress: () => encodeAddress, get42Zeros: () => get42Zeros, parseRoyalties: () => parseRoyalties, parseRoyaltyPart: () => parseRoyaltyPart, splitStringEvery: () => splitStringEvery, toLibPart: () => toLibPart }); var ROYALTIES_PROPERTY = "royalties"; var get42Zeros = () => "".padStart(42, "0"); var splitStringEvery = (str, every) => { const result = []; for (let i = 0; i < str.length; i += every) { result.push(str.substring(i, i + every)); } return result; }; var encodeAddress = (address) => { if (Address_exports.is.ethereumAddress(address)) { return [ true, Address_exports.normalize.ethereumAddress(address).substring(2).padStart(64, "0").toLowerCase() ]; } return [false, Address_exports.substrate.decode(address).hex.substring(2)]; }; var toLibPart = (part) => { const account = Address_exports.is.ethereumAddress(part.address) ? part.address : Address_exports.mirror.substrateToEthereum(part.address); const value = part.value * 10n ** BigInt(part.decimals - 4); return { account, value }; }; var parseRoyaltyPart = (part) => { part.version = part.version ?? 1; if (1 > part.version || part.version > 127) { throw new Error(`Version must be between 1 and 127, got ${part.version}`); } if (!Number.isInteger(part.version)) { throw new Error(`Version must be an integer, got ${part.version}`); } part.decimals = part.decimals ?? 4; if (0 > part.decimals || part.decimals > 255) { throw new Error(`Decimals must be between 0 and 255, got ${part.decimals}`); } if (!Number.isInteger(part.decimals)) { throw new Error(`Decimals must be an integer, got ${part.decimals}`); } if (!Number.isInteger(part.value) && typeof part.value !== "bigint") { throw new Error(`Value must be an integer or bigint, got ${part.value} (${typeof part.value})`); } if (part.value < 1 || part.value > 2n ** 64n - 1n) { throw new Error( `Value must be between 1 and 18446744073709551615 (uint64), got ${part.value}` ); } part.royaltyType = part.royaltyType ?? "DEFAULT" /* DEFAULT */; if (!RoyaltyType[part.royaltyType]) { throw new Error( `Royalty type must be one of ${Object.keys(RoyaltyType)}, got ${part.royaltyType}` ); } part.address = Address_exports.extract.address(part.address); return part; }; var parseRoyalties = (parts) => { if (!Array.isArray(parts)) { throw new Error("Royalties must be an array"); } return parts.map(parseRoyaltyPart); }; // src/Royalties/calculation.ts var calculateRoyaltyPart = (part, sellPrice) => { const royalty = parseRoyaltyPart(part); return { address: royalty.address, amount: sellPrice * royalty.value / 10n ** BigInt(royalty.decimals) }; }; var calculateRoyalties = (royalties, isPrimarySale, sellPrice) => { return royalties.filter( (r) => isPrimarySale === (r.royaltyType === "PRIMARY_ONLY" /* PRIMARY_ONLY */) ).map((r) => calculateRoyaltyPart(r, sellPrice)); }; // src/Royalties/decoding.ts var decodeRoyaltyPart = (encoded) => { if (encoded.length !== 130) { throw new Error('Invalid royalty part encoding - length is not 32 bytes ("0x" + 64 symbols)'); } const encodedMeta = encoded.slice(2, 66); const encodedAddress = encoded.slice(2 + 64); const version = parseInt(encodedMeta.slice(0, 2), 16); const decimals = parseInt(encodedMeta.slice(46, 46 + 2), 16); const value = BigInt("0x" + encodedMeta.slice(48)); const royaltyType = encodedMeta[44] === "0" ? "DEFAULT" /* DEFAULT */ : "PRIMARY_ONLY" /* PRIMARY_ONLY */; const isEthereum = encodedMeta[45] === "0"; const address = isEthereum ? Address.normalize.ethereumAddress("0x" + encodedAddress.slice(24)) : Address.substrate.encode(encodedAddress); return { version, decimals, value, royaltyType, address }; }; var decodeRoyalties = (encoded) => { if ((encoded.length - 2) % 128 !== 0) { throw new Error("Invalid royalties encoding - length is not multiple of 64 bytes (128 symbols)"); } const parts = splitStringEvery(encoded.substring(2), 128).map( (encoded2) => "0x" + encoded2 ); return parts.map((part) => decodeRoyaltyPart(part)); }; var decodeRoyaltyToV2 = (encoded) => { const royaltyParts = encoded ? decodeRoyalties(encoded) : []; return royaltyParts.map((royaltyPart) => { const royalty = { address: royaltyPart.address, // core idea: given value 2500 with decimals 4, we want to get 2.5 // or 650000 with decimals 6, we want to get 6.5 percent: Number(royaltyPart.value) / Math.pow(10, royaltyPart.decimals - 2) }; if (royaltyPart.royaltyType === "PRIMARY_ONLY" /* PRIMARY_ONLY */) { royalty.isPrimaryOnly = true; } return royalty; }); }; // src/Royalties/encoding.ts var encodeRoyaltyPart = (royaltyPart) => { const part = parseRoyaltyPart(royaltyPart); const version = part.version.toString(16).padStart(2, "0"); const royaltyType = part.royaltyType === "DEFAULT" /* DEFAULT */ ? "0" : "1"; const decimals = part.decimals.toString(16).padStart(2, "0"); const value = part.value.toString(16).padStart(16, "0"); const [isEthereum, address] = encodeAddress(part.address); const addressType = isEthereum ? "0" : "1"; return `0x${version}${get42Zeros()}${royaltyType}${addressType}${decimals}${value}${address}`; }; var encodeRoyalties = (parts) => "0x" + parts.map((part) => encodeRoyaltyPart(part).substring(2)).join(""); var encodeRoyaltyFromV2 = (royalties) => { const royaltiesToEncode = royalties.map((royalty) => { const { address, percent, isPrimaryOnly } = royalty; const valueInPercent = percent * 100; if (valueInPercent % 1 !== 0) throw new Error("Royalty percent value must has maximum 2 decimal places"); return { address, value: BigInt(percent * 100), decimals: 4, royaltyType: isPrimaryOnly ? "PRIMARY_ONLY" /* PRIMARY_ONLY */ : "DEFAULT" /* DEFAULT */, version: 1 }; }); return encodeRoyalties(royaltiesToEncode); }; // src/Royalties/index.ts var Royalties = { part: { calculate: calculateRoyaltyPart, decode: decodeRoyaltyPart, encode: encodeRoyaltyPart, validate: (part) => { parseRoyaltyPart(part); return true; } }, calculate: calculateRoyalties, decode: decodeRoyalties, encode: encodeRoyalties, validate: (royalties) => { parseRoyalties(royalties); return true; }, uniqueV2: { decode: decodeRoyaltyToV2, encode: encodeRoyaltyFromV2 }, utils: utils_exports }; export { Royalties, RoyaltyType }; //# sourceMappingURL=royalties.mjs.map