UNPKG

@btc-vision/transaction

Version:

OPNet transaction library allows you to create and sign transactions for the OPNet network.

244 lines (243 loc) 7.77 kB
import { AddressMap } from '../deterministic/AddressMap.js'; import { Address } from '../keypair/Address.js'; import { ADDRESS_BYTE_LENGTH, I128_BYTE_LENGTH, U128_BYTE_LENGTH, U16_BYTE_LENGTH, U256_BYTE_LENGTH, U32_BYTE_LENGTH, U64_BYTE_LENGTH, U8_BYTE_LENGTH, } from '../utils/lengths.js'; export class BinaryReader { constructor(bytes) { this.currentOffset = 0; this.buffer = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); } static stringCompare(a, b) { return a.localeCompare(b); } static bigintCompare(a, b) { if (a < b) return -1; if (a > b) return 1; return 0; } static numberCompare(a, b) { if (a < b) return -1; if (a > b) return 1; return 0; } setBuffer(bytes) { this.buffer = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); this.currentOffset = 0; } length() { return this.buffer.byteLength; } bytesLeft() { return this.buffer.byteLength - this.currentOffset; } readU8() { this.verifyEnd(this.currentOffset + U8_BYTE_LENGTH); const value = this.buffer.getUint8(this.currentOffset); this.currentOffset += U8_BYTE_LENGTH; return value; } readU16(be = true) { this.verifyEnd(this.currentOffset + U16_BYTE_LENGTH); const value = this.buffer.getUint16(this.currentOffset, !be); this.currentOffset += U16_BYTE_LENGTH; return value; } readU32(be = true) { this.verifyEnd(this.currentOffset + U32_BYTE_LENGTH); const value = this.buffer.getUint32(this.currentOffset, !be); this.currentOffset += U32_BYTE_LENGTH; return value; } readU64(be = true) { this.verifyEnd(this.currentOffset + U64_BYTE_LENGTH); const value = this.buffer.getBigUint64(this.currentOffset, !be); this.currentOffset += U64_BYTE_LENGTH; return value; } readU128(be = true) { const raw = this.readBytes(U128_BYTE_LENGTH); let bytes = raw; if (!be) { bytes = this.reverseBytes(raw); } return BigInt('0x' + this.toHexString(bytes)); } readU256(be = true) { const raw = this.readBytes(U256_BYTE_LENGTH); let bytes = raw; if (!be) { bytes = this.reverseBytes(raw); } return BigInt('0x' + this.toHexString(bytes)); } readI128(be = true) { const raw = this.readBytes(I128_BYTE_LENGTH); let bytes = raw; if (!be) { bytes = this.reverseBytes(raw); } let value = BigInt('0x' + this.toHexString(bytes)); const signBitMask = 0x80; if (bytes[0] & signBitMask) { const twoTo128 = BigInt(1) << BigInt(128); value = value - twoTo128; } return value; } readBoolean() { return this.readU8() !== 0; } readSelector() { return this.readU32(true); } readBytes(length, zeroStop = false) { this.verifyEnd(this.currentOffset + length); let bytes = new Uint8Array(length); for (let i = 0; i < length; i++) { const b = this.buffer.getUint8(this.currentOffset++); if (zeroStop && b === 0) { bytes = bytes.subarray(0, i); break; } bytes[i] = b; } return bytes; } readString(length) { const textDecoder = new TextDecoder(); const bytes = this.readBytes(length, false); return textDecoder.decode(bytes); } readStringWithLength(be = true) { const length = this.readU32(be); return this.readString(length); } readAddress() { const bytes = Array.from(this.readBytes(ADDRESS_BYTE_LENGTH)); return new Address(bytes); } readBytesWithLength(maxLength = 0, be = true) { const length = this.readU32(be); if (maxLength > 0 && length > maxLength) { throw new Error('Data length exceeds maximum length.'); } return this.readBytes(length); } readArrayOfBuffer(be = true) { const length = this.readU16(be); const result = new Array(length); for (let i = 0; i < length; i++) { result[i] = this.readBytesWithLength(); } return result; } readAddressArray(be = true) { const length = this.readU16(be); const result = new Array(length); for (let i = 0; i < length; i++) { result[i] = this.readAddress(); } return result; } readU256Array(be = true) { const length = this.readU16(be); const result = new Array(length); for (let i = 0; i < length; i++) { result[i] = this.readU256(be); } return result; } readU128Array(be = true) { const length = this.readU16(be); const result = new Array(length); for (let i = 0; i < length; i++) { result[i] = this.readU128(be); } return result; } readU64Array(be = true) { const length = this.readU16(be); const result = new Array(length); for (let i = 0; i < length; i++) { result[i] = this.readU64(be); } return result; } readU32Array(be = true) { const length = this.readU16(be); const result = new Array(length); for (let i = 0; i < length; i++) { result[i] = this.readU32(be); } return result; } readU16Array(be = true) { const length = this.readU16(be); const result = new Array(length); for (let i = 0; i < length; i++) { result[i] = this.readU16(be); } return result; } readU8Array() { const length = this.readU16(true); const result = new Array(length); for (let i = 0; i < length; i++) { result[i] = this.readU8(); } return result; } readStringArray(be = true) { const length = this.readU16(be); const result = new Array(length); for (let i = 0; i < length; i++) { result[i] = this.readStringWithLength(be); } return result; } readBytesArray(be = true) { const length = this.readU16(be); const result = new Array(length); for (let i = 0; i < length; i++) { result[i] = this.readBytesWithLength(0, be); } return result; } readAddressValueTuple(be = true) { const length = this.readU16(be); const result = new AddressMap(); for (let i = 0; i < length; i++) { const address = this.readAddress(); const value = this.readU256(be); if (result.has(address)) { throw new Error('Duplicate address found in map'); } result.set(address, value); } return result; } getOffset() { return this.currentOffset; } setOffset(offset) { this.currentOffset = offset; } verifyEnd(size) { if (size > this.buffer.byteLength) { throw new Error(`Attempt to read beyond buffer length: requested up to byte offset ${size}, but buffer is only ${this.buffer.byteLength} bytes.`); } } reverseBytes(bytes) { const out = new Uint8Array(bytes.length); for (let i = 0; i < bytes.length; i++) { out[i] = bytes[bytes.length - 1 - i]; } return out; } toHexString(bytes) { return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join(''); } }