# All files Sequence.ts

9.3% Statements 4/43
0% Branches 0/15
0% Functions 0/23
10% Lines 4/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212

    1x

    1x
    1x

    1x

     import { StreamReader } from '@node-dlc/bufio';

    import { ICloneable } from './ICloneable';
    import { TimeLockMode } from './TimeLockMode';

    const MAX_SEQUENCE = 0xffff_ffff;
    const DEFAULT_SEQUENCE = 0xffff_ffff;

    /**
     * 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.
     */
    export class Sequence implements ICloneable<Sequence> {
      /**
       * Parses the value from a byte stream
       * @param reader
       */
      public static parse(reader: StreamReader): Sequence {
        return new Sequence(reader.readUInt32LE());
      }

      /**
       * Creates an nSequence value of 0xffff_fffe which is used to enable
       * nLockTime.
       */
      public static locktime(): Sequence {
        return new Sequence(0xffff_fffe);
      }

      /**
       * Creates an nSequence value of 0xffff_fffd which is used to
       * enable opt-in full replace-by-fee.
       */
      public static rbf(): Sequence {
        return new Sequence(0xffff_fffd);
      }

      /**
       * Creates an nSequence value of 0xffff_ffff
       */
      public static default(): Sequence {
        return new Sequence();
      }

      /**
       * Creates an nSequence value of 0
       */
      public static zero(): Sequence {
        return new Sequence(0);
      }

      /**
       * Creates an nSequence value with the specified block delay
       * @param blocks number of blocks sequence must wait
       */
      public static blockDelay(blocks: number): Sequence {
        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
       */
      public static timeDelay(seconds: number): Sequence {
        const sut = new Sequence();
        sut.timeDelay = seconds;
        return sut;
      }

      /**
       * Gets or sets the raw nSequence value.
       */
      public get value(): number {
        return this._value;
      }

      public set value(val: number) {
        if (val < 0 || val > MAX_SEQUENCE) throw new Error('Invalid nSequence');
        this._value = val;
      }

      private _value: number;

      constructor(val: number = DEFAULT_SEQUENCE) {
        this.value = val;
      }

      /**
       * Returns true when the nSequence is the default value 0xffff_ffff
       */
      public get isDefault(): boolean {
        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.
       */
      public get enabled(): boolean {
        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.
       */
      public get isLockTimeSignaled(): boolean {
        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.
       */
      public get isRBFSignaled(): boolean {
        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.
       */
      public get mode(): TimeLockMode {
        if (this.value >> 22 === 1) return TimeLockMode.Time;
        else return 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.
       */
      public get timeDelay(): number {
        return (this.value & 0xffff) * 512;
      }

      public set timeDelay(seconds: number) {
        // 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.
       */
      public get blockDelay(): number {
        return this.value & 0xffff;
      }

      public set blockDelay(blocks: number) {
        // 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
       */
      public serialize(): Buffer {
        const buf = Buffer.alloc(4);
        buf.writeUInt32LE(this.value, 0);
        return buf;
      }

      /**
       * Returns the raw value as a hex encoded string, eg: 0xfffffffe
       */
      public toString(): string {
        return '0x' + this.value.toString(16).padStart(8, '0');
      }

      /**
       * Returns the raw value as a hex encoded string, eg: 0xfffffffe
       */
      public toJSON(): string {
        return this.toString();
      }

      /**
       * Clone via deep copy
       */
      public clone(): Sequence {
        return new Sequence(this._value);
      }
    }