import { Multiasset } from "../assets"; import { CborByte } from "./byte"; import { CborInteger } from "./integer"; import { CborMultiasset } from "./multiasset"; import { CborSet } from "./set"; import { CborUnsigned } from "./unsigned"; import { CborTransaction } from "./transaction"; import { CborMetadata } from "./metadata"; import { CborText } from "./text"; import { CborArray } from "./array"; import { CborSignedData } from "./signedData"; export type CborEncoded = { data: T; encoded: string; }; const read = (value: string, start: number = 0) => { return value.substring(start, start + 2); }; const countItemsUntilBreak = (value: string) => { let foundBreak = false; let itemsCount = 0; let cursor = 0; while (!foundBreak) { if (read(value).toLowerCase() === "ff") { return itemsCount; } cursor += readNextItemStringLength(value.substring(cursor)); itemsCount++; } return itemsCount; }; const INTEGER_IDENTIFIERS = Array.from(Array(24)).map((v, i) => i.toString(16).padStart(2, "0") ); const UNSIGNED_INTEGER_IDENTIFIERS = ["18", "19", "1a", "1b"]; const identifyType = (value: string) => { if (value.charAt(0) === "8" || value.charAt(0).toLowerCase() === "9") { return "array"; } else if ( value.charAt(0).toLowerCase() === "a" || value.charAt(0).toLowerCase() === "b" ) { return "set"; } else if ( INTEGER_IDENTIFIERS.includes(value.substring(0, 2).toLowerCase()) ) { return "integer"; } else if ( UNSIGNED_INTEGER_IDENTIFIERS.includes(value.substring(0, 2).toLowerCase()) ) { return "unsigned"; } else if (value.charAt(0) === "4" || value.charAt(0) === "5") { return "byte"; } else if (value.charAt(0) === "6" || value.charAt(0) === "7") { return "text"; } else if ( value.substring(0, 2).toLowerCase() === "f4" || value.substring(0, 2).toLowerCase() === "f5" || ["1", "2"].includes(value.charAt(0)) // TODO: This is not really a negative, it's a negative sign ) { return "primitive"; } else { console.log("Unknown value", value); return "unknown"; } }; const readNextItemStringLength = (value: string) => { const readSetStringLength = (mapValue: string) => { if (identifyType(mapValue) !== "set") throw "Not a set"; const mapSize = CborSet.readSize(mapValue); let cursor = CborSet.getFirstValueCharIndex(mapValue); for (let i = 0; i < mapSize * 2; i++) { const value = mapValue.substring(cursor); const length = readNextItemStringLength(value); cursor += length; } return cursor; }; const readIntegerStringLength = (value: string) => { const integerType = identifyType(value); const byteValue = value.substring(0, 2); if (integerType === "integer") { return 2; // Type is the integer itself } else if (integerType === "unsigned") { switch (byteValue) { case "18": return 4; case "19": return 6; case "1a": return 10; case "1b": return 18; default: throw "Invalid unsigned integer"; } } else { throw "Not an integer"; } }; const readArrayStringLength = (value: string) => { if (identifyType(value) !== "set") throw "Not a set"; const mapSize = CborSet.readSize(value); let cursor = 2; for (let i = 0; i < mapSize; i++) { const item = value.substring(cursor); cursor += readNextItemStringLength(item); } return cursor; }; const type = identifyType(value); if (type === "array") { return readArrayStringLength(value); } else if (type === "set") { return readSetStringLength(value); } else if (type === "integer" || type === "unsigned") { return readIntegerStringLength(value); } else if (type === "byte") { return CborByte.getLength(value); } else if (type === "text") { return CborText.getLength(value); } else if (type === "primitive") { return 2; } else { console.log(value); throw new Error(`Unable to determine length ${value}`); } }; const encodePlutusScript = (contract: string): CborEncoded => { return { data: contract, encoded: CborByte.encode(contract), }; }; const encodeValue = (value: number | [number, Multiasset]) => { if (typeof value === "number") { return CborUnsigned.encode(value); } else { return value[0] > 0 ? CborMultiasset.encode(value[1], value[0]) : CborMultiasset.encode(value[1]); } }; const lovelaceToCBOR = (value: number) => { return CborUnsigned.encode(value); }; const getExUnits = (mem: number, steps: number) => { return `82${CborUnsigned.encode(mem)}${CborUnsigned.encode(steps)}`; }; const Cbor = { read, readNextItemStringLength, countItemsUntilBreak, identifyType, encodePlutusScript, lovelaceToCBOR, getExUnits, encodeValue, }; export { Cbor, CborByte, CborUnsigned, CborSet, CborInteger, CborTransaction, CborMultiasset, CborMetadata, CborArray, CborSignedData, };