@melonproject/protocol
Version:
Technology Regulated and Operated Investment Funds
134 lines (133 loc) • 6.43 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const BigNumber = require('bignumber.js');
const rp = require('request-promise');
const apiPath = 'https://min-api.cryptocompare.com/data/price';
// retry the request if it fails (helps with bad connections)
function requestWithRetries(options, maxRetries) {
return __awaiter(this, void 0, void 0, function* () {
if (maxRetries === -1) {
throw new Error('Request failed. Max retry limit reached.');
}
else {
try {
return yield rp(options);
}
catch (err) {
console.error(`Error during request:\n${err.message}\n\n${JSON.stringify(options, null, 2)}`);
return requestWithRetries(options, maxRetries - 1);
}
}
});
}
function convertPrice(inputPrice) {
const quoteDecimals = 18; // Hardcoded for now
return new BigNumber((1 / inputPrice).toFixed(16)).mul(Math.pow(10, quoteDecimals));
}
// get token from a list by symbol
function getToken(tokenList, sym) {
return tokenList.find(e => e.symbol === sym);
}
// TODO: reduce code duplication between this and the other one when we can
// This function gets prices only for assets defined in an environment object
/**
* Get prices converted to the format our contracts expect
* @param {Object} env - Environment as used in our deploy scripts
* @param {string} fromSymbol - Quote asset symbol, used to price other assets
*/
// TODO: Change to BigInteger
function getConvertedPrices(env, fromSymbol) {
return __awaiter(this, void 0, void 0, function* () {
const tokens = env.deployment.thirdPartyContracts.tokens;
const toSymbols = [
...(typeof getToken(tokens, 'DGX') !== 'undefined' ? ['DGX'] : []),
...(typeof getToken(tokens, 'MLN') !== 'undefined' ? ['MLN'] : []),
...(typeof getToken(tokens, 'EUR') !== 'undefined' ? ['EUR'] : []),
...(typeof getToken(tokens, 'WETH') !== 'undefined' ? ['ETH'] : []),
...(typeof getToken(tokens, 'DAI') !== 'undefined' ? ['DAI'] : []),
];
const options = {
json: true,
uri: `${apiPath}?fsym=${fromSymbol}&tsyms=${toSymbols.join(',')}&sign=true`,
};
const queryResult = yield requestWithRetries(options, 3);
if (queryResult[fromSymbol] !== 1) {
throw new Error(`API call returned incorrect price for ${fromSymbol}`);
}
else if (Object.values(queryResult).indexOf(0) !== -1) {
throw new Error('API call returned a zero price');
}
const result = Object.assign({}, (typeof getToken(tokens, 'EUR') !== 'undefined'
? { [getToken(tokens, 'EUR').address]: convertPrice(queryResult.EUR) }
: {}), (typeof getToken(tokens, 'WETH') !== 'undefined'
? { [getToken(tokens, 'WETH').address]: convertPrice(queryResult.ETH) }
: {}), (typeof getToken(tokens, 'MLN') !== 'undefined'
? { [getToken(tokens, 'MLN').address]: convertPrice(queryResult.MLN) }
: {}), (typeof getToken(tokens, 'DGX') !== 'undefined'
? { [getToken(tokens, 'DGX').address]: convertPrice(queryResult.DGX) }
: {}), (typeof getToken(tokens, 'DAI') !== 'undefined'
? { [getToken(tokens, 'DAI').address]: convertPrice(queryResult.DAI) }
: {}));
return result;
});
}
exports.getConvertedPrices = getConvertedPrices;
// TODO: make this more dynamic (different tokens) and flexible
// This function uses a default set of assets to get prices
/**
* Get prices converted to the format our contracts expect
* @param {Object} deployed - Contracts as returned by our deploy script
* @param {string} fromSymbol - Quote asset symbol, used to price other assets
*/
// TODO: Change to BigInteger
function getConvertedPricesDefault(deployed, fromSymbol) {
return __awaiter(this, void 0, void 0, function* () {
const toSymbols = ['MLN', 'EUR', 'ETH', 'DGX', 'DAI'];
const options = {
json: true,
uri: `${apiPath}?fsym=${fromSymbol}&tsyms=${toSymbols.join(',')}&sign=true`,
};
const queryResult = yield requestWithRetries(options, 3);
if (queryResult[fromSymbol] !== 1) {
throw new Error(`API call returned incorrect price for ${fromSymbol}`);
}
else if (Object.values(queryResult).indexOf(0) !== -1) {
throw new Error('API call returned a zero price');
}
return {
[deployed.eur.options.address]: convertPrice(queryResult.EUR),
[deployed.weth.options.address]: convertPrice(queryResult.ETH),
[deployed.mln.options.address]: convertPrice(queryResult.MLN),
[deployed.dgx.options.address]: convertPrice(queryResult.DGX),
[deployed.dai.options.address]: convertPrice(queryResult.DAI),
};
});
}
/**
* @param {Object} deployed - Object of deployed contracts from deployment script
* @param {Object} inputPrices - Optional object of asset addresses (keys) and prices (values)
*/
function updateTestingPriceFeed(deployed, env, inputPrices = {}, quoteSymbol = 'ETH') {
return __awaiter(this, void 0, void 0, function* () {
let prices;
const accounts = yield env.eth.getAccounts();
if (Object.keys(inputPrices).length === 0) {
prices = yield getConvertedPricesDefault(deployed, quoteSymbol);
}
else {
prices = inputPrices;
}
yield deployed.priceSource.methods
.update(Object.keys(prices), Object.values(prices).map(e => e.toString()))
.send({ from: accounts[0], gas: 8000000 });
});
}
exports.updateTestingPriceFeed = updateTestingPriceFeed;