"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Sequence = void 0;
const TimeLockMode_1 = require("./TimeLockMode");
const MAX_SEQUENCE = 4294967295;
const DEFAULT_SEQUENCE = 4294967295;
/**
 * A transaction input's nSequence field according to BIP 68 where
 * rules for relative timelocks are defined. Relative timelocks prevent
 * mining of a transaction until a certain age of the spent output
 * in blocks or timespan.
 *
 * nSequence defaults to a value of 0xffff_ffff which disables the field.
 * When using a nLocktime, at least one transaction must be non-default.
 * In this condition, it is standard to use 0xffff_fffe.
 */
class Sequence {
    /**
     * Parses the value from a byte stream
     * @param reader
     */
    static parse(reader) {
        return new Sequence(reader.readUInt32LE());
    }
    /**
     * Creates an nSequence value of 0xffff_fffe which is used to enable
     * nLockTime.
     */
    static locktime() {
        return new Sequence(4294967294);
    }
    /**
     * Creates an nSequence value of 0xffff_fffd which is used to
     * enable opt-in full replace-by-fee.
     */
    static rbf() {
        return new Sequence(4294967293);
    }
    /**
     * Creates an nSequence value of 0xffff_ffff
     */
    static default() {
        return new Sequence();
    }
    /**
     * Creates an nSequence value of 0
     */
    static zero() {
        return new Sequence(0);
    }
    /**
     * Creates an nSequence value with the specified block delay
     * @param blocks number of blocks sequence must wait
     */
    static blockDelay(blocks) {
        const sut = new Sequence();
        sut.blockDelay = blocks;
        return sut;
    }
    /**
     * Creates an nSequence value with the specified time delay
     * @param seconds delay in seconds which will be rounded up to the
     * nearest 512 second interval
     */
    static timeDelay(seconds) {
        const sut = new Sequence();
        sut.timeDelay = seconds;
        return sut;
    }
    /**
     * Gets or sets the raw nSequence value.
     */
    get value() {
        return this._value;
    }
    set value(val) {
        if (val < 0 || val > MAX_SEQUENCE)
            throw new Error('Invalid nSequence');
        this._value = val;
    }
    constructor(val = DEFAULT_SEQUENCE) {
        this.value = val;
    }
    /**
     * Returns true when the nSequence is the default value 0xffff_ffff
     */
    get isDefault() {
        return this.value === DEFAULT_SEQUENCE;
    }
    /**
     * Returns true when the relative timelock is enabled. Technically
     * this occurs when the top-most bit is unset. This means that the
     * default value of 0xffff_ffff is unset.
     */
    get enabled() {
        return BigInt(this.value) >> BigInt(31) === BigInt(0);
    }
    /**
     * Returns true for a value that would enable nLockTime. To enable
     * nLockTime, at least one input in the transaction must have a
     * non-default nSequence value.
     */
    get isLockTimeSignaled() {
        return this.value < DEFAULT_SEQUENCE;
    }
    /**
     * Returns true for a value that would signal opt-in replace-by-fee
     * as defined in BIP 125. To signal this, the nSequence must be less
     * than 0xffffffff-1.
     */
    get isRBFSignaled() {
        return this.value < DEFAULT_SEQUENCE - 1;
    }
    /**
     * Gets the time lock mode for the nSequence. Technically, the bit
     * with index 22 controls the mode. When the bit is set, it will use
     * time-based relative time locks. When it is unset, it will use
     * block-based relatively time locks.
     */
    get mode() {
        if (this.value >> 22 === 1)
            return TimeLockMode_1.TimeLockMode.Time;
        else
            return TimeLockMode_1.TimeLockMode.Block;
    }
    /**
     * Gets or sets a relative timelock in seconds. Time-based relative
     * time locks are encoded in 512 second granularity which is close
     * to the 600 seconds each block should be generated in. When
     * setting a value in seconds, it will rounded up to the nearest
     * 512s granularity.
     */
    get timeDelay() {
        return (this.value & 0xffff) * 512;
    }
    set timeDelay(seconds) {
        // calculate the delay in 512 second granularity
        let value = Math.ceil(seconds / 512);
        // if the value execeeds the max value, throw an error
        if (value < 0 || value > 0xffff)
            throw new Error('Invalid nSequence value');
        // set the typeto time-based relatively timelock
        value |= 1 << 22;
        // set the actual value
        this.value = value;
    }
    /**
     * Gets or set a relative timelock in blocks.
     */
    get blockDelay() {
        return this.value & 0xffff;
    }
    set blockDelay(blocks) {
        // if the value exceeds the max value, throw an error
        if (blocks < 0 || blocks > 0xffff)
            throw new Error('Invalid nSequence value');
        this.value = blocks;
    }
    /**
     * Serializes the value to a buffer
     */
    serialize() {
        const buf = Buffer.alloc(4);
        buf.writeUInt32LE(this.value, 0);
        return buf;
    }
    /**
     * Returns the raw value as a hex encoded string, eg: 0xfffffffe
     */
    toString() {
        return '0x' + this.value.toString(16).padStart(8, '0');
    }
    /**
     * Returns the raw value as a hex encoded string, eg: 0xfffffffe
     */
    toJSON() {
        return this.toString();
    }
    /**
     * Clone via deep copy
     */
    clone() {
        return new Sequence(this._value);
    }
}
exports.Sequence = Sequence;
//# sourceMappingURL=Sequence.js.map