UNPKG

@melonproject/protocol

Version:

Technology Regulated and Operated Investment Funds

344 lines (343 loc) 21.3 kB
"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 }); });