UNPKG

@btc-vision/transaction

Version:

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

143 lines 5.36 kB
import { alloc, fromUtf8, networks, toXOnly, } from '@btc-vision/bitcoin'; import { BinaryWriter } from '../buffer/BinaryWriter.js'; import { Features, } from './Features.js'; import { Address } from '../keypair/Address.js'; import { Compressor } from '../bytecode/Compressor.js'; /** Bitcoin Script Generator */ export class Generator { /** * The maximum size of a data chunk */ static DATA_CHUNK_SIZE = 512; /** * The magic number of OPNet */ static MAGIC = fromUtf8('op'); /** * The public key of the sender * @protected */ senderPubKey; /** * The public key of the sender * @protected */ xSenderPubKey; /** * The public key of the contract salt * @protected */ contractSaltPubKey; /** * The network to use * @protected */ network = networks.bitcoin; constructor(senderPubKey, contractSaltPubKey, network = networks.bitcoin) { this.senderPubKey = senderPubKey; this.contractSaltPubKey = contractSaltPubKey; this.network = network; this.xSenderPubKey = toXOnly(senderPubKey); } buildHeader(features) { let flags = 0; for (const feature of features) { flags |= feature; } const bytesU24 = alloc(3); bytesU24[0] = (flags >> 16) & 0xff; bytesU24[1] = (flags >> 8) & 0xff; bytesU24[2] = flags & 0xff; return Uint8Array.from([this.senderPubKey[0], ...bytesU24]); } getHeader(maxPriority, features = []) { const writer = new BinaryWriter(12); writer.writeBytes(this.buildHeader(features)); writer.writeU64(maxPriority); return new Uint8Array(writer.getBuffer()); } /** * Split a buffer into chunks * @param {Uint8Array} buffer - The buffer to split * @param {number} chunkSize - The size of each chunk * @protected * @returns {Array<Uint8Array[]>} - The chunks */ splitBufferIntoChunks(buffer, chunkSize = Generator.DATA_CHUNK_SIZE) { const chunks = []; for (let i = 0; i < buffer.length; i += chunkSize) { const dataLength = Math.min(chunkSize, buffer.length - i); const buf2 = alloc(dataLength); for (let j = 0; j < dataLength; j++) { buf2[j] = buffer[i + j]; } chunks.push([buf2]); } return chunks; } encodeFeature(feature, finalBuffer) { switch (feature.opcode) { case Features.ACCESS_LIST: { return this.encodeAccessListFeature(feature, finalBuffer); } case Features.EPOCH_SUBMISSION: { return this.encodeChallengeSubmission(feature, finalBuffer); } case Features.MLDSA_LINK_PUBKEY: { return this.encodeLinkRequest(feature, finalBuffer); } default: throw new Error(`Unknown feature type: ${feature.opcode}`); } } encodeAccessListFeature(feature, finalBuffer) { const writer = new BinaryWriter(); writer.writeU16(Object.keys(feature.data).length); for (const contract in feature.data) { const parsedContract = Address.fromString(contract); const data = feature.data[contract]; writer.writeAddress(parsedContract); writer.writeU32(data.length); for (const pointer of data) { const pointerBuffer = Uint8Array.from(atob(pointer), (c) => c.charCodeAt(0)); if (pointerBuffer.length !== 32) { throw new Error(`Invalid pointer length: ${pointerBuffer.length}`); } writer.writeBytes(pointerBuffer); } } finalBuffer.writeBytesWithLength(Compressor.compress(new Uint8Array(writer.getBuffer()))); } encodeChallengeSubmission(feature, finalBuffer) { if ('verifySignature' in feature.data && !feature.data.verifySignature()) { throw new Error('Invalid signature in challenge submission feature'); } const writer = new BinaryWriter(); writer.writeBytes(feature.data.publicKey.toBuffer()); writer.writeBytes(feature.data.solution); if (feature.data.graffiti) { writer.writeBytesWithLength(feature.data.graffiti); } finalBuffer.writeBytesWithLength(writer.getBuffer()); } encodeLinkRequest(feature, finalBuffer) { const data = feature.data; const writer = new BinaryWriter(); writer.writeU8(data.level); writer.writeBytes(data.hashedPublicKey); writer.writeBoolean(data.verifyRequest); if (data.verifyRequest) { if (!data.publicKey || !data.mldsaSignature) { throw new Error('MLDSA public key and signature required when verifyRequest is true'); } writer.writeBytes(data.publicKey); writer.writeBytes(data.mldsaSignature); } if (!data.legacySignature || data.legacySignature.length !== 64) { throw new Error('Legacy signature must be exactly 64 bytes'); } writer.writeBytes(data.legacySignature); finalBuffer.writeBytesWithLength(writer.getBuffer()); } } //# sourceMappingURL=Generator.js.map