UNPKG

@btc-vision/transaction

Version:

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

128 lines (107 loc) 4.02 kB
import { crypto, Network, networks, opcodes, script } from '@btc-vision/bitcoin'; import { Generator } from '../Generator.js'; import { Feature, Features } from '../Features.js'; import { ChallengeSolution } from '../../epoch/ChallengeSolution.js'; export const OPNET_DEPLOYMENT_VERSION = 0x00; export const versionBuffer = Buffer.from([OPNET_DEPLOYMENT_VERSION]); export class DeploymentGenerator extends Generator { constructor( senderPubKey: Buffer, contractSaltPubKey: Buffer, network: Network = networks.bitcoin, ) { super(senderPubKey, contractSaltPubKey, network); } /** * Compile a bitcoin script representing a contract deployment * @param {Buffer} contractBytecode - The contract bytecode * @param {Buffer} contractSalt - The contract salt * @param {ChallengeSolution} challenge - The challenge for reward * @param {bigint} maxPriority - The maximum priority for the contract * @param {Buffer} [calldata] - The calldata to be passed to the contract * @param {Feature<Features>[]} [features] - Optional features to include in the script * @returns {Buffer} - The compiled script */ public compile( contractBytecode: Buffer, contractSalt: Buffer, challenge: ChallengeSolution, maxPriority: bigint, calldata?: Buffer, features?: Feature<Features>[], ): Buffer { const asm = this.getAsm( contractBytecode, contractSalt, challenge, maxPriority, calldata, features, ); const compiled = script.compile(asm); /** * Verify that the script can be decompiled */ const decompiled = script.decompile(compiled); if (!decompiled) { throw new Error('Failed to decompile script??'); } return compiled; } private getAsm( contractBytecode: Buffer, contractSalt: Buffer, challenge: ChallengeSolution, maxPriority: bigint, calldata?: Buffer, features?: Feature<Features>[], ): (number | Buffer)[] { if (!this.contractSaltPubKey) throw new Error('Contract salt public key not set'); const dataChunks: Buffer[][] = this.splitBufferIntoChunks(contractBytecode); const calldataChunks: Buffer[][] = calldata ? this.splitBufferIntoChunks(calldata) : []; const featuresList: Features[] = []; const featureData: (number | Buffer | Buffer[])[] = []; if (features) { for (let i = 0; i < features.length; i++) { const feature = features[i]; featuresList.push(feature.opcode); const data = this.encodeFeature(feature); featureData.push(...data); } } const compiledData = [ this.getHeader(maxPriority, featuresList), opcodes.OP_TOALTSTACK, // CHALLENGE PREIMAGE FOR REWARD, challenge.publicKey.originalPublicKeyBuffer(), opcodes.OP_TOALTSTACK, challenge.solution, opcodes.OP_TOALTSTACK, this.xSenderPubKey, opcodes.OP_DUP, opcodes.OP_HASH256, crypto.hash256(this.xSenderPubKey), opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIGVERIFY, this.contractSaltPubKey, opcodes.OP_CHECKSIGVERIFY, opcodes.OP_HASH256, crypto.hash256(contractSalt), opcodes.OP_EQUALVERIFY, opcodes.OP_DEPTH, opcodes.OP_1, opcodes.OP_NUMEQUAL, opcodes.OP_IF, Generator.MAGIC, ...featureData, opcodes.OP_0, ...calldataChunks, opcodes.OP_1NEGATE, ...dataChunks, opcodes.OP_ELSE, opcodes.OP_1, opcodes.OP_ENDIF, ]; return compiledData.flat(); } }