PHP WebShell

Текущая директория: /opt/BitGoJS/modules/sdk-coin-sol/src/lib

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

import { BaseCoin as CoinConfig } from '@bitgo/statics';
import assert from 'assert';

import { BuildTransactionError, Recipient, TransactionType } from '@bitgo/sdk-core';
import { InstructionBuilderTypes, STAKE_ACCOUNT_RENT_EXEMPT_AMOUNT } from './constants';
import { StakingDeactivate, Transfer } from './iface';
import { Transaction } from './transaction';
import { TransactionBuilder } from './transactionBuilder';
import { isValidStakingAmount, validateAddress } from './utils';

export class StakingDeactivateBuilder extends TransactionBuilder {
  protected _stakingAddress: string;
  protected _stakingAddresses: string[];
  protected _amount?: string;
  protected _unstakingAddress: string;
  protected _isMarinade = false;
  protected _recipients: Recipient[];

  constructor(_coinConfig: Readonly<CoinConfig>) {
    super(_coinConfig);
  }

  protected get transactionType(): TransactionType {
    return TransactionType.StakingDeactivate;
  }

  /** @inheritdoc */
  initBuilder(tx: Transaction): void {
    super.initBuilder(tx);
    const stakingAddresses: string[] = [];
    for (const instruction of this._instructionsData) {
      if (instruction.type === InstructionBuilderTypes.StakingDeactivate) {
        const deactivateInstruction: StakingDeactivate = instruction;
        this.isMarinade(deactivateInstruction.params.isMarinade ?? false);
        if (!deactivateInstruction.params.isMarinade) {
          this.sender(deactivateInstruction.params.fromAddress);
        }
        if (deactivateInstruction.params.isMarinade) {
          this.recipients(deactivateInstruction.params.recipients ?? []);
        }
        stakingAddresses.push(deactivateInstruction.params.stakingAddress);
        if (deactivateInstruction.params.amount && deactivateInstruction.params.unstakingAddress) {
          this.amount(deactivateInstruction.params.amount);
          this.unstakingAddress(deactivateInstruction.params.unstakingAddress);
        }
      }
    }
    if (stakingAddresses.length > 1) {
      this.stakingAddresses(stakingAddresses);
    } else {
      if (!this._isMarinade) {
        this.stakingAddress(stakingAddresses[0]);
      }
    }
  }

  /**
   * The staking address of the staking account.
   *
   * @param {string} stakingAddress public address of the staking account
   * @returns {StakingDeactivateBuilder} This staking deactivate builder.
   *
   * @see https://docs.solana.com/staking/stake-accounts#account-address
   */
  stakingAddress(stakingAddress: string): this {
    validateAddress(stakingAddress, 'stakingAddress');
    this._stakingAddress = stakingAddress;
    return this;
  }

  /**
   * The staking addresses of the staking account.
   *
   * @param {string[]} stakingAddresses public address of the staking accounts
   * @returns {StakingDeactivateBuilder} This staking deactivate builder.
   *
   * @see https://docs.solana.com/staking/stake-accounts#account-address
   */
  stakingAddresses(stakingAddresses: string[]): this {
    for (const stakingAddress of stakingAddresses) {
      validateAddress(stakingAddress, 'stakingAddress');
    }
    this._stakingAddresses = stakingAddresses;
    return this;
  }

  /**
   * Optional amount to unstake expressed in Lamports, 1 SOL = 1_000_000_000 lamports, to be used
   * when partially unstaking. If not given then the entire staked amount will be unstaked.
   *
   * @param {string} amount The partial amount to unstake, expressed in Lamports.
   * @returns {StakingDeactivateBuilder} This staking builder.
   *
   * @see https://docs.solana.com/cli/delegate-stake#split-stake
   */
  amount(amount: string): this {
    if (!isValidStakingAmount(amount)) {
      throw new BuildTransactionError('If given, amount cannot be zero or less');
    }
    this._amount = amount;
    return this;
  }

  /**
   * Setter to set the recipients object
   *
   * @param recipients RecipientEntry[] - The recipients object
   * @returns {StakingDeactivateBuilder} This staking builder.
   */
  recipients(recipients: Recipient[]): this {
    this._recipients = recipients;
    return this;
  }

  /**
   * When partially unstaking move the amount to unstake to this account and initiate the
   * unstake process. The original stake account will continue staking.
   *
   * @param {string} unstakingAddress An account used to unstake a partial amount.
   * @returns {StakingDeactivateBuilder} This staking builder.
   *
   * @see https://docs.solana.com/cli/delegate-stake#split-stake
   */
  unstakingAddress(unstakingAddress: string): this {
    validateAddress(unstakingAddress, 'unstakingAddress');
    this._unstakingAddress = unstakingAddress;
    return this;
  }

  /**
   * Set isMarinade flag
   * @param {boolean} flag - true if the transaction is for Marinade, false by default if not set
   * @returns {StakingActivateBuilder} This staking builder
   */
  isMarinade(flag: boolean): this {
    this._isMarinade = flag;
    return this;
  }

  /** @inheritdoc */
  protected async buildImplementation(): Promise<Transaction> {
    assert(this._sender, 'Sender must be set before building the transaction');
    assert(this._isMarinade !== undefined, 'isMarinade must be set before building the transaction');

    if (this._stakingAddresses && this._stakingAddresses.length > 0) {
      this._instructionsData = [];
      for (const stakingAddress of this._stakingAddresses) {
        const stakingDeactivateData: StakingDeactivate = {
          type: InstructionBuilderTypes.StakingDeactivate,
          params: {
            fromAddress: this._sender,
            stakingAddress: stakingAddress,
          },
        };
        this._instructionsData.push(stakingDeactivateData);
      }
    } else {
      if (!this._isMarinade) {
        // we don't need stakingAddress in marinade staking deactivate txn
        assert(this._stakingAddress, 'Staking address must be set before building the transaction');
      }

      if (this._sender === this._stakingAddress) {
        throw new BuildTransactionError('Sender address cannot be the same as the Staking address');
      }

      if (this._amount && !this._isMarinade) {
        assert(
          this._unstakingAddress,
          'When partially unstaking the unstaking address must be set before building the transaction'
        );
      }
      this._instructionsData = [];
      if (this._unstakingAddress && !this._isMarinade) {
        assert(
          this._amount,
          'If an unstaking address is given then a partial amount to unstake must also be set before building the transaction'
        );
        const stakingFundUnstakeAddress: Transfer = {
          type: InstructionBuilderTypes.Transfer,
          params: {
            fromAddress: this._sender,
            amount: STAKE_ACCOUNT_RENT_EXEMPT_AMOUNT.toString(),
            toAddress: this._unstakingAddress,
          },
        };
        this._instructionsData.push(stakingFundUnstakeAddress);
      }

      const stakingDeactivateData: StakingDeactivate = {
        type: InstructionBuilderTypes.StakingDeactivate,
        params: {
          fromAddress: this._sender,
          stakingAddress: this._stakingAddress,
          amount: this._amount,
          unstakingAddress: this._unstakingAddress,
          isMarinade: this._isMarinade,
          recipients: this._recipients,
        },
      };
      this._instructionsData.push(stakingDeactivateData);
    }
    return await super.buildImplementation();
  }
}

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


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