UNPKG

lotus-sdk

Version:

Central repository for several classes of tools for integrating with, and building for, the Lotusia ecosystem

232 lines (231 loc) 7.12 kB
import { Preconditions } from '../util/preconditions.js'; import { BitcoreError } from '../errors.js'; import { BufferWriter } from '../encoding/bufferwriter.js'; import { JSUtil } from '../util/js.js'; import { Script } from '../script.js'; import { BN } from '../crypto/bn.js'; const MAX_SAFE_INTEGER = 0x1fffffffffffff; export class Output { satoshis; _satoshisBN; _scriptBuffer; _script; constructor(args) { if (typeof args === 'object' && args !== null) { if (args.satoshis !== undefined) { this.satoshis = this._parseSatoshis(args.satoshis); } else { this.satoshis = 0; this._satoshisBN = new BN(0); } if (Buffer.isBuffer(args.script)) { this._scriptBuffer = args.script; } else if (args.scriptBuffer !== undefined) { this._scriptBuffer = args.scriptBuffer; } else if (args.script !== undefined) { this.setScript(args.script); } else { this._scriptBuffer = Buffer.alloc(0); } } else { throw new TypeError('Unrecognized argument for Output'); } } static create(args) { return new Output(args); } _parseSatoshis(value) { if (value instanceof BN) { this._satoshisBN = value; return value.toNumber(); } else if (typeof value === 'string') { const num = parseInt(value); Preconditions.checkArgument(JSUtil.isNaturalNumber(num), 'Output satoshis is not a natural number'); this._satoshisBN = new BN(num); return num; } else if (typeof value === 'bigint') { const num = Number(value); Preconditions.checkArgument(JSUtil.isNaturalNumber(num), 'Output satoshis is not a natural number'); this._satoshisBN = new BN(num); return num; } else { Preconditions.checkArgument(JSUtil.isNaturalNumber(value), 'Output satoshis is not a natural number'); this._satoshisBN = new BN(value); return value; } } get satoshisBN() { return this._satoshisBN; } set satoshisBN(value) { this._satoshisBN = value; this.satoshis = value.toNumber(); Preconditions.checkState(JSUtil.isNaturalNumber(this.satoshis), 'Output satoshis is not a natural number'); } get script() { if (this._script) { return this._script; } else { this.setScriptFromBuffer(this._scriptBuffer); return this._script; } } get scriptBuffer() { return this._scriptBuffer; } setScriptFromBuffer(buffer) { this._scriptBuffer = buffer; try { this._script = Script.fromBuffer(this._scriptBuffer); this._script._isOutput = true; } catch (e) { if (e instanceof BitcoreError.Script.InvalidBuffer) { this._script = undefined; } else { throw e; } } } setScript(script) { if (script instanceof Script) { this._scriptBuffer = script.toBuffer(); this._script = script; this._script._isOutput = true; } else if (typeof script === 'string') { this._script = Script.fromString(script); this._scriptBuffer = this._script.toBuffer(); this._script._isOutput = true; } else if (Buffer.isBuffer(script)) { this.setScriptFromBuffer(script); } else { throw new TypeError('Invalid argument type: script'); } return this; } getXPI() { return this.satoshis / 1000000; } setXPI(xpi) { this.satoshis = Math.round(xpi * 1000000); this._satoshisBN = new BN(this.satoshis); return this; } isValid() { return (this.satoshis >= 0 && this.satoshis <= 21000000 * 1000000 && this._scriptBuffer.length > 0); } isDust(dustThreshold = 546) { return this.satoshis < dustThreshold; } invalidSatoshis() { if (this.satoshis > MAX_SAFE_INTEGER) { return 'transaction txout satoshis greater than max safe integer'; } if (this.satoshis !== this._satoshisBN.toNumber()) { return 'transaction txout satoshis has corrupted value'; } if (this.satoshis < 0) { return 'transaction txout negative'; } return false; } isOpReturn() { if (!this._script) { this.setScriptFromBuffer(this._scriptBuffer); } return !!(this._script && this._script.chunks.length > 0 && this._script.chunks[0].opcodenum === 0x6a); } toObject() { return { satoshis: this.satoshis, script: this._scriptBuffer.toString('hex'), asm: this.script.toASM(), }; } toJSON = this.toObject; inspect() { let scriptStr; if (this.script) { scriptStr = this.script.inspect(); } else { scriptStr = this._scriptBuffer.toString('hex'); } return '<Output (' + this.satoshis + ' sats) ' + scriptStr + '>'; } static fromBufferReader(br) { const obj = {}; obj.satoshis = br.readUInt64LEBN(); const size = br.readVarintNum(); if (size !== 0) { obj.script = br.read(size); } else { obj.script = Buffer.from([]); } return new Output(obj); } toBuffer() { const bw = new BufferWriter(); bw.writeUInt64LEBN(this._satoshisBN); bw.writeVarintNum(this._scriptBuffer.length); bw.write(this._scriptBuffer); return bw.concat(); } toBufferWriter(writer) { if (!writer) { writer = new BufferWriter(); } writer.writeUInt64LEBN(this._satoshisBN); const script = this._scriptBuffer; writer.writeVarintNum(script.length); writer.write(script); return writer; } getSize() { return (8 + BufferWriter.varintBufNum(this._scriptBuffer.length).length + this._scriptBuffer.length); } clone() { return new Output({ satoshis: this.satoshis, script: this.script.clone(), }); } static fromObject(data) { return new Output(data); } isPayToPublicKeyHash() { return this.script.isPayToPublicKeyHash(); } isPayToScriptHash() { return this.script.isPayToScriptHash(); } getAddress() { try { const addressInfo = this.script.getAddressInfo(); return addressInfo ? addressInfo.toString() : null; } catch (e) { return null; } } }