PHP WebShell

Текущая директория: /opt/BitGoJS/modules/utxo-staking/src/babylon

Просмотр файла: descriptor.ts

/**
 * https://github.com/babylonlabs-io/babylon/tree/main/docs
 * https://github.com/babylonlabs-io/babylon/blob/main/docs/staking-script.md
 * https://github.com/babylonlabs-io/babylon/blob/v1.99.0-snapshot.250211/btcstaking/staking.go
 */

import { Descriptor, ast } from '@bitgo/wasm-miniscript';
import { StakingParams } from '@bitgo/babylonlabs-io-btc-staking-ts';

export function getUnspendableKey(): string {
  // https://github.com/babylonlabs-io/btc-staking-ts/blob/v0.4.0-rc.2/src/constants/internalPubkey.ts
  return '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0';
}

// Helper functions for creating miniscript nodes
function pk(b: Buffer): ast.MiniscriptNode {
  return { 'v:pk': b.toString('hex') };
}

function sortedKeys(keys: Buffer[]): Buffer[] {
  return [...keys].sort((a, b) => a.compare(b));
}

function multiArgs(threshold: number, keys: Buffer[]): [number, ...string[]] {
  return [threshold, ...sortedKeys(keys).map((k) => k.toString('hex'))];
}

function taprootScriptOnlyFromAst(n: ast.TapTreeNode): Descriptor {
  return Descriptor.fromString(ast.formatNode({ tr: [getUnspendableKey(), n] }), 'definite');
}

export class BabylonDescriptorBuilder {
  constructor(
    public stakerKey: Buffer,
    public finalityProviderKeys: Buffer[],
    public covenantKeys: Buffer[],
    public covenantThreshold: number,
    public stakingTimeLock: number,
    public unbondingTimeLock: number
  ) {}

  static fromParams(
    params: {
      stakerKey: Buffer;
      finalityProviderKeys: Buffer[];
    } & StakingParams
  ): BabylonDescriptorBuilder {
    return new BabylonDescriptorBuilder(
      params.stakerKey,
      params.finalityProviderKeys,
      params.covenantNoCoordPks.map((k) => Buffer.from(k, 'hex')),
      params.covenantQuorum,
      params.minStakingTimeBlocks,
      params.unbondingTime
    );
  }

  getTimelockMiniscript(): ast.MiniscriptNode {
    return { and_v: [pk(this.stakerKey), { older: this.stakingTimeLock }] };
  }

  getUnbondingMiniscript(): ast.MiniscriptNode {
    return { and_v: [pk(this.stakerKey), { multi_a: multiArgs(this.covenantThreshold, this.covenantKeys) }] };
  }

  getSlashingMiniscript(): ast.MiniscriptNode {
    return {
      and_v: [
        {
          and_v: [
            pk(this.stakerKey),
            this.finalityProviderKeys.length === 1
              ? { 'v:pk': this.finalityProviderKeys[0].toString('hex') }
              : { 'v:multi_a': multiArgs(1, this.finalityProviderKeys) },
          ],
        },
        { multi_a: multiArgs(this.covenantThreshold, this.covenantKeys) },
      ],
    };
  }

  getUnbondingTimelockMiniscript(): ast.MiniscriptNode {
    return { and_v: [pk(this.stakerKey), { older: this.unbondingTimeLock }] };
  }

  getStakingDescriptor(): Descriptor {
    return taprootScriptOnlyFromAst([
      this.getSlashingMiniscript(),
      [this.getUnbondingMiniscript(), this.getTimelockMiniscript()],
    ]);
  }

  getSlashingDescriptor(): Descriptor {
    return taprootScriptOnlyFromAst(this.getUnbondingTimelockMiniscript());
  }

  getUnbondingDescriptor(): Descriptor {
    return taprootScriptOnlyFromAst([this.getSlashingMiniscript(), this.getUnbondingTimelockMiniscript()]);
  }
}

Выполнить команду


Для локальной разработки. Не используйте в интернете!