115 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { Component, ChangeDetectionStrategy, Input, OnChanges } from '@angular/core';
 | 
						|
import { Vin, Vout } from '../../interfaces/electrs.interface';
 | 
						|
import { StateService } from '../../services/state.service';
 | 
						|
import { parseMultisigScript } from '../../bitcoin.utils';
 | 
						|
 | 
						|
@Component({
 | 
						|
  selector: 'app-address-labels',
 | 
						|
  templateUrl: './address-labels.component.html',
 | 
						|
  styleUrls: ['./address-labels.component.scss'],
 | 
						|
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
						|
})
 | 
						|
export class AddressLabelsComponent implements OnChanges {
 | 
						|
  network = '';
 | 
						|
 | 
						|
  @Input() vin: Vin;
 | 
						|
  @Input() vout: Vout;
 | 
						|
  @Input() channel: any;
 | 
						|
 | 
						|
  label?: string;
 | 
						|
 | 
						|
  constructor(
 | 
						|
    stateService: StateService,
 | 
						|
  ) {
 | 
						|
    this.network = stateService.network;
 | 
						|
  }
 | 
						|
 | 
						|
  ngOnChanges() {
 | 
						|
    if (this.channel) {
 | 
						|
      this.handleChannel();
 | 
						|
    } else if (this.vin) {
 | 
						|
      this.handleVin();
 | 
						|
    } else if (this.vout) {
 | 
						|
      this.handleVout();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  handleChannel() {
 | 
						|
    const type = this.vout ? 'open' : 'close';
 | 
						|
    const leftNodeName = this.channel.node_left.alias || this.channel.node_left.public_key.substring(0, 10);
 | 
						|
    const rightNodeName = this.channel.node_right.alias || this.channel.node_right.public_key.substring(0, 10);
 | 
						|
    this.label = `Channel ${type}: ${leftNodeName} <> ${rightNodeName}`;
 | 
						|
  }
 | 
						|
 | 
						|
  handleVin() {
 | 
						|
    if (this.vin.inner_witnessscript_asm) {
 | 
						|
      if (this.vin.inner_witnessscript_asm.indexOf('OP_DEPTH OP_PUSHNUM_12 OP_EQUAL OP_IF OP_PUSHNUM_11') === 0) {
 | 
						|
        if (this.vin.witness.length > 11) {
 | 
						|
          this.label = 'Liquid Peg Out';
 | 
						|
        } else {
 | 
						|
          this.label = 'Emergency Liquid Peg Out';
 | 
						|
        }
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      const topElement = this.vin.witness[this.vin.witness.length - 2];
 | 
						|
      if (/^OP_IF OP_PUSHBYTES_33 \w{66} OP_ELSE OP_PUSH(NUM_\d+|BYTES_(1 \w{2}|2 \w{4})) OP_CSV OP_DROP OP_PUSHBYTES_33 \w{66} OP_ENDIF OP_CHECKSIG$/.test(this.vin.inner_witnessscript_asm)) {
 | 
						|
        // https://github.com/lightning/bolts/blob/master/03-transactions.md#commitment-transaction-outputs
 | 
						|
        if (topElement === '01') {
 | 
						|
          // top element is '01' to get in the revocation path
 | 
						|
          this.label = 'Revoked Lightning Force Close';
 | 
						|
        } else {
 | 
						|
          // top element is '', this is a delayed to_local output
 | 
						|
          this.label = 'Lightning Force Close';
 | 
						|
        }
 | 
						|
        return;
 | 
						|
      } else if (
 | 
						|
        /^OP_DUP OP_HASH160 OP_PUSHBYTES_20 \w{40} OP_EQUAL OP_IF OP_CHECKSIG OP_ELSE OP_PUSHBYTES_33 \w{66} OP_SWAP OP_SIZE OP_PUSHBYTES_1 20 OP_EQUAL OP_NOTIF OP_DROP OP_PUSHNUM_2 OP_SWAP OP_PUSHBYTES_33 \w{66} OP_PUSHNUM_2 OP_CHECKMULTISIG OP_ELSE OP_HASH160 OP_PUSHBYTES_20 \w{40} OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF (OP_PUSHNUM_1 OP_CSV OP_DROP |)OP_ENDIF$/.test(this.vin.inner_witnessscript_asm) ||
 | 
						|
        /^OP_DUP OP_HASH160 OP_PUSHBYTES_20 \w{40} OP_EQUAL OP_IF OP_CHECKSIG OP_ELSE OP_PUSHBYTES_33 \w{66} OP_SWAP OP_SIZE OP_PUSHBYTES_1 20 OP_EQUAL OP_IF OP_HASH160 OP_PUSHBYTES_20 \w{40} OP_EQUALVERIFY OP_PUSHNUM_2 OP_SWAP OP_PUSHBYTES_33 \w{66} OP_PUSHNUM_2 OP_CHECKMULTISIG OP_ELSE OP_DROP OP_PUSHBYTES_3 \w{6} OP_CLTV OP_DROP OP_CHECKSIG OP_ENDIF (OP_PUSHNUM_1 OP_CSV OP_DROP |)OP_ENDIF$/.test(this.vin.inner_witnessscript_asm)
 | 
						|
      ) {
 | 
						|
        // https://github.com/lightning/bolts/blob/master/03-transactions.md#offered-htlc-outputs
 | 
						|
        // https://github.com/lightning/bolts/blob/master/03-transactions.md#received-htlc-outputs
 | 
						|
        if (topElement.length === 66) {
 | 
						|
          // top element is a public key
 | 
						|
          this.label = 'Revoked Lightning HTLC';
 | 
						|
        } else if (topElement) {
 | 
						|
          // top element is a preimage
 | 
						|
          this.label = 'Lightning HTLC';
 | 
						|
        } else {
 | 
						|
          // top element is '' to get in the expiry of the script
 | 
						|
          this.label = 'Expired Lightning HTLC';
 | 
						|
        }
 | 
						|
        return;
 | 
						|
      } else if (/^OP_PUSHBYTES_33 \w{66} OP_CHECKSIG OP_IFDUP OP_NOTIF OP_PUSHNUM_16 OP_CSV OP_ENDIF$/.test(this.vin.inner_witnessscript_asm)) {
 | 
						|
        // https://github.com/lightning/bolts/blob/master/03-transactions.md#to_local_anchor-and-to_remote_anchor-output-option_anchors
 | 
						|
        if (topElement) {
 | 
						|
          // top element is a signature
 | 
						|
          this.label = 'Lightning Anchor';
 | 
						|
        } else {
 | 
						|
          // top element is '', it has been swept after 16 blocks
 | 
						|
          this.label = 'Swept Lightning Anchor';
 | 
						|
        }
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      this.detectMultisig(this.vin.inner_witnessscript_asm);
 | 
						|
    }
 | 
						|
 | 
						|
    this.detectMultisig(this.vin.inner_redeemscript_asm);
 | 
						|
 | 
						|
    this.detectMultisig(this.vin.prevout.scriptpubkey_asm);
 | 
						|
  }
 | 
						|
 | 
						|
  detectMultisig(script: string) {
 | 
						|
    const ms = parseMultisigScript(script);
 | 
						|
 | 
						|
    if (ms) {
 | 
						|
      this.label = $localize`:@@address-label.multisig:Multisig ${ms.m}:multisigM: of ${ms.n}:multisigN:`;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  handleVout() {
 | 
						|
    this.detectMultisig(this.vout.scriptpubkey_asm);
 | 
						|
  }
 | 
						|
}
 |