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
JavaScript
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;
}
}
}