@bloom-trade/finance-connector
Version:
Is a package entended to be used with multiple web3 and web2 providers to interact with blockchains.
285 lines (282 loc) • 7.98 kB
text/typescript
/* eslint-disable @typescript-eslint/no-var-requires */
import {
ProviderCredentials,
Providers,
Client,
Balance,
Contracts,
PoloniexPrice,
} from '../@types/index';
import Web3 from 'web3';
import { cryptocurrencies } from '../data/cryptocurrencies';
import { contracts } from '../data/contracts';
import {
Transaction,
Chain,
Asset,
Provider,
STABLECOINS,
StableCoin,
} from '@bloom-trade/types';
import axios from 'axios';
import moment from 'moment';
const sum = (a: any, b: any, positions: number) => {
const factor = Math.pow(10, positions);
return (
(a.toFixed(positions) * factor + b.toFixed(positions) * factor) / factor
);
};
const setClient = (providerConnection: ProviderCredentials[]): Client => {
const providers = providerConnection;
return {
providers,
getProvider(id) {
//staff this function to return the provider object
},
async getBalance() {
const balance: Balance = [];
for (const connection of providerConnection) {
const {
ProviderConnectorImpl,
} = require(`../impl/${connection.provider.id}/index`);
const service = new ProviderConnectorImpl(connection);
const res = (await service.getBalance()) as Balance;
res.forEach((e) => {
const foundElement = balance.find(
(element) => element.asset === e.asset
);
if (!foundElement) {
balance.push(e);
} else {
if (
foundElement.asset === 'ETH' ||
foundElement.asset === 'MATIC' ||
foundElement.asset === 'AVAX'
) {
const index = balance.indexOf(foundElement);
balance[index].balance = sumEthsBalances(
foundElement.balance,
e.balance
);
balance[index].detail.push(...e.detail);
} else {
const index = balance.indexOf(foundElement);
balance[index].balance = sum(
parseFloat(e.balance),
parseFloat(balance[index].balance),
3
).toString();
balance[index].detail.push(...e.detail);
}
}
});
}
return balance;
},
async getTransactionHistory(params: {
from:
| 'beginning'
| {
selfCustodialProviders?: {
chain: Chain;
block: number;
}[];
custodialProviders?: {
id: Provider;
block?: number;
date: number; //NOT IN UNIX TIMESTAMP
}[];
};
order?: 'asc' | 'desc';
filters?: {
onlyStables?: boolean;
};
}) {
let transactions: Transaction[] = [];
const StableAssets: STABLECOINS = ['usdt', 'usdc', 'dai'];
for (const connection of providerConnection) {
const {
ProviderConnectorImpl,
} = require(`../impl/${connection.provider.id}/index`);
const service = new ProviderConnectorImpl(connection);
const res = (await service.getTransactionHistory(
params
)) as Transaction[];
res.forEach((e) => {
transactions.push(e);
});
}
switch (params.order) {
case 'asc':
transactions.sort((a, b) => a.timestamp - b.timestamp);
break;
case 'desc':
transactions.sort((a, b) => b.timestamp - a.timestamp);
default:
break;
}
if (params.filters && params.filters.onlyStables) {
transactions = transactions.filter((tx) => {
if (StableAssets.includes(tx.asset as StableCoin)) {
return tx;
}
});
}
return transactions;
},
};
};
const getDescription = (asset: string) => {
const myKeys = Object.keys(cryptocurrencies);
const foundKey = myKeys.find((e) => e === asset);
if (!foundKey) return '';
return cryptocurrencies[foundKey];
};
const getSupportedContracts = () => {
return contracts.tokens as Contracts;
};
const manageBaseUrl = (connection: ProviderCredentials): string => {
let url = '';
if (!connection.provider.useTestnet) {
url = setProdUrl(connection.provider.id);
} else {
url = setTestUrl(connection.provider.id);
}
return url;
//staff this function to return the base url
};
const setProdUrl = (provider: Providers) => {
switch (provider) {
case 'binance':
return 'https://api.binance.com';
case 'etherscan':
return 'https://api.etherscan.io/api';
case 'polygonscan':
return 'https://api.polygonscan.com/api';
case 'snowtrace':
return 'https://snowtrace.io/api';
case 'circle':
return 'https://api.circle.com/v1';
default:
return 'https://api.etherscan.io/api';
}
};
const setTestUrl = (provider: Providers) => {
switch (provider) {
case 'binance':
return 'https://testnet.binance.vision';
case 'etherscan':
return 'https://api-goerli.etherscan.io/api';
case 'polygonscan':
return 'https://api-testnet.polygonscan.com/api';
case 'snowtrace':
return 'https://api-testnet.snowtrace.io/api';
case 'circle':
return 'https://api-sandbox.circle.com/v1';
default:
return 'https://api-goerli.etherscan.io/api';
}
};
const getTestnetByMainnet = (chain: Chain) => {
switch (chain) {
case 'eth':
return 'goerli';
case 'avax':
return 'fuji';
case 'polygon':
return 'mumbai';
default:
return 'goerli';
}
};
const sumEthsBalances = (referenceBalance: string, balanceToAdd: string) => {
const web3 = new Web3(Web3.givenProvider || 'ws://localhost:8545');
const totalBalanceInWei = web3.utils.toWei(referenceBalance, 'ether');
const foundElementInWei = web3.utils.toWei(balanceToAdd, 'ether');
const newBalance = web3.utils
.toBN(totalBalanceInWei)
.add(web3.utils.toBN(foundElementInWei))
.toString();
const formattedBalance = web3.utils.fromWei(newBalance, 'ether');
return formattedBalance;
};
const weiToEth = (value: string) => {
const web3 = new Web3(Web3.givenProvider || 'ws://localhost:8545');
return web3.utils.fromWei(value, 'ether');
};
const convertToken = (value: string, decimals: number) => {
const web3 = new Web3(Web3.givenProvider || 'ws://localhost:8545');
return web3.utils
.toBN(value)
.div(web3.utils.toBN(10 ** decimals))
.toString();
};
const getAssetPriceInUSDC = async (
asset: Asset,
startDate: number,
endDate: number
) => {
//staff this function to return the price of the asset in USDC
try {
const { data } = await axios.get(
`https://poloniex.com/public?command=returnChartData¤cyPair=USDC_${asset.toUpperCase()}&start=${startDate}&end=${endDate}&period=14400`
);
return data[0] as PoloniexPrice;
} catch (error) {
throw new Error();
}
};
const getAssetDataByChain = (
contract: {
token: Asset;
networks: {
chain: Chain;
address: string;
decimalPosition: number;
}[];
},
chain: Chain,
provider: {
id: Providers;
useTestnet: boolean;
auth: {
apiKey?: string;
apiSecret?: string;
};
}
) => {
const filteredContract = contract.networks.find(
(e) =>
e.chain ===
(provider.useTestnet
? getTestnetByMainnet(chain as Chain)
: chain === 'eth'
? 'erc20'
: chain)
);
return filteredContract as {
chain: Chain;
address: string;
decimalPosition: number;
};
};
const stringToMilisecondsDate = (string: string) => {
const date = new Date(string);
return date.getTime();
};
const fDate = (date: number) => {
return moment(date).format();
};
export {
setClient,
getDescription,
manageBaseUrl,
getSupportedContracts,
weiToEth,
convertToken,
getAssetPriceInUSDC,
getTestnetByMainnet,
getAssetDataByChain,
fDate,
stringToMilisecondsDate,
};