UNPKG

@unique-nft/utils

Version:

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

1 lines 14.3 kB
{"version":3,"sources":["../src/Royalties/types.ts","../src/Royalties/utils.ts","../src/Royalties/calculation.ts","../src/Royalties/decoding.ts","../src/Royalties/encoding.ts","../src/Royalties/index.ts"],"sourcesContent":["export enum RoyaltyType {\n DEFAULT = 'DEFAULT',\n PRIMARY_ONLY = 'PRIMARY_ONLY',\n}\n\nexport interface UniqueRoyaltyPart {\n version: number\n royaltyType: RoyaltyType | `${RoyaltyType}`\n decimals: number\n value: bigint\n address: string\n}\n\nexport type UniqueRoyaltyPartToEncode = {\n version?: number\n royaltyType?: RoyaltyType | `${RoyaltyType}`\n decimals?: number\n value: bigint\n address: string\n}\n\nexport type RoyaltyAmount = {\n address: string\n amount: bigint\n}\n\nexport type LibPart = {\n account: string\n value: bigint\n}\n\nexport type IV2Royalty = {\n address: string,\n percent: number,\n isPrimaryOnly?: boolean,\n}\n","import {LibPart, RoyaltyType, UniqueRoyaltyPart, UniqueRoyaltyPartToEncode} from './types'\nimport {Address} from '../index'\n\nexport const ROYALTIES_PROPERTY = 'royalties'\n\nexport const get42Zeros = () => ''.padStart(42, '0')\n\nexport const splitStringEvery = (str: string, every: number): string[] => {\n const result = []\n\n for (let i = 0; i < str.length; i += every) {\n result.push(str.substring(i, i + every))\n }\n\n return result\n}\n\n\nexport const encodeAddress = (address: string): [boolean, string] => {\n if (Address.is.ethereumAddress(address)) {\n return [\n true,\n Address.normalize\n .ethereumAddress(address)\n .substring(2)\n .padStart(64, '0')\n .toLowerCase(),\n ]\n }\n\n return [false, Address.substrate.decode(address).hex.substring(2)]\n}\n\nexport const toLibPart = (part: UniqueRoyaltyPart): LibPart => {\n const account = Address.is.ethereumAddress(part.address)\n ? part.address\n : Address.mirror.substrateToEthereum(part.address)\n\n // recalculating value to 4 decimals\n const value = part.value * 10n ** BigInt(part.decimals - 4)\n\n return {account, value}\n}\n\nexport const parseRoyaltyPart = (\n part: UniqueRoyaltyPartToEncode,\n): UniqueRoyaltyPart => {\n part.version = part.version ?? 1\n if (1 > part.version || part.version > 127) {\n throw new Error(`Version must be between 1 and 127, got ${part.version}`)\n }\n\n if (!Number.isInteger(part.version)) {\n throw new Error(`Version must be an integer, got ${part.version}`)\n }\n\n part.decimals = part.decimals ?? 4\n if (0 > part.decimals || part.decimals > 255) {\n throw new Error(`Decimals must be between 0 and 255, got ${part.decimals}`)\n }\n\n if (!Number.isInteger(part.decimals)) {\n throw new Error(`Decimals must be an integer, got ${part.decimals}`)\n }\n\n if (!Number.isInteger(part.value) && (typeof part.value !== 'bigint')) {\n throw new Error(`Value must be an integer or bigint, got ${part.value} (${typeof part.value})`)\n }\n\n if (part.value < 1 || part.value > (2n ** 64n - 1n)) {\n throw new Error(\n `Value must be between 1 and 18446744073709551615 (uint64), got ${part.value}`,\n )\n }\n\n part.royaltyType = part.royaltyType ?? RoyaltyType.DEFAULT\n\n if (!RoyaltyType[part.royaltyType]) {\n throw new Error(\n `Royalty type must be one of ${Object.keys(RoyaltyType)}, got ${\n part.royaltyType\n }`,\n )\n }\n\n part.address = Address.extract.address(part.address)\n\n return part as UniqueRoyaltyPart\n}\n\nexport const parseRoyalties = (parts: UniqueRoyaltyPartToEncode[]): UniqueRoyaltyPart[] => {\n if (!Array.isArray(parts)) {\n throw new Error('Royalties must be an array')\n }\n return parts.map(parseRoyaltyPart)\n}\n","import {RoyaltyAmount, RoyaltyType, UniqueRoyaltyPartToEncode} from './types'\nimport {parseRoyaltyPart} from './utils'\n\nexport const calculateRoyaltyPart = (\n part: UniqueRoyaltyPartToEncode,\n sellPrice: bigint,\n): RoyaltyAmount => {\n const royalty = parseRoyaltyPart(part)\n return {\n address: royalty.address,\n amount: (sellPrice * royalty.value) / 10n ** BigInt(royalty.decimals),\n }\n}\n\nexport const calculateRoyalties = (\n royalties: UniqueRoyaltyPartToEncode[],\n isPrimarySale: boolean,\n sellPrice: bigint,\n): RoyaltyAmount[] => {\n return royalties\n .filter(\n (r) => isPrimarySale === (r.royaltyType === RoyaltyType.PRIMARY_ONLY),\n )\n .map((r) => calculateRoyaltyPart(r, sellPrice))\n}\n","import {Address} from '../Address'\n\nimport {IV2Royalty, RoyaltyType, UniqueRoyaltyPart} from './types'\nimport {splitStringEvery} from './utils'\n\nexport const decodeRoyaltyPart = (encoded: string): UniqueRoyaltyPart => {\n if (encoded.length !== 130) {\n throw new Error('Invalid royalty part encoding - length is not 32 bytes (\"0x\" + 64 symbols)')\n }\n const encodedMeta = encoded.slice(2, 66)\n const encodedAddress = encoded.slice(2 + 64)\n\n const version = parseInt(encodedMeta.slice(0, 2), 16)\n const decimals = parseInt(encodedMeta.slice(46, 46 + 2), 16)\n const value = BigInt('0x' + encodedMeta.slice(48))\n const royaltyType = encodedMeta[44] === '0'\n ? RoyaltyType.DEFAULT\n : RoyaltyType.PRIMARY_ONLY\n\n const isEthereum = encodedMeta[45] === '0'\n const address = isEthereum\n ? Address.normalize.ethereumAddress('0x' + encodedAddress.slice(24))\n : Address.substrate.encode(encodedAddress)\n\n return {\n version,\n decimals,\n value,\n royaltyType,\n address,\n }\n}\n\nexport const decodeRoyalties = (encoded: string): UniqueRoyaltyPart[] => {\n if (((encoded.length - 2) % 128) !== 0) {\n throw new Error('Invalid royalties encoding - length is not multiple of 64 bytes (128 symbols)')\n }\n\n const parts = splitStringEvery(encoded.substring(2), 128).map(\n (encoded) => '0x' + encoded,\n )\n\n return parts.map((part) => decodeRoyaltyPart(part))\n}\n\nexport const decodeRoyaltyToV2 = (encoded: string): IV2Royalty[] => {\n const royaltyParts = encoded ? decodeRoyalties(encoded) : []\n\n return royaltyParts.map((royaltyPart) => {\n const royalty: IV2Royalty = {\n address: royaltyPart.address,\n // core idea: given value 2500 with decimals 4, we want to get 2.5\n // or 650000 with decimals 6, we want to get 6.5\n percent: Number(royaltyPart.value) / (Math.pow(10, royaltyPart.decimals - 2)),\n }\n if (royaltyPart.royaltyType === RoyaltyType.PRIMARY_ONLY) {\n royalty.isPrimaryOnly = true\n }\n return royalty\n })\n}\n","import {IV2Royalty, RoyaltyType, UniqueRoyaltyPart, UniqueRoyaltyPartToEncode} from './types'\nimport {encodeAddress, get42Zeros, parseRoyaltyPart} from './utils'\n\n/**\n * encodes a UniqueRoyaltyPart into a hex string\n * @param part UniqueRoyaltyPart\n * @returns hex string where first 64 characters are metadata in format:\n * VV000000000000000000000000000000000000000000RADDvvvvvvvvvvvvvvvv\n * where:\n * VV - version\n * 42 zeros\n * R - royalty type (0 - default, 1 - primary-only)\n * A - address type (0 - ethereum, 1 - substrate)\n * DD - decimals\n * vvvvvvvvvvvvvvvvvv - value (uint64)\n *\n * and the rest of the string is the address encoded as hex\n */\nexport const encodeRoyaltyPart = (\n royaltyPart: UniqueRoyaltyPartToEncode,\n): string => {\n const part = parseRoyaltyPart(royaltyPart)\n\n const version = part.version.toString(16).padStart(2, '0')\n const royaltyType = part.royaltyType === RoyaltyType.DEFAULT ? '0' : '1'\n const decimals = part.decimals.toString(16).padStart(2, '0')\n\n const value = part.value.toString(16).padStart(16, '0')\n\n const [isEthereum, address] = encodeAddress(part.address)\n const addressType = isEthereum ? '0' : '1'\n\n return `0x${version}${get42Zeros()}${royaltyType}${addressType}${decimals}${value}${address}`\n}\n\nexport const encodeRoyalties = (\n parts: UniqueRoyaltyPartToEncode[],\n): string =>\n '0x' + parts.map((part) => encodeRoyaltyPart(part).substring(2)).join('')\n\n\nexport const encodeRoyaltyFromV2 = (royalties: IV2Royalty[]) => {\n const royaltiesToEncode = royalties.map((royalty) => {\n const {address, percent, isPrimaryOnly} = royalty;\n const valueInPercent = percent * 100\n\n // if valueInPercent is not integer\n if (valueInPercent % 1 !== 0) throw new Error('Royalty percent value must has maximum 2 decimal places')\n\n return {\n address,\n value: BigInt(percent * 100),\n decimals: 4,\n royaltyType: isPrimaryOnly ? RoyaltyType.PRIMARY_ONLY : RoyaltyType.DEFAULT,\n version: 1,\n } satisfies UniqueRoyaltyPart\n })\n\n return encodeRoyalties(royaltiesToEncode)\n}\n","import {UniqueRoyaltyPart, UniqueRoyaltyPartToEncode} from './types'\n\nexport * from './types'\n\nimport * as calculation from './calculation'\nimport * as decoding from './decoding'\nimport * as encoding from './encoding'\nimport * as utils from './utils'\nimport {parseRoyalties, parseRoyaltyPart} from './utils'\nimport {encodeRoyaltyFromV2} from './encoding'\n\nexport const Royalties = {\n part: {\n calculate: calculation.calculateRoyaltyPart,\n decode: decoding.decodeRoyaltyPart,\n encode: encoding.encodeRoyaltyPart,\n validate: (part: UniqueRoyaltyPartToEncode): part is UniqueRoyaltyPart => {\n parseRoyaltyPart(part)\n return true\n },\n },\n calculate: calculation.calculateRoyalties,\n decode: decoding.decodeRoyalties,\n encode: encoding.encodeRoyalties,\n validate: (royalties: UniqueRoyaltyPartToEncode[]): royalties is UniqueRoyaltyPart[] => {\n parseRoyalties(royalties)\n return true\n },\n uniqueV2: {\n decode: decoding.decodeRoyaltyToV2,\n encode: encoding.encodeRoyaltyFromV2,\n },\n utils,\n}\n"],"mappings":"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","names":["RoyaltyType","encoded"]}