@melonproject/protocol
Version:
Technology Regulated and Operated Investment Funds
344 lines (343 loc) • 21.3 kB
JavaScript
"use strict";
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());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const R = __importStar(require("ramda"));
const Contracts_1 = require("../../Contracts");
const deployMatchingMarketAdapter_1 = require("../../contracts/exchanges/transactions/deployMatchingMarketAdapter");
const deployMatchingMarketAccessor_1 = require("../../contracts/exchanges/transactions/deployMatchingMarketAccessor");
const deployEngine_1 = require("../../contracts/engine/transactions/deployEngine");
const deploy_1 = require("../../contracts/fund/policies/risk-management/transactions/deploy");
const deployRegistry_1 = require("../../contracts/version/transactions/deployRegistry");
const registerAsset_1 = require("../../contracts/version/transactions/registerAsset");
const FunctionSignatures_1 = require("../../contracts/fund/trading/utils/FunctionSignatures");
const registerExchangeAdapter_1 = require("../../contracts/version/transactions/registerExchangeAdapter");
const updateExchangeAdapter_1 = require("../../contracts/version/transactions/updateExchangeAdapter");
const deployVersion_1 = require("../../contracts/version/transactions/deployVersion");
const deployFundRanking_1 = require("../../contracts/factory/transactions/deployFundRanking");
const deployUserWhitelist_1 = require("../../contracts/fund/policies/compliance/transactions/deployUserWhitelist");
const deployAccountingFactory_1 = require("../../contracts/fund/accounting/transactions/deployAccountingFactory");
const deployFeeManagerFactory_1 = require("../../contracts/fund/fees/transactions/deployFeeManagerFactory");
const deployParticipationFactory_1 = require("../../contracts/fund/participation/transactions/deployParticipationFactory");
const deploySharesFactory_1 = require("../../contracts/fund/shares/transactions/deploySharesFactory");
const deployTradingFactory_1 = require("../../contracts/fund/trading/transactions/deployTradingFactory");
const deployVaultFactory_1 = require("../../contracts/fund/vault/transactions/deployVaultFactory");
const deployPolicyManagerFactory_1 = require("../../contracts/fund/policies/transactions/deployPolicyManagerFactory");
const deploy0xAdapter_1 = require("../../contracts/exchanges/transactions/deploy0xAdapter");
const deployEthfinexAdapter_1 = require("../../contracts/exchanges/transactions/deployEthfinexAdapter");
const Environment_1 = require("../environment/Environment");
const deployKyberAdapter_1 = require("../../contracts/exchanges/transactions/deployKyberAdapter");
const token_math_1 = require("@melonproject/token-math");
const setMlnToken_1 = require("../../contracts/version/transactions/setMlnToken");
const setNativeAsset_1 = require("../../contracts/version/transactions/setNativeAsset");
const setPriceSource_1 = require("../../contracts/version/transactions/setPriceSource");
const setEngine_1 = require("../../contracts/version/transactions/setEngine");
const setMGM_1 = require("../../contracts/version/transactions/setMGM");
const setAmguPrice_1 = require("../../contracts/engine/transactions/setAmguPrice");
const getAmguToken_1 = require("../../contracts/engine/calls/getAmguToken");
const registerVersion_1 = require("../../contracts/version/transactions/registerVersion");
const getVersionInformation_1 = require("../../contracts/version/calls/getVersionInformation");
const isFeeRegistered_1 = require("../../contracts/version/calls/isFeeRegistered");
const registerFees_1 = require("../../contracts/version/transactions/registerFees");
const getRegistryInformation_1 = require("../../contracts/version/calls/getRegistryInformation");
const deployKyberPriceFeed_1 = require("../../contracts/prices/transactions/deployKyberPriceFeed");
const getLogCurried_1 = require("../environment/getLogCurried");
const updateKyber_1 = require("../../contracts/prices/transactions/updateKyber");
const deployTestingPriceFeed_1 = require("../../contracts/prices/transactions/deployTestingPriceFeed");
const updateTestingPriceFeed_1 = require("../../tests/utils/updateTestingPriceFeed");
const getContract_1 = require("../solidity/getContract");
const setDecimals_1 = require("../../contracts/prices/transactions/setDecimals");
const deployManagementFee_1 = require("../../contracts/fund/fees/transactions/deployManagementFee");
const deployPerformanceFee_1 = require("../../contracts/fund/fees/transactions/deployPerformanceFee");
const setEthfinexWrapperRegistry_1 = require("../../contracts/version/transactions/setEthfinexWrapperRegistry");
const deployEngineAdapter_1 = require("../../contracts/exchanges/transactions/deployEngineAdapter");
const pkg = require('../../../package.json');
exports.deployAllContractsConfig = JSON.parse(`{
"priceSource": "DEPLOY",
"adapters": {
"ethfinexAdapter": "DEPLOY",
"kyberAdapter": "DEPLOY",
"matchingMarketAdapter": "DEPLOY",
"matchingMarketAccessor": "DEPLOY",
"zeroExAdapter": "DEPLOY",
"engineAdapter": "DEPLOY"
},
"policies": {
"priceTolerance": "DEPLOY",
"userWhitelist": "DEPLOY"
},
"fees" : {
"managementFee": "DEPLOY",
"performanceFee": "DEPLOY"
},
"factories": {
"accountingFactory": "DEPLOY",
"feeManagerFactory": "DEPLOY",
"participationFactory": "DEPLOY",
"policyManagerFactory": "DEPLOY",
"sharesFactory": "DEPLOY",
"tradingFactory": "DEPLOY",
"vaultFactory": "DEPLOY"
},
"engine": "DEPLOY",
"registry": "DEPLOY",
"version": "DEPLOY",
"ranking": "DEPLOY"
}`);
exports.defaultControlConfig = JSON.parse(`{
"MGM": "",
"registryOwner": "",
"versionOwner": ""
}`);
const getLog = getLogCurried_1.getLogCurried('melon:protocol:utils:deploySystem');
const maybeDeploy = R.curry((path, deployFunction, environmentPromise) => __awaiter(this, void 0, void 0, function* () {
const environment = yield environmentPromise;
const environmentPath = ['deployment', 'melonContracts', ...path];
const { info } = getLog(environment);
const adoptedContract = R.path(environmentPath, environment);
if (adoptedContract === 'DEPLOY') {
info('Deploying', path.join('.'));
const address = yield deployFunction(environment);
const newEnvironment = R.assocPath(environmentPath, address, environment);
return newEnvironment;
}
info('Not Deploying', path.join('.'));
return environment;
}));
const maybeDoSomething = R.curry((shouldIt, something, environmentPromise) => __awaiter(this, void 0, void 0, function* () {
const environment = yield environmentPromise;
if (shouldIt)
yield something(environment);
return environment;
}));
/**
* Deploys all contracts and checks their health
*/
exports.deploySystem = (environmentWithoutDeployment, thirdPartyContracts, adoptedContracts, control, description) => __awaiter(this, void 0, void 0, function* () {
// Set thirdPartyContracts already to have them available in subsequent calls
const environment = Object.assign({}, environmentWithoutDeployment, { deployment: { thirdPartyContracts, melonContracts: adoptedContracts } });
const log = getLog(environment);
log.info('Deploying system from:', environment.wallet.address);
log.debug('Deploying system', {
adoptedContracts,
thirdPartyContracts,
});
const wethToken = thirdPartyContracts.tokens.find(t => t.symbol === 'WETH');
const mlnToken = thirdPartyContracts.tokens.find(t => t.symbol === 'MLN');
const monthInSeconds = 30 * 24 * 60 * 60;
const environmentWithDeployment = yield R.pipe(maybeDeploy(['adapters', 'ethfinexAdapter'], environment => deployEthfinexAdapter_1.deployEthfinexAdapter(environment)), maybeDeploy(['adapters', 'kyberAdapter'], environment => deployKyberAdapter_1.deployKyberAdapter(environment)), maybeDeploy(['adapters', 'matchingMarketAdapter'], environment => deployMatchingMarketAdapter_1.deployMatchingMarketAdapter(environment)), maybeDeploy(['adapters', 'matchingMarketAccessor'], environment => deployMatchingMarketAccessor_1.deployMatchingMarketAccessor(environment)), maybeDeploy(['adapters', 'zeroExAdapter'], environment => deploy0xAdapter_1.deploy0xAdapter(environment)), maybeDeploy(['adapters', 'engineAdapter'], environment => deployEngineAdapter_1.deployEngineAdapter(environment)), maybeDeploy(['policies', 'priceTolerance'], environment => deploy_1.deploy(environment, 10)), maybeDeploy(['policies', 'userWhitelist'], environment => deployUserWhitelist_1.deployUserWhitelist(environment, [environment.wallet.address])), maybeDeploy(['fees', 'managementFee'], environment => deployManagementFee_1.deployManagementFee(environment)), maybeDeploy(['fees', 'performanceFee'], environment => deployPerformanceFee_1.deployPerformanceFee(environment)), maybeDeploy(['factories', 'accountingFactory'], environment => deployAccountingFactory_1.deployAccountingFactory(environment)), maybeDeploy(['factories', 'feeManagerFactory'], environment => deployFeeManagerFactory_1.deployFeeManagerFactory(environment)), maybeDeploy(['factories', 'participationFactory'], environment => deployParticipationFactory_1.deployParticipationFactory(environment)), maybeDeploy(['factories', 'policyManagerFactory'], environment => deployPolicyManagerFactory_1.deployPolicyManagerFactory(environment)), maybeDeploy(['factories', 'sharesFactory'], environment => deploySharesFactory_1.deploySharesFactory(environment)), maybeDeploy(['factories', 'tradingFactory'], environment => deployTradingFactory_1.deployTradingFactory(environment)), maybeDeploy(['factories', 'vaultFactory'], environment => deployVaultFactory_1.deployVaultFactory(environment)), maybeDeploy(['registry'], environment => deployRegistry_1.deployRegistry(environment, control.registryOwner || environment.wallet.address)), maybeDeploy(['engine'], environment => deployEngine_1.deployEngine(environment, {
delay: monthInSeconds,
registry: environment.deployment.melonContracts.registry,
})), maybeDeploy(['priceSource'], environment => environment.track === Environment_1.Tracks.KYBER_PRICE
? deployKyberPriceFeed_1.deployKyberPriceFeed(environment, {
// tslint:disable-next-line:max-line-length
kyberNetworkProxy: environment.deployment.thirdPartyContracts.exchanges.kyber
.kyberNetworkProxy,
maxSpread: 0.1,
quoteToken: wethToken,
registry: environment.deployment.melonContracts.registry,
})
: deployTestingPriceFeed_1.deployTestingPriceFeed(environment, wethToken)), maybeDoSomething(adoptedContracts.priceSource === 'DEPLOY' ||
adoptedContracts.registry === 'DEPLOY', (environment) => __awaiter(this, void 0, void 0, function* () {
const { melonContracts } = environment.deployment;
getLog(environment).info('Register priceSource');
yield setPriceSource_1.setPriceSource(environment, melonContracts.registry, {
address: melonContracts.priceSource,
});
})), maybeDoSomething(
// TODO: some of these can be conditional
true, // ensure these steps are done at each deployment
(environment) => __awaiter(this, void 0, void 0, function* () {
const { melonContracts } = environment.deployment;
const previousInfo = yield getRegistryInformation_1.getRegistryInformation(environment, melonContracts.registry);
if (R.pathOr('', ['nativeAsset', 'address'], previousInfo).toLowerCase() !== wethToken.address.toLowerCase()) {
getLog(environment).info('Setting native token');
yield setNativeAsset_1.setNativeAsset(environment, melonContracts.registry, {
address: wethToken.address,
});
}
if (R.pathOr('', ['mlnToken', 'address'], previousInfo).toLowerCase() !==
mlnToken.address.toLowerCase()) {
getLog(environment).info('Setting MLN token');
yield setMlnToken_1.setMlnToken(environment, melonContracts.registry, {
address: mlnToken.address,
});
}
if (R.pathOr('', ['engine'], previousInfo).toLowerCase() !==
melonContracts.engine.toLowerCase()) {
getLog(environment).info('Setting engine on registry');
yield setEngine_1.setEngine(environment, melonContracts.registry, {
address: melonContracts.engine,
});
}
getLog(environment).info('Setting MGM on registry');
yield setMGM_1.setMGM(environment, melonContracts.registry, {
address: control.MGM || environment.wallet.address,
});
if (R.pathOr('', ['ethfinexWrapperRegistry'], previousInfo).toLowerCase() !==
thirdPartyContracts.exchanges.ethfinex.wrapperRegistryEFX.toLowerCase()) {
getLog(environment).info('Setting ethfinex wrapper registry');
yield setEthfinexWrapperRegistry_1.setEthfinexWrapperRegistry(environment, melonContracts.registry, {
address: thirdPartyContracts.exchanges.ethfinex.wrapperRegistryEFX,
});
}
})), maybeDoSomething(true, (environment) => __awaiter(this, void 0, void 0, function* () {
// TODO: make this conditional
const { melonContracts } = environment.deployment;
const fees = [
melonContracts.fees.managementFee,
melonContracts.fees.performanceFee,
];
const unregistered = [];
for (const fee of fees) {
if (!(yield isFeeRegistered_1.isFeeRegistered(environment, melonContracts.registry, {
fee,
}))) {
unregistered.push(fee);
}
}
if (unregistered.length > 0) {
getLog(environment).info('Registering fees');
yield registerFees_1.registerFees(environment, melonContracts.registry, {
addresses: unregistered.map(e => e.toString()),
});
}
})), maybeDeploy(['ranking'], environment => deployFundRanking_1.deployFundRanking(environment)), maybeDeploy(['version'], environment => deployVersion_1.deployVersion(environment, {
factories: environment.deployment.melonContracts.factories,
postDeployOwner: control.versionOwner || environment.wallet.address,
registry: environment.deployment.melonContracts.registry,
})), maybeDoSomething(true, (environment) => __awaiter(this, void 0, void 0, function* () {
// TODO: make this conditional
yield setMGM_1.setMGM(environment, environment.deployment.melonContracts.registry, {
// used for setting initial amguPrice
address: environment.wallet.address,
});
const amguToken = yield getAmguToken_1.getAmguToken(environment, environment.deployment.melonContracts.version);
yield setAmguPrice_1.setAmguPrice(environment, environment.deployment.melonContracts.engine, token_math_1.createQuantity(amguToken, 0));
yield setMGM_1.setMGM(environment, environment.deployment.melonContracts.registry, {
// used for setting initial amguPrice
address: control.MGM || environment.wallet.address,
});
})))(new Promise(resolve => resolve(environment)));
const { melonContracts } = environmentWithDeployment.deployment;
const registryInformation = yield getRegistryInformation_1.getRegistryInformation(environmentWithDeployment, melonContracts.registry);
const versionInformation = yield getVersionInformation_1.getVersionInformation(environment, melonContracts.registry, { version: melonContracts.version });
if (!versionInformation) {
yield registerVersion_1.registerVersion(environment, melonContracts.registry, {
address: melonContracts.version,
name: pkg.version,
});
}
const exchangeConfigs = {
[Contracts_1.Exchanges.MatchingMarket]: {
adapter: melonContracts.adapters.matchingMarketAdapter,
exchange: thirdPartyContracts.exchanges.matchingMarket,
takesCustody: true,
},
[Contracts_1.Exchanges.KyberNetwork]: {
adapter: melonContracts.adapters.kyberAdapter,
exchange: thirdPartyContracts.exchanges.kyber.kyberNetworkProxy,
takesCustody: false,
},
[Contracts_1.Exchanges.ZeroEx]: {
adapter: melonContracts.adapters.zeroExAdapter,
exchange: thirdPartyContracts.exchanges.zeroEx,
takesCustody: false,
},
[Contracts_1.Exchanges.Ethfinex]: {
adapter: melonContracts.adapters.ethfinexAdapter,
exchange: thirdPartyContracts.exchanges.ethfinex.exchange,
takesCustody: true,
},
[Contracts_1.Exchanges.MelonEngine]: {
adapter: melonContracts.adapters.engineAdapter,
exchange: melonContracts.engine,
takesCustody: false,
},
};
for (const [exchangeName, exchangeConfig] of R.toPairs(exchangeConfigs)) {
const adapter = exchangeConfig.adapter.toLowerCase();
// HACK: Blindly just update all registered exchanges on every deploy
// TODO: Check the individual entries (address, adapter, takesCustory, sigs)
// and only update if changed
const action = registryInformation.registeredExchanges[adapter]
? updateExchangeAdapter_1.updateExchangeAdapter
: registerExchangeAdapter_1.registerExchangeAdapter;
// Action.name is "execute" for both
const actionName = registryInformation.registeredExchanges[adapter]
? 'updateExchangeAdapter'
: 'registerExchangeAdapter';
const args = {
adapter: exchangeConfig.adapter,
exchange: exchangeConfig.exchange,
sigs: [
FunctionSignatures_1.FunctionSignatures.makeOrder,
FunctionSignatures_1.FunctionSignatures.takeOrder,
FunctionSignatures_1.FunctionSignatures.cancelOrder,
FunctionSignatures_1.FunctionSignatures.withdrawTokens,
],
takesCustody: exchangeConfig.takesCustody,
};
log.debug(actionName, exchangeName, args);
yield action(environment, melonContracts.registry, args);
}
for (const asset of thirdPartyContracts.tokens) {
if (!registryInformation.registeredAssets[asset.address.toLowerCase()]) {
yield registerAsset_1.registerAsset(environment, melonContracts.registry, {
assetAddress: `${asset.address}`,
assetSymbol: asset.symbol,
name: '',
reserveMin: `${asset.reserveMin || 0}`,
sigs: [],
standards: [],
url: '',
});
if (environment.track !== Environment_1.Tracks.KYBER_PRICE) {
yield setDecimals_1.setDecimals(environment, melonContracts.priceSource, asset);
}
}
}
if (environment.track === Environment_1.Tracks.KYBER_PRICE) {
yield updateKyber_1.updateKyber(environmentWithDeployment, environmentWithDeployment.deployment.melonContracts.priceSource);
}
else if (environment.track === Environment_1.Tracks.TESTING) {
const prices = yield updateTestingPriceFeed_1.getConvertedPrices(environmentWithDeployment, 'ETH');
const testingPriceFeed = yield getContract_1.getContract(environmentWithDeployment, Contracts_1.Contracts.TestingPriceFeed, environmentWithDeployment.deployment.melonContracts.priceSource);
yield testingPriceFeed.methods
.update(Object.keys(prices), Object.values(prices).map(e => e.toString()))
.send({ from: environmentWithDeployment.wallet.address, gas: 8000000 });
}
const track = environment.track;
const network = yield environment.eth.net.getId();
const deploymentId = `${network}:${track}`;
// tslint:disable:object-literal-sort-keys
const deployment = {
meta: {
deployer: environment.wallet.address,
timestamp: new Date().toISOString(),
track,
version: pkg.version,
chain: network,
description,
},
melonContracts: melonContracts,
thirdPartyContracts,
exchangeConfigs,
};
log.info('Deployed:', deploymentId);
log.debug('Deployed:', deployment);
return Object.assign({}, environment, { deployment });
});