UNPKG

juna

Version:

A cross platform NFT lending client for serious lenders

165 lines (141 loc) 5.49 kB
import { Gondi } from "gondi"; import { gondiConfig, testChain } from "./config"; import axios, { AxiosInstance } from "axios"; import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; import { PrivateKeyAccount, createWalletClient, http } from "viem"; import { mainnet } from "viem/chains"; import { Loan, Offer, LendingClientParameters, PromissoryNote, LendingClientWithPromissoryNotes, Listing, SingleItemOfferParams, CollectionOfferParams, } from "../types"; import Loans from "./api/loans"; import Offers from "./api/offers"; import { gondiLoanMapper, gondiOfferMapper, mapError } from "./support/mappers"; import { CollectionNotSupported } from "../errors"; const nowPlusOffset = (offset: number) => { const currentTime = new Date(); const currentTimePlusOffset = new Date(currentTime.getTime() + offset * 60 * 1000); // Add offset return Math.floor(currentTimePlusOffset.getTime() / 1000); // Convert to seconds }; export interface LendingClientParametersGondi extends LendingClientParameters { originationFeeInPercentage?: number; } export class GondiClient implements LendingClientWithPromissoryNotes { private http: AxiosInstance; private readonly account: PrivateKeyAccount; private loans: Loans; private offers: Offers; private client: Gondi; private originationFeeInPercentage: number; constructor(p: LendingClientParametersGondi) { this.account = privateKeyToAccount(p.privateKey ?? generatePrivateKey()); this.http = axios.create({ baseURL: gondiConfig.baseUrl, }); const wallet = createWalletClient({ account: privateKeyToAccount(p.privateKey ?? generatePrivateKey()), transport: p.testnet ? http(gondiConfig.rpcTestnet) : http(), chain: p.testnet ? testChain : mainnet, }); this.client = new Gondi({ wallet }); this.originationFeeInPercentage = p.originationFeeInPercentage ?? 0; this.loans = new Loans(this.http); this.offers = new Offers(this.http, this.client); } public async _getCollectionId(collectionAddress: `0x${string}`, slug?: string): Promise<any> { let collectionId: number; if (slug) { collectionId = await this.client.collectionId({ slug: slug, }); } else { collectionId = ( await this.client.collectionId({ contractAddress: collectionAddress, }) )[0]; } if (collectionId === undefined) { throw new CollectionNotSupported(); } return collectionId; } public async getListings(): Promise<Listing[]> { throw Error("Not implemented"); } public async getListingsForCollection(): Promise<Listing[]> { throw Error("Not implemented"); } public async getLoans(): Promise<Loan[]> { return await this.loans.get([], false).then((res) => res.map(gondiLoanMapper)); } public async getLoansForCollection(address: `0x${string}`): Promise<Loan[]> { console.log(address); throw Error("Not implemented"); } public async getLoansForAccount(address: `0x${string}`): Promise<Loan[]> { return await this.loans.get([address], true).then((res) => res.map(gondiLoanMapper)); } public async getMyLoans(): Promise<Loan[]> { return await this.getLoansForAccount(this.account.address); } public async createSingleItemOffer(offerParams: SingleItemOfferParams): Promise<Offer> { console.log(offerParams); throw Error("Not implemented"); } public async createCollectionOffer(offerParams: CollectionOfferParams): Promise<Offer> { const payload = { collectionId: await this._getCollectionId(offerParams.collectionAddress, offerParams.slug), principalAddress: offerParams.currency.address, principalAmount: BigInt(offerParams.principal * 1e18), capacity: BigInt(offerParams.principal * 1e18), fee: BigInt( Math.round( ((offerParams.principal * this.originationFeeInPercentage * offerParams.apr * offerParams.durationInDays) / 365) * 1e18, ), ), // Origination fee aprBps: BigInt(Math.round(offerParams.apr * (1 - this.originationFeeInPercentage) * 10000)), expirationTime: BigInt(nowPlusOffset(offerParams.expiryInMinutes)), duration: BigInt(Math.round(offerParams.durationInDays * 24 * 3600)), requiresLiquidation: false, // Sets the collateral to be liquidated on default. lenderAddress: offerParams.lenderAddress ?? this.account.address, // borrowerAddress: null, // Optional: allow only this borrower to accept the offer. }; return await this.offers .createCollectionOffer(payload) .then((res) => gondiOfferMapper(res)) .catch((error) => { throw mapError(error); }); } public async deleteOffer(offerId: string): Promise<void> { console.log(offerId); throw new Error("Not implemented!"); } public async getOffers(): Promise<Offer[]> { throw Error("Not implemented"); } public async getOffersForAccount(address: `0x${string}`): Promise<Offer[]> { console.log(address); throw new Error("Not implemented!"); } public async getOffersForCollection(address: `0x${string}`): Promise<Offer[]> { console.log(address); throw Error("Not implemented"); } public async getMyOffers(): Promise<Offer[]> { throw new Error("Not implemented!"); } public async getPromissoryNote(loanId: number): Promise<PromissoryNote> { console.log(loanId); throw Error("Not implemented"); } }