File

src/security/instrument.service.ts

Index

Properties
Methods

Constructor

constructor(instrumentModel: Model<InstrumentDocument>, navModel: Model<NavDocument>)
Parameters :
Name Type Optional
instrumentModel Model<InstrumentDocument> No
navModel Model<NavDocument> No

Methods

Async create
create(createInstrumentDto)
Parameters :
Name Optional
createInstrumentDto No
Returns : Promise<>
Async findAllByFilter
findAllByFilter(filterInstrument)
Parameters :
Name Optional
filterInstrument No
Returns : Promise<IInstrumentDbWithNavs[]>
Async findByIds
findByIds(ids: string[])
Parameters :
Name Type Optional
ids string[] No
Async findInstrumentByProperty
findInstrumentByProperty(filterInstrument)
Parameters :
Name Optional
filterInstrument No
Async findOne
findOne(id: string)
Parameters :
Name Type Optional
id string No
Async getInstrumentOrders
getInstrumentOrders(instrumentId: string)
Parameters :
Name Type Optional
instrumentId string No
Returns : unknown
Async initializeInstrument
initializeInstrument(undefined: IInitializeInstrument)
Parameters :
Name Type Optional
IInitializeInstrument No
Returns : unknown
Async update
update(id: string, updateInstrumentDto: UpdateInstrumentDto)
Parameters :
Name Type Optional
id string No
updateInstrumentDto UpdateInstrumentDto No

Properties

Private Readonly adminProfileService
Type : AdminProfileService
Decorators :
@Inject(AdminProfileService)
Private Readonly internalCustodialService
Type : InternalCustodialService
Decorators :
@Inject(InternalCustodialService)
Private Readonly userService
Type : UserService
Decorators :
@Inject(UserService)
import { LeanDocument, Model } from "mongoose";
import { InjectModel } from "@nestjs/mongoose";
import { BadRequestException, Inject, Injectable } from "@nestjs/common";

import { Instrument, InstrumentDocument } from "./schemas/instrument.schema";
import { CreateInstrumentDto } from "./dto/create-instrument.dto";
import {
  apolloClient,
  getAllOrdersByInstrumentIdQuery,
  transactionSubmitter,
} from "src/common/provider";
import {
  getContractByName,
  getRoleAndContractAddressByNameOrAddress,
} from "src/common/provider/web3/web3Provider";
import {
  ContractName,
  IFile,
  IGetOrdersQuery,
  OrderDirection,
  TransactionNames,
} from "src/common/interfaces";
import { encodeBytes32String } from "ethers";
import {
  PaymentToken,
  RedemptionBookImpl,
  RulesEngineAddress,
  SecurityTokenBookImpl,
  SubscriptionBookImpl,
  TreasuryWallet,
} from "src/common/constants/Addresses";
import { Roles } from "src/common/constants";
import { FilterInstrumentDto } from "./dto/filter-instrument.dto";
import { ApolloQueryResult } from "@apollo/client";
import { IInitializeInstrument, IInstrumentDbWithNavs } from "./fund.interface";
import { InternalCustodialService } from "src/shared/custodial/internalCustodial.service";
import { UserService } from "src/user/user.service";
import { Nav, NavDocument } from "./schemas/nav.schema";
import { AdminProfileService } from "src/admin-profile/admin-profile.service";
import { CustodialDocument } from "src/shared/custodial/schemas/custodial.schema";
import { UpdateInstrumentDto } from "./dto/update-instrument.dto";
import { uploadCmsFileFields } from "src/common/utils";

@Injectable()
export class InstrumentService {
  @Inject(UserService)
  private readonly userService: UserService;
  @Inject(InternalCustodialService)
  private readonly internalCustodialService: InternalCustodialService;
  @Inject(AdminProfileService)
  private readonly adminProfileService: AdminProfileService;

  constructor(
    @InjectModel(Instrument.name)
    private readonly instrumentModel: Model<InstrumentDocument>,
    @InjectModel(Nav.name)
    private readonly navModel: Model<NavDocument>,
  ) {}

  async create(
    createInstrumentDto: CreateInstrumentDto & {
      adminEmail: string;
      fundId: string;
    },
  ): Promise<Instrument & { txHash: string }> {
    const newInstrument = new this.instrumentModel(createInstrumentDto);
    const adminSigner = await this.adminProfileService.getCustodial(
      createInstrumentDto.adminEmail,
    );
    const tx = await transactionSubmitter({
      signerKey: adminSigner.privateKey,
      contractAddress:
        getContractByName[ContractName.InstrumentRegistry].address,
      transactionName: TransactionNames.addInstrument,
      contractName: ContractName.InstrumentRegistry,
      args: [
        Roles.Admin,
        encodeBytes32String(newInstrument.id),
        encodeBytes32String(createInstrumentDto.fundId),
      ],
    });
    newInstrument.save();
    return { ...newInstrument.toObject(), txHash: tx.hash };
  }

  async initializeInstrument({
    instrumentId,
    userJwtPayload,
  }: IInitializeInstrument) {
    const isPlatformAdmin = userJwtPayload.role === "admin";

    const contractAddress =
      getContractByName[ContractName.InstrumentRegistry].address;

    let signerKey: CustodialDocument;
    if (isPlatformAdmin) {
      signerKey = await this.adminProfileService.getCustodial(
        userJwtPayload.email,
      );
    } else {
      signerKey = await this.userService.getCustodial(userJwtPayload.email);
    }

    const [instrument, { role }] = await Promise.all([
      this.findOne(instrumentId),
      getRoleAndContractAddressByNameOrAddress({
        transactionName: TransactionNames.initializeInstrument,
        contractName: ContractName.InstrumentRegistry,
        userAddress: signerKey.address,
      }),
    ]);
    if (!instrument) {
      throw new BadRequestException(
        `The instrument with id ${instrumentId} does not exist`,
      );
    }

    return await transactionSubmitter({
      signerKey: signerKey.privateKey,
      contractAddress,
      transactionName: TransactionNames.initializeInstrument,
      contractName: ContractName.InstrumentRegistry,
      args: [
        role,
        encodeBytes32String(instrument.id),
        PaymentToken,
        RulesEngineAddress,
        instrument.name,
        instrument.symbol,
        SubscriptionBookImpl,
        RedemptionBookImpl,
        SecurityTokenBookImpl,
        TreasuryWallet,
      ],
    });
  }

  async findAllByFilter(
    filterInstrument: FilterInstrumentDto & { fundId: string },
  ): Promise<IInstrumentDbWithNavs[]> {
    const {
      limit,
      skip,
      orderDirection = OrderDirection.asc,
      selectors,
      ...restOfFilter
    } = filterInstrument;
    const [instrumentsDb, navsDb]: [
      LeanDocument<InstrumentDocument>[],
      LeanDocument<NavDocument>[],
    ] = await Promise.all([
      this.instrumentModel
        .find(restOfFilter, selectors ? selectors.join(" ") : "")
        .limit(limit)
        .skip(skip * limit)
        .sort({ created: orderDirection })
        .lean()
        .exec(),
      selectors ? [] : this.navModel.find().lean().exec(),
    ]);
    const navByInstrumentId: Record<string, LeanDocument<NavDocument>[]> = {};
    navsDb.forEach((nav) => {
      if (navByInstrumentId[nav.instrument.toString()]) {
        navByInstrumentId[nav.instrument.toString()].push(nav);
      } else {
        navByInstrumentId[nav.instrument.toString()] = [nav];
      }
    });

    return instrumentsDb.map((instrument) => {
      return {
        ...instrument,
        navs: navByInstrumentId[instrument._id.toString()] || [],
      };
    });
  }

  async findByIds(ids: string[]): Promise<InstrumentDocument[]> {
    return this.instrumentModel.find({ _id: { $in: ids } });
  }
  async findOne(id: string): Promise<InstrumentDocument> {
    return this.instrumentModel.findById(id);
  }
  async findInstrumentByProperty(
    filterInstrument: FilterInstrumentDto & { fundId: string },
  ): Promise<InstrumentDocument> {
    return this.instrumentModel.findOne(filterInstrument);
  }

  async update(
    id: string,
    updateInstrumentDto: UpdateInstrumentDto,
  ): Promise<InstrumentDocument> {
    const cmsFields = [];
    if (updateInstrumentDto.cmsFields) {
      cmsFields.push(
        ...(await uploadCmsFileFields(updateInstrumentDto.cmsFields)),
      );
    }

    return await this.instrumentModel
      .findByIdAndUpdate(
        id,
        {
          ...updateInstrumentDto,
          cmsFields,
        },
        { new: true },
      )
      .exec();
  }

  async getInstrumentOrders(instrumentId: string) {
    const orderBooks: ApolloQueryResult<IGetOrdersQuery> =
      await apolloClient.query({
        query: getAllOrdersByInstrumentIdQuery,
        variables: {
          instrumentId: encodeBytes32String(instrumentId),
          type: "",
        },
      });
    return orderBooks.data;
  }
}

results matching ""

    No results matching ""