js-stellar-base/src/liquidity_pool_asset.js

import xdr from './xdr';
import { Asset } from './asset';
import {
  LiquidityPoolFeeV18,
  getLiquidityPoolId
} from './get_liquidity_pool_id';

/**
 * LiquidityPoolAsset class represents a liquidity pool trustline change.
 *
 * @constructor
 * @param {Asset} assetA – The first asset in the Pool, it must respect the rule assetA < assetB. See {@link Asset.compare} for more details on how assets are sorted.
 * @param {Asset} assetB – The second asset in the Pool, it must respect the rule assetA < assetB. See {@link Asset.compare} for more details on how assets are sorted.
 * @param {number} fee – The liquidity pool fee. For now the only fee supported is `30`.
 */
export class LiquidityPoolAsset {
  constructor(assetA, assetB, fee) {
    if (!assetA || !(assetA instanceof Asset)) {
      throw new Error('assetA is invalid');
    }
    if (!assetB || !(assetB instanceof Asset)) {
      throw new Error('assetB is invalid');
    }
    if (Asset.compare(assetA, assetB) !== -1) {
      throw new Error('Assets are not in lexicographic order');
    }
    if (!fee || fee !== LiquidityPoolFeeV18) {
      throw new Error('fee is invalid');
    }

    this.assetA = assetA;
    this.assetB = assetB;
    this.fee = fee;
  }

  /**
   * Returns a liquidity pool asset object from its XDR ChangeTrustAsset object
   * representation.
   * @param {xdr.ChangeTrustAsset} ctAssetXdr - The asset XDR object.
   * @returns {LiquidityPoolAsset}
   */
  static fromOperation(ctAssetXdr) {
    const assetType = ctAssetXdr.switch();
    if (assetType === xdr.AssetType.assetTypePoolShare()) {
      const liquidityPoolParameters = ctAssetXdr
        .liquidityPool()
        .constantProduct();
      return new this(
        Asset.fromOperation(liquidityPoolParameters.assetA()),
        Asset.fromOperation(liquidityPoolParameters.assetB()),
        liquidityPoolParameters.fee()
      );
    }

    throw new Error(`Invalid asset type: ${assetType.name}`);
  }

  /**
   * Returns the `xdr.ChangeTrustAsset` object for this liquidity pool asset.
   *
   * Note: To convert from an {@link Asset `Asset`} to `xdr.ChangeTrustAsset`
   * please refer to the
   * {@link Asset.toChangeTrustXDRObject `Asset.toChangeTrustXDRObject`} method.
   *
   * @returns {xdr.ChangeTrustAsset} XDR ChangeTrustAsset object.
   */
  toXDRObject() {
    const lpConstantProductParamsXdr =
      new xdr.LiquidityPoolConstantProductParameters({
        assetA: this.assetA.toXDRObject(),
        assetB: this.assetB.toXDRObject(),
        fee: this.fee
      });
    const lpParamsXdr = new xdr.LiquidityPoolParameters(
      'liquidityPoolConstantProduct',
      lpConstantProductParamsXdr
    );
    return new xdr.ChangeTrustAsset('assetTypePoolShare', lpParamsXdr);
  }

  /**
   * @returns {LiquidityPoolParameters} Liquidity pool parameters.
   */
  getLiquidityPoolParameters() {
    return {
      ...this,
      assetA: this.assetA,
      assetB: this.assetB,
      fee: this.fee
    };
  }

  /**
   * @see [Assets concept](https://developers.stellar.org/docs/glossary/assets/)
   * @returns {AssetType.liquidityPoolShares} asset type. Can only be `liquidity_pool_shares`.
   */
  getAssetType() {
    return 'liquidity_pool_shares';
  }

  /**
   * @param {LiquidityPoolAsset} other the LiquidityPoolAsset to compare
   * @returns {boolean} `true` if this asset equals the given asset.
   */
  equals(other) {
    return (
      this.assetA.equals(other.assetA) &&
      this.assetB.equals(other.assetB) &&
      this.fee === other.fee
    );
  }

  toString() {
    const poolId = getLiquidityPoolId(
      'constant_product',
      this.getLiquidityPoolParameters()
    ).toString('hex');
    return `liquidity_pool:${poolId}`;
  }
}