@brightunion/sdk
Version:
Brightjs is a set of javascript tools to interact with the Bright Union's risk platform aggregator's protocol on Ethereum, Binance Smart Chain and Polygon blockchains.
195 lines (167 loc) • 9.31 kB
text/typescript
import axios from 'axios';
import NetConfig from '../config/NetConfig'
import RiskCarriers from '../config/RiskCarriers'
import CatalogHelper from '../helpers/catalogHelper'
import BigNumber from 'bignumber.js'
import {toBN, toWei, fromWei} from 'web3-utils'
import {
_getNexusDistributorsContract, _getNexusV2CoverContract, _getNexusV2CoverNFT,
} from '../helpers/getContract'
import {getCoverMin} from "../helpers/cover_minimums"
import UniswapV3Api from '../helpers/UniswapV3Api';
export default class NexusApi {
static fetchCoverables() {
return axios.get(`${NetConfig.netById(global.user.ethNet.networkId).nexusAPI}/coverables/contracts.json`)
.then((response) => {
return response.data;
}).catch(error => {
return [];
});
}
static async setNXMBasedquotePrice(priceInNXM: any, quoteCurrency: string) {
//add 10%, Nexus adds 17,65% to the 'base quotation'
//PLUS 4% to cover a slight quotation volatility
priceInNXM = fromWei(priceInNXM.mul(toBN(1400)).div(toBN(10000)).add(priceInNXM));
let [priceInCurrencyFromNXM, routeData]: any = await UniswapV3Api.getNXMPriceFor(quoteCurrency, Number(priceInNXM.toString()));
const BrightFeeCoef: any = toBN(103); // Margin added - 3%
let [finalPrice, priceWithSlippage]: any = [null, null];
if (priceInCurrencyFromNXM) {
finalPrice = toBN(priceInCurrencyFromNXM).mul(BrightFeeCoef).div(toBN(100));
priceWithSlippage = toBN(priceInCurrencyFromNXM).mul(toBN(101)).div(toBN(100)) //max 1% slippage
}
return [
finalPrice,
priceWithSlippage,
priceInCurrencyFromNXM ? toBN(priceInCurrencyFromNXM) : null,
toWei(priceInNXM.toString()),
routeData
];
}
static async fetchQuote(amount: number, currency: string, period: number, protocol: any): Promise<any> {
let capacityETH: any = null;
let capacityDAI: any = null;
let quoteCapacity: any = null;
const productId = protocol.nexusProductId;
await this.fetchCapacity(productId).then((capacity: any) => {
capacityETH = capacity.find((obj: any) => {
return obj.assetId == RiskCarriers.NEXUS.assetsIds.ETH
}).amount;
capacityDAI = capacity.find((obj: any) => {
return obj.assetId == RiskCarriers.NEXUS.assetsIds.DAI
}).amount;
quoteCapacity = currency === 'ETH' ? capacityETH : capacityDAI;
}, () => {
quoteCapacity = false;
});
const amountInWei: any = toBN(toWei(amount.toString(), 'ether'));
if (currency === 'USD') {
currency = RiskCarriers.NEXUS.fallbackQuotation;
}
const minimumAmount = getCoverMin("nexus", global.user.ethNet.symbol, currency);
let quote: any = CatalogHelper.quoteFromCoverable(
'nexus',
protocol,
{
status: "INITIAL_DATA",
amount: amountInWei,
currency: currency,
period: period,
chain: 'ETH',
chainId: global.user.ethNet.networkId,
minimumAmount: minimumAmount,
capacity: quoteCapacity,
},
{}
);
const currencyId = RiskCarriers.NEXUS.assetsIds[currency];
return axios.get(
`${NetConfig.netById(global.user.ethNet.networkId).nexusAPI}/v2/quote?productId=${productId}&amount=${amountInWei}&coverAsset=${currencyId}&paymentAsset=255&period=${period}&contractAddress=${protocol.nexusCoverable}`,
{
headers: {}
}
)
.then(async (response: any) => {
if (Number(period) < 28 || Number(period) > 365) {
//API doesn't fall for wrong params
return NexusApi.emptyErrorQuote(quote, {message: "Minimum duration is 28 days. Maximum is 365", errorType: "period"});
}
let basePrice = toBN(response.data.quote.premiumInAsset);
//add 10%, Nexus adds 17,65% to the 'base quotation'
//basePrice = basePrice.mul(toBN(1000)).div(toBN(10000)).add(basePrice);
//const distributor = await _getNexusDistributorsContract(NetConfig.netById(global.user.ethNet.networkId).nexusDistributor);
// hardcoded address, as Bright Distributors contract cannot be called by passive net - fix for Nexus Multichain Quotation
//let fee: any = await distributor.methods.feePercentage().call();
//fee = toBN(fee);
let priceWithNexusUIFee: any = basePrice.mul(toBN(11750)).div(toBN(10000));
let pricePercentNXM: any = null;
let pricePercent: any = 0;
let [nxmBasedPrice, priceWithSlippage, nxmBasedPriceNoMargin, nxmNexusExpects, routeData] = await NexusApi.setNXMBasedquotePrice(toBN(response.data.quote.premiumInNXM), currency);
pricePercent = new BigNumber(priceWithNexusUIFee).times(1000).dividedBy(amountInWei).dividedBy(new BigNumber(period)).times(365).times(100).dividedBy(1000);
if (nxmBasedPrice && nxmBasedPrice > 0) {
pricePercentNXM = new BigNumber(nxmBasedPrice).times(1000).dividedBy(amountInWei).dividedBy(new BigNumber(period)).times(365).times(100).dividedBy(1000);
}
quote.rawData = response.data;
quote.uniSwapRouteData = routeData;
quote.priceOrigin = priceWithNexusUIFee.toString();
quote.price = nxmBasedPrice ? nxmBasedPrice : priceWithNexusUIFee;
quote.priceWithSlippage = priceWithSlippage ? priceWithSlippage : priceWithNexusUIFee;
quote.priceNoMargin = nxmBasedPriceNoMargin;
quote.pricePercentOrigin = pricePercent;
quote.pricePercent = pricePercentNXM ? pricePercentNXM : pricePercent;
quote.priceInNXM = nxmNexusExpects;
global.events.emit("quote", quote);
const nexusV2CoverAddr = NetConfig.netById(global.user.ethNet.networkId).nexusV2Cover;
const NexusV2CoverContract = await _getNexusV2CoverContract(nexusV2CoverAddr, global.user.ethNet.web3Instance);
const totalActiveCoversETH = fromWei(await NexusV2CoverContract.methods.totalActiveCoverInAsset(RiskCarriers.NEXUS.assetsIds.ETH).call());
const totalActiveCoversDAI = fromWei(await NexusV2CoverContract.methods.totalActiveCoverInAsset(RiskCarriers.NEXUS.assetsIds.DAI).call());
const coverNFT = await _getNexusV2CoverNFT(NetConfig.netById(global.user.ethNet.networkId).nexusV2CoverNFT);
const totalCovers = await coverNFT.methods.totalSupply().call();
quote.stats = {
capacityETH: capacityETH,
capacityDAI: capacityDAI,
totalCovers: totalCovers,
totalActiveCoversDAI: totalActiveCoversDAI,
totalActiveCoversETH: totalActiveCoversETH,
}
quote.status = "FINAL_DATA";
return quote;
}).catch(function (error) {
if ((error.response && error.response.status === 400) || (error.response && error.response.status === 409)) {
//wrong parameters
if (error.response.data.error || error.response.data.message.details || error.response.data.message) {
let errorMsg: any = null;
if (error.response.data.error) {
errorMsg = {message: error.response.data.error, errorType: "capacity"};
} else {
errorMsg = {message: error.response.data.message.details[0].message}
}
if (errorMsg.message.includes("coverAmount") && errorMsg.message.includes("required pattern")) {
errorMsg = {message: "Nexus supports only whole amounts to cover (e.g. 1999)", errorType: "amount"};
}
if (errorMsg.message.includes("only allows ETH as a currency")) {
errorMsg = {message: "Nexus supports only ETH currency for this cover"};
}
return NexusApi.emptyErrorQuote(quote, errorMsg);
}
} else {
quote.error = error;
return quote;
}
});
}
static emptyErrorQuote(quote:any, errorMsg:any) {
quote.priceOrigin = 0,
quote.price = 0,
quote.pricePercentOrigin = 0,
quote.pricePercent = 0,
quote.errorMsg = errorMsg,
quote.status = "FINAL_DATA";
return quote;
}
static fetchCapacity(_productId: any) {
return axios.get(`https://api.nexusmutual.io/v2/capacity/${_productId}`)
.then((response: any) => {
return response.data.availableCapacity;
});
}
}