@melonproject/protocol
Version:
Technology Regulated and Operated Investment Funds
126 lines (125 loc) • 6.13 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());
});
};
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;