UNPKG

@melonproject/protocol

Version:

Technology Regulated and Operated Investment Funds

126 lines (125 loc) 6.13 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 zen_observable_ts_1 = require("zen-observable-ts"); const R = __importStar(require("ramda")); const Environment_1 = require("../environment/Environment"); const getContract_1 = require("./getContract"); const ensure_1 = require("../guards/ensure"); const token_math_1 = require("@melonproject/token-math"); const defaultPrepareArgs = (environment, params, contractAddress) => Object.values(params || {}).map(v => v.toString()); const defaultPostProcess = (environment, result, prepared) => result; const defaultProcessors = { postProcess: defaultPostProcess, prepareArgs: defaultPrepareArgs, }; const callFactory = (name, contract, processors = defaultProcessors) => { const { postProcess, prepareArgs } = Object.assign({}, defaultProcessors, processors); const prepare = (environment, contractAddress, params = {}) => { ensure_1.ensure(token_math_1.isAddress(contractAddress), `Invalid contract address provided: ${contractAddress}`); const log = environment.logger('melon:protocol:utils:solidity:callFactory'); const args = prepareArgs(environment, params, contractAddress); const txId = `${contract}@${contractAddress}.${name}(${args.join(',')})`; try { log(Environment_1.LogLevels.INFO, 'Prepare call', txId); const contractInstance = getContract_1.getContract(environment, contract, contractAddress); const txObject = contractInstance.methods[name](...args); const prepared = { contractAddress, params, txObject, }; return prepared; } catch (error) { log(Environment_1.LogLevels.ERROR, txId, error); throw new Error( // tslint:disable-next-line:max-line-length `Error in prepare call ${txId}): ${error.message}`); } }; const call = (environment, prepared) => __awaiter(this, void 0, void 0, function* () { const log = environment.logger('melon:protocol:utils:solidity:callFactory'); const txId = `${contract}@${prepared.contractAddress}.${name}(${prepared.txObject.arguments.join(',')})`; let result; try { result = yield prepared.txObject.call(); } catch (error) { log(Environment_1.LogLevels.ERROR, txId, error); throw new Error(`Call failed. ${txId}: ${error.message}`); } try { const postProcessed = yield postProcess(environment, result, prepared); log(Environment_1.LogLevels.DEBUG, 'Call processed', txId, { result, postProcessed }); return postProcessed; } catch (error) { log(Environment_1.LogLevels.ERROR, txId, result, error); throw error; // throw new Error(`Postprocess failed. ${txId}: ${error.message}`); } }); // TODO: Possibility to specify custom filters // TODO: Check if newBlockHeaders & multiple subscriptions lead to // performance problems? const observable = (environment, contractAddress, params) => new zen_observable_ts_1.Observable(observer => { let lastResult; const prepared = prepare(environment, contractAddress, params); const subscription = environment.eth.subscribe('newBlockHeaders'); subscription.on('data', (block) => __awaiter(this, void 0, void 0, function* () { if (block.number) { const result = yield call(environment, prepared); if (!R.equals(result, lastResult)) { observer.next(result); lastResult = result; } } })); // TODO: Better error handling (what kind of errors do we expect?) subscription.on('error', error => { observer.error(error); }); return () => subscription.unsubscribe(); }); const execute = (environment, contractAddress, params = {}) => __awaiter(this, void 0, void 0, function* () { const prepared = prepare(environment, contractAddress, params); const result = yield call(environment, prepared); return result; }); execute.prepare = prepare; execute.call = call; execute.observable = observable; return execute; }; exports.callFactory = callFactory; const callFactoryWithoutParams = (name, contract, processors) => { const withParams = callFactory(name, contract, processors); const prepare = (environment, contractAddress) => withParams.prepare(environment, contractAddress, {}); const call = withParams.call; const observable = (environment, contractAddress) => withParams.observable(environment, contractAddress, {}); const execute = (environment, contractAddress) => __awaiter(this, void 0, void 0, function* () { const prepared = prepare(environment, contractAddress); const result = yield call(environment, prepared); return result; }); execute.prepare = prepare; execute.call = call; execute.observable = observable; return execute; }; exports.callFactoryWithoutParams = callFactoryWithoutParams;