diff --git a/.gitignore b/.gitignore index 130b731..98139e5 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,7 @@ package-lock.json .node_repl_history # Built TS -dist/ +# dist/ docs/ # ide diff --git a/CHANGELOG.md b/CHANGELOG.md index 02e051d..bce219a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 4.4.0 + +- **Feature:** + - Add support for querying subsequent interchain verifications +- **Bug Fix:** + - Fix type import on `L2BlockAtRest` from current_ddds to current_ddss + ## 4.3.4 - **Development:** diff --git a/dist/errors/FailureByDesign.js b/dist/errors/FailureByDesign.js new file mode 100644 index 0000000..584bc5e --- /dev/null +++ b/dist/errors/FailureByDesign.js @@ -0,0 +1,33 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var tslib_1 = require("tslib"); +/** + * Error class thrown by the SDK + * All expected errors thrown by the SDK should be an instantiation of this class, with different codes as appropriate + */ +var FailureByDesign = /** @class */ (function (_super) { + tslib_1.__extends(FailureByDesign, _super); + function FailureByDesign(code, message) { + var _this = _super.call(this, message) || this; + _this.code = code; + _this.message = message || 'Failure By Design'; + return _this; + } + return FailureByDesign; +}(Error)); +exports.FailureByDesign = FailureByDesign; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..f6144b8 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,40 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var DragonchainClient_1 = require("./services/dragonchain-client/DragonchainClient"); +exports.createClient = DragonchainClient_1.createClient; +/** + * @hidden + */ +var nullLog = function () { }; // eslint-disable-line @typescript-eslint/no-empty-function +/** + * @hidden + */ +var logger; // singleton logger +exports.logger = logger; +/** + * Set the logger that the sdk uses + * + * By default this logger will do nothing, thorwing away all logs + * @param newLogger a logger object that implements functions for: `log`, `info`, `warn`, `error`, and `debug` + */ +var setLogger = function (newLogger) { + if (newLogger === void 0) { newLogger = { log: nullLog, info: nullLog, warn: nullLog, error: nullLog, debug: nullLog }; } + exports.logger = logger = newLogger; +}; +exports.setLogger = setLogger; +setLogger(); // actually initialize the singleton on initial import diff --git a/dist/interfaces/DragonchainClientInterfaces.js b/dist/interfaces/DragonchainClientInterfaces.js new file mode 100644 index 0000000..abddbb2 --- /dev/null +++ b/dist/interfaces/DragonchainClientInterfaces.js @@ -0,0 +1,17 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/services/config-service/ConfigCient.js b/dist/services/config-service/ConfigCient.js new file mode 100644 index 0000000..fa919aa --- /dev/null +++ b/dist/services/config-service/ConfigCient.js @@ -0,0 +1,343 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var tslib_1 = require("tslib"); +var fs_1 = require("fs"); +var util_1 = require("util"); +var os_1 = require("os"); +var path = require("path"); +var ini = require("ini"); +var node_fetch_1 = require("node-fetch"); +var FailureByDesign_1 = require("../../errors/FailureByDesign"); +var index_1 = require("../../index"); +/** + * @hidden + */ +var readFileAsync = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { + return [2 /*return*/, '']; +}); }); }; +if (fs_1.readFile) + readFileAsync = util_1.promisify(fs_1.readFile); +/** + * @hidden + * Get the path for the configuration file depending on the OS + * @returns {string} dragonchain configuration file path + * @example e.g.: "~/.dragonchain/credentials" or "%LOCALAPPDATA%\dragonchain\credentials" on Windows + */ +var getConfigFilePath = function (injected) { + if (injected === void 0) { injected = { platform: os_1.platform, homedir: os_1.homedir }; } + if (injected.platform() === 'win32') { + return path.join(process.env.LOCALAPPDATA || '', 'dragonchain', 'credentials'); + } + return path.join(injected.homedir(), '.dragonchain', 'credentials'); +}; +exports.getConfigFilePath = getConfigFilePath; +/** + * @hidden + * Get the endpoint for a dragonchain from environment variables + * @returns {string} Dragonchain enpdoint if found, empty string if not + */ +var getIdFromEnvVars = function () { + return process.env.DRAGONCHAIN_ID || ''; +}; +exports.getIdFromEnvVars = getIdFromEnvVars; +/** + * @hidden + * get the endpoint for a dragonchain from environment variables + * @returns {string} Dragonchain enpdoint if found, empty string if not + */ +var getEndpointFromEnvVars = function () { + return process.env.DRAGONCHAIN_ENDPOINT || ''; +}; +exports.getEndpointFromEnvVars = getEndpointFromEnvVars; +/** + * @hidden + * get the credentials for a dragonchain from environment variables + * @returns {DragonchainCredentials} Dragonchain enpdoint if found, false if not + */ +var getCredsFromEnvVars = function () { + var authKey = process.env.AUTH_KEY; + var authKeyId = process.env.AUTH_KEY_ID; + if (!authKey || !authKeyId) + return false; + return { authKey: authKey, authKeyId: authKeyId }; +}; +exports.getCredsFromEnvVars = getCredsFromEnvVars; +/** + * @hidden + * get the default dragonchain ID from the configuration file + * @returns {Promise} dragonchain ID if found in file, empty string if not + */ +var getIdFromFile = function (injected) { + if (injected === void 0) { injected = { readFileAsync: readFileAsync }; } + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var config, _a, _b, e_1; + return tslib_1.__generator(this, function (_c) { + switch (_c.label) { + case 0: + config = {}; + _c.label = 1; + case 1: + _c.trys.push([1, 3, , 4]); + _b = (_a = ini).parse; + return [4 /*yield*/, injected.readFileAsync(getConfigFilePath(), 'utf-8')]; + case 2: + config = _b.apply(_a, [_c.sent()]); + return [3 /*break*/, 4]; + case 3: + e_1 = _c.sent(); + index_1.logger.debug("Error loading ID from config file " + e_1); + return [2 /*return*/, '']; + case 4: return [2 /*return*/, config.default && config.default.dragonchain_id ? config.default.dragonchain_id : '']; + } + }); + }); +}; +exports.getIdFromFile = getIdFromFile; +/** + * @hidden + * get the dragonchain endpoint from the configuration file + * @returns {Promise} dragonchain endpoint if found in file, empty string if not + */ +var getEndpointFromFile = function (dragonchainId, injected) { + if (injected === void 0) { injected = { readFileAsync: readFileAsync }; } + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var config, _a, _b, e_2; + return tslib_1.__generator(this, function (_c) { + switch (_c.label) { + case 0: + config = {}; + _c.label = 1; + case 1: + _c.trys.push([1, 3, , 4]); + _b = (_a = ini).parse; + return [4 /*yield*/, injected.readFileAsync(getConfigFilePath(), 'utf-8')]; + case 2: + config = _b.apply(_a, [_c.sent()]); + return [3 /*break*/, 4]; + case 3: + e_2 = _c.sent(); + index_1.logger.debug("Error loading from config file " + e_2); + return [2 /*return*/, '']; + case 4: return [2 /*return*/, config[dragonchainId] && config[dragonchainId].endpoint ? config[dragonchainId].endpoint : '']; + } + }); + }); +}; +exports.getEndpointFromFile = getEndpointFromFile; +/** + * @hidden + * get the dragonchain credentials from the configuration file + * @returns {Promise} dragonchain credentials if found in file, false if not + */ +var getCredsFromFile = function (dragonchainId, injected) { + if (injected === void 0) { injected = { readFileAsync: readFileAsync }; } + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var config, _a, _b, e_3, _c, auth_key, auth_key_id; + return tslib_1.__generator(this, function (_d) { + switch (_d.label) { + case 0: + config = {}; + _d.label = 1; + case 1: + _d.trys.push([1, 3, , 4]); + _b = (_a = ini).parse; + return [4 /*yield*/, injected.readFileAsync(getConfigFilePath(), 'utf-8')]; + case 2: + config = _b.apply(_a, [_d.sent()]); + return [3 /*break*/, 4]; + case 3: + e_3 = _d.sent(); + index_1.logger.debug("Error loading credentials from config file " + e_3); + return [2 /*return*/, false]; + case 4: + if (!config[dragonchainId]) + return [2 /*return*/, false]; + _c = config[dragonchainId], auth_key = _c.auth_key, auth_key_id = _c.auth_key_id; + if (!auth_key || !auth_key_id) + return [2 /*return*/, false]; + return [2 /*return*/, { + authKey: auth_key, + authKeyId: auth_key_id, + }]; + } + }); + }); +}; +exports.getCredsFromFile = getCredsFromFile; +/** + * @hidden + * use a remote service to fetch the endpoint of a dragonchain by id + * @param {string} dragonchainId dragonchainId to request endpoint for + * @returns {Promise} the endpoint of the dragonchain + * @throws {FailureByDesign} if unable to contact remote service or not found + */ +var getEndpointFromRemote = function (dragonchainId, injected) { + if (injected === void 0) { injected = { fetch: node_fetch_1.default }; } + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var result, json, endpoint, e_4; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 2, , 3]); + return [4 /*yield*/, injected.fetch("https://matchmaking.api.dragonchain.com/registration/" + dragonchainId, { timeout: 30000 })]; + case 1: + result = _a.sent(); + json = result.json(); + endpoint = json.url; + if (!endpoint) + throw new Error("Bad response from remote service " + json); // Caught and re-thrown below + return [2 /*return*/, endpoint]; + case 2: + e_4 = _a.sent(); + throw new FailureByDesign_1.FailureByDesign('NOT_FOUND', "Failure to retrieve dragonchain endpoint from remote service " + e_4); + case 3: return [2 /*return*/]; + } + }); + }); +}; +exports.getEndpointFromRemote = getEndpointFromRemote; +/** + * @hidden + * get credentials for a dragonchain from the standard location for a smart contract + * @returns {Promise} dragonchain credentials if found, false if not + */ +var getCredsAsSmartContract = function (injected) { + if (injected === void 0) { injected = { readFileAsync: readFileAsync }; } + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var authKeyId, authKey, basePath, e_5; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + authKeyId = ''; + authKey = ''; + basePath = path.join('/', 'var', 'openfaas', 'secrets'); + _a.label = 1; + case 1: + _a.trys.push([1, 4, , 5]); + return [4 /*yield*/, injected.readFileAsync(path.join(basePath, "sc-" + process.env.SMART_CONTRACT_ID + "-auth-key-id"), 'utf-8')]; + case 2: + authKeyId = _a.sent(); + return [4 /*yield*/, injected.readFileAsync(path.join(basePath, "sc-" + process.env.SMART_CONTRACT_ID + "-secret-key"), 'utf-8')]; + case 3: + authKey = _a.sent(); + return [3 /*break*/, 5]; + case 4: + e_5 = _a.sent(); + index_1.logger.debug("Error loading credentials from SC location " + e_5); + return [2 /*return*/, false]; + case 5: + if (!authKeyId || !authKey) + return [2 /*return*/, false]; + return [2 /*return*/, { authKey: authKey, authKeyId: authKeyId }]; + } + }); + }); +}; +exports.getCredsAsSmartContract = getCredsAsSmartContract; +/** + * Get the default configured dragonchainId from environment/config file + * @returns {Promise} + * @throws {FailureByDesign} + */ +var getDragonchainId = function (injected) { + if (injected === void 0) { injected = { getIdFromEnvVars: getIdFromEnvVars, getIdFromFile: getIdFromFile }; } + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var dragonchainId; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + index_1.logger.debug('Checking if dragonchain_id is in the environment'); + dragonchainId = injected.getIdFromEnvVars(); + if (dragonchainId) + return [2 /*return*/, dragonchainId]; + index_1.logger.debug('Dragonchain ID not provided in environment, will search on disk'); + return [4 /*yield*/, injected.getIdFromFile()]; + case 1: + dragonchainId = _a.sent(); + if (dragonchainId) + return [2 /*return*/, dragonchainId]; + throw new FailureByDesign_1.FailureByDesign('NOT_FOUND', 'Configuration file is missing a default id'); + } + }); + }); +}; +exports.getDragonchainId = getDragonchainId; +/** + * @hidden + * Get the endpoint for a dragonchain. First checks environment, then configuration files, then a remote service + * @param {string} dragonchainId dragonchainId to get endpoint for + * @returns {Promise} Endpoint of the dragonchain + * @throws {FailureByDesign} + */ +var getDragonchainEndpoint = function (dragonchainId, injected) { + if (injected === void 0) { injected = { getEndpointFromEnvVars: getEndpointFromEnvVars, getEndpointFromFile: getEndpointFromFile, getEndpointFromRemote: getEndpointFromRemote }; } + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var endpoint; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + endpoint = injected.getEndpointFromEnvVars(); + if (endpoint) + return [2 /*return*/, endpoint]; + index_1.logger.debug("Endpoint isn't in environment, trying to load from ini config file"); + return [4 /*yield*/, injected.getEndpointFromFile(dragonchainId)]; + case 1: + endpoint = _a.sent(); + if (endpoint) + return [2 /*return*/, endpoint]; + index_1.logger.debug("Endpoint isn't in config file, trying to load from remote service"); + return [2 /*return*/, injected.getEndpointFromRemote(dragonchainId)]; // This will throw NOT_FOUND if necessary + } + }); + }); +}; +exports.getDragonchainEndpoint = getDragonchainEndpoint; +/** + * Get the credentials for a dragonchain. First checks environment, then configuration files, then a smart contract location + * @param {string} dragonchainId dragonchainId to get credentials for + * @returns {DragonchainCredentials} Credentials of the dragonchain + * @throws {FailureByDesign} + */ +var getDragonchainCredentials = function (dragonchainId, injected) { + if (injected === void 0) { injected = { getCredsFromEnvVars: getCredsFromEnvVars, getCredsFromFile: getCredsFromFile, getCredsAsSmartContract: getCredsAsSmartContract }; } + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var credentials; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + credentials = injected.getCredsFromEnvVars(); + if (credentials) + return [2 /*return*/, credentials]; + index_1.logger.debug("Credentials aren't in environment, trying to load from ini config file"); + return [4 /*yield*/, injected.getCredsFromFile(dragonchainId)]; + case 1: + credentials = _a.sent(); + if (credentials) + return [2 /*return*/, credentials]; + index_1.logger.debug("Credentials aren't in config file, trying to load as a smart contract"); + return [4 /*yield*/, injected.getCredsAsSmartContract()]; + case 2: + credentials = _a.sent(); + if (credentials) + return [2 /*return*/, credentials]; + throw new FailureByDesign_1.FailureByDesign('NOT_FOUND', "Credentials for " + dragonchainId + " could not be found"); + } + }); + }); +}; +exports.getDragonchainCredentials = getDragonchainCredentials; diff --git a/dist/services/config-service/ConfigClient.spec.js b/dist/services/config-service/ConfigClient.spec.js new file mode 100644 index 0000000..8397a35 --- /dev/null +++ b/dist/services/config-service/ConfigClient.spec.js @@ -0,0 +1,517 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var tslib_1 = require("tslib"); +var chai_1 = require("chai"); +var ConfigClient = require("./ConfigCient"); +describe('ConfigClient', function () { + describe('#getConfigFilePath', function () { + it('returns correct path on windows', function () { + var platform = function () { return 'win32'; }; + process.env.LOCALAPPDATA = 'test'; + chai_1.expect(ConfigClient.getConfigFilePath({ platform: platform })).to.equal('test/dragonchain/credentials'); + }); + it('returns correct path on non-windows', function () { + var platform = function () { return 'something_else'; }; + var homedir = function () { return '/home'; }; + chai_1.expect(ConfigClient.getConfigFilePath({ platform: platform, homedir: homedir })).to.equal('/home/.dragonchain/credentials'); + }); + }); + describe('#getIdFromEnvVars', function () { + it('returns the DRAGONCHAIN_ID env var if present', function () { + process.env.DRAGONCHAIN_ID = 'test'; + chai_1.expect(ConfigClient.getIdFromEnvVars()).to.equal('test'); + }); + it('returns an empty string if the DRAGONCHAIN_ID env var is not present', function () { + delete process.env.DRAGONCHAIN_ID; + chai_1.expect(ConfigClient.getIdFromEnvVars()).to.equal(''); + }); + }); + describe('#getEndpointFromEnvVars', function () { + it('returns the DRAGONCHAIN_ENDPOINT env var if present', function () { + process.env.DRAGONCHAIN_ENDPOINT = 'test'; + chai_1.expect(ConfigClient.getEndpointFromEnvVars()).to.equal('test'); + }); + it('returns an empty string if the DRAGONCHAIN_ENDPOINT env var is not present', function () { + delete process.env.DRAGONCHAIN_ENDPOINT; + chai_1.expect(ConfigClient.getEndpointFromEnvVars()).to.equal(''); + }); + }); + describe('#getCredsFromEnvVars', function () { + it('returns the credentials if AUTH_KEY and AUTH_KEY_ID env vars are present', function () { + process.env.AUTH_KEY = 'testKey'; + process.env.AUTH_KEY_ID = 'testId'; + chai_1.expect(ConfigClient.getCredsFromEnvVars()).to.deep.equal({ authKey: 'testKey', authKeyId: 'testId' }); + }); + it('returns false if AUTH_KEY and AUTH_KEY_ID env vars are not present', function () { + delete process.env.AUTH_KEY; + chai_1.expect(ConfigClient.getCredsFromEnvVars()).to.equal(false); + }); + }); + describe('#getIdFromFile', function () { + it('returns dragonchain id from correct section if present', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { return '[default]\ndragonchain_id = test'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getIdFromFile({ readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal('test'); + return [2 /*return*/]; + } + }); + }); }); + it('returns an empty string on file open error', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { + throw new Error(); + }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getIdFromFile({ readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal(''); + return [2 /*return*/]; + } + }); + }); }); + it('returns an empty string if the correct ini section does not exist', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { return '[notDefault]\nsomething = test'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getIdFromFile({ readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal(''); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('#getEndpointFromFile', function () { + it('returns endpoint from correct section if present', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { return '[id]\nendpoint = test'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getEndpointFromFile('id', { readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal('test'); + return [2 /*return*/]; + } + }); + }); }); + it('returns an empty string on file open error', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { + throw new Error(); + }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getEndpointFromFile('id', { readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal(''); + return [2 /*return*/]; + } + }); + }); }); + it('returns an empty string if the correct ini section does not exist', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { return '[something]\nsomething = test'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getEndpointFromFile('id', { readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal(''); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('#getCredsFromFile', function () { + it('returns credentials from correct section if present', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { return '[id]\nauth_key = key\nauth_key_id = key_id'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getCredsFromFile('id', { readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.deep.equal({ authKey: 'key', authKeyId: 'key_id' }); + return [2 /*return*/]; + } + }); + }); }); + it('returns false on file open error', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { + throw new Error(); + }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getCredsFromFile('id', { readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal(false); + return [2 /*return*/]; + } + }); + }); }); + it('returns false if the correct ini section does not exist', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { return '[something]\nsomething = test'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getCredsFromFile('id', { readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal(false); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('#getEndpointFromRemote', function () { + it('returns endpoint from remote service', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFetch, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFetch = function () { + return { + json: function () { + return { url: 'test' }; + }, + }; + }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getEndpointFromRemote('id', { fetch: fakeFetch })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal('test'); + return [2 /*return*/]; + } + }); + }); }); + it('throws NOT_FOUND when unexpected response schema from remote', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFetch, e_1; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeFetch = function () { + return { + json: function () { + return { notUrl: 'test' }; + }, + }; + }; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, ConfigClient.getEndpointFromRemote('id', { fetch: fakeFetch })]; + case 2: + _a.sent(); + return [3 /*break*/, 4]; + case 3: + e_1 = _a.sent(); + chai_1.expect(e_1.code).to.equal('NOT_FOUND'); + return [2 /*return*/]; + case 4: + chai_1.expect.fail(); + return [2 /*return*/]; + } + }); + }); }); + it('throws NOT_FOUND when erroring while fetching from remote', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFetch, e_2; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeFetch = function () { + throw new Error(); + }; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, ConfigClient.getEndpointFromRemote('id', { fetch: fakeFetch })]; + case 2: + _a.sent(); + return [3 /*break*/, 4]; + case 3: + e_2 = _a.sent(); + chai_1.expect(e_2.code).to.equal('NOT_FOUND'); + return [2 /*return*/]; + case 4: + chai_1.expect.fail(); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('#getCredsAsSmartContract', function () { + it('returns false when credentials arent found in files', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { + throw new Error(); + }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getCredsAsSmartContract({ readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal(false); + return [2 /*return*/]; + } + }); + }); }); + it('returns values from files as credentials', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + fakeFile = function () { return 'thing'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getCredsAsSmartContract({ readFileAsync: fakeFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.deep.equal({ authKey: 'thing', authKeyId: 'thing' }); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('#getDragonchainId', function () { + it('returns ID from env vars', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var getIdFromEnvVars, getIdFromFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + getIdFromEnvVars = function () { return 'envId'; }; + getIdFromFile = function () { return 'fileId'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getDragonchainId({ getIdFromEnvVars: getIdFromEnvVars, getIdFromFile: getIdFromFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal('envId'); + return [2 /*return*/]; + } + }); + }); }); + it('returns ID from config file', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var getIdFromEnvVars, getIdFromFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + getIdFromEnvVars = function () { return ''; }; + getIdFromFile = function () { return 'fileId'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getDragonchainId({ getIdFromEnvVars: getIdFromEnvVars, getIdFromFile: getIdFromFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal('fileId'); + return [2 /*return*/]; + } + }); + }); }); + it('throws NOT_FOUND when not found', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var getIdFromEnvVars, getIdFromFile, e_3; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + getIdFromEnvVars = function () { return ''; }; + getIdFromFile = function () { return ''; }; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, ConfigClient.getDragonchainId({ getIdFromEnvVars: getIdFromEnvVars, getIdFromFile: getIdFromFile })]; + case 2: + _a.sent(); + return [3 /*break*/, 4]; + case 3: + e_3 = _a.sent(); + chai_1.expect(e_3.code).to.equal('NOT_FOUND'); + return [2 /*return*/]; + case 4: + chai_1.expect.fail(); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('#getDragonchainEndpoint', function () { + it('returns Endpoint from env vars', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var getEndpointFromEnvVars, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + getEndpointFromEnvVars = function () { return 'envEndpoint'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getDragonchainEndpoint('id', { getEndpointFromEnvVars: getEndpointFromEnvVars })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal('envEndpoint'); + return [2 /*return*/]; + } + }); + }); }); + it('returns Endpoint from config file', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var getEndpointFromEnvVars, getEndpointFromFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + getEndpointFromEnvVars = function () { return ''; }; + getEndpointFromFile = function () { return 'fileEndpoint'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getDragonchainEndpoint('id', { getEndpointFromEnvVars: getEndpointFromEnvVars, getEndpointFromFile: getEndpointFromFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal('fileEndpoint'); + return [2 /*return*/]; + } + }); + }); }); + it('returns Endpoint from remote', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var getEndpointFromEnvVars, getEndpointFromFile, getEndpointFromRemote, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + getEndpointFromEnvVars = function () { return ''; }; + getEndpointFromFile = function () { return ''; }; + getEndpointFromRemote = function () { return 'remoteEndpoint'; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getDragonchainEndpoint('id', { getEndpointFromEnvVars: getEndpointFromEnvVars, getEndpointFromFile: getEndpointFromFile, getEndpointFromRemote: getEndpointFromRemote })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal('remoteEndpoint'); + return [2 /*return*/]; + } + }); + }); }); + it('throws Error from getEndpointFromRemote', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var error, getEndpointFromEnvVars, getEndpointFromFile, getEndpointFromRemote, e_4; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + error = new Error('thing'); + getEndpointFromEnvVars = function () { return ''; }; + getEndpointFromFile = function () { return ''; }; + getEndpointFromRemote = function () { + throw error; + }; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, ConfigClient.getDragonchainEndpoint('id', { getEndpointFromEnvVars: getEndpointFromEnvVars, getEndpointFromFile: getEndpointFromFile, getEndpointFromRemote: getEndpointFromRemote })]; + case 2: + _a.sent(); + return [3 /*break*/, 4]; + case 3: + e_4 = _a.sent(); + chai_1.expect(e_4).to.equal(error); + return [2 /*return*/]; + case 4: + chai_1.expect.fail(); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('#getDragonchainCredentials', function () { + it('returns credentials from env vars', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var creds, getCredsFromEnvVars, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + creds = { authKey: 'thing', authKeyId: 'keyid' }; + getCredsFromEnvVars = function () { return creds; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getDragonchainCredentials('id', { getCredsFromEnvVars: getCredsFromEnvVars })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal(creds); + return [2 /*return*/]; + } + }); + }); }); + it('returns credentials from config file', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var creds, getCredsFromEnvVars, getCredsFromFile, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + creds = { authKey: 'thing', authKeyId: 'keyid' }; + getCredsFromEnvVars = function () { return false; }; + getCredsFromFile = function () { return creds; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getDragonchainCredentials('id', { getCredsFromEnvVars: getCredsFromEnvVars, getCredsFromFile: getCredsFromFile })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal(creds); + return [2 /*return*/]; + } + }); + }); }); + it('returns credentials from smart contract location', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var creds, getCredsFromEnvVars, getCredsFromFile, getCredsAsSmartContract, _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + creds = { authKey: 'thing', authKeyId: 'keyid' }; + getCredsFromEnvVars = function () { return false; }; + getCredsFromFile = function () { return false; }; + getCredsAsSmartContract = function () { return creds; }; + _a = chai_1.expect; + return [4 /*yield*/, ConfigClient.getDragonchainCredentials('id', { getCredsFromEnvVars: getCredsFromEnvVars, getCredsFromFile: getCredsFromFile, getCredsAsSmartContract: getCredsAsSmartContract })]; + case 1: + _a.apply(void 0, [_b.sent()]).to.equal(creds); + return [2 /*return*/]; + } + }); + }); }); + it('throws NOT_FOUND when not found', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var getCredsFromEnvVars, getCredsFromFile, getCredsAsSmartContract, e_5; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + getCredsFromEnvVars = function () { return false; }; + getCredsFromFile = function () { return false; }; + getCredsAsSmartContract = function () { return false; }; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, ConfigClient.getDragonchainCredentials('id', { getCredsFromEnvVars: getCredsFromEnvVars, getCredsFromFile: getCredsFromFile, getCredsAsSmartContract: getCredsAsSmartContract })]; + case 2: + _a.sent(); + return [3 /*break*/, 4]; + case 3: + e_5 = _a.sent(); + chai_1.expect(e_5.code).to.equal('NOT_FOUND'); + return [2 /*return*/]; + case 4: + chai_1.expect.fail(); + return [2 /*return*/]; + } + }); + }); }); + }); +}); diff --git a/dist/services/config-service/index.js b/dist/services/config-service/index.js new file mode 100644 index 0000000..455d373 --- /dev/null +++ b/dist/services/config-service/index.js @@ -0,0 +1,21 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var ConfigCient_1 = require("./ConfigCient"); +exports.getDragonchainCredentials = ConfigCient_1.getDragonchainCredentials; +exports.getDragonchainId = ConfigCient_1.getDragonchainId; +exports.getDragonchainEndpoint = ConfigCient_1.getDragonchainEndpoint; diff --git a/dist/services/credential-service/CredentialService.js b/dist/services/credential-service/CredentialService.js new file mode 100644 index 0000000..5f95350 --- /dev/null +++ b/dist/services/credential-service/CredentialService.js @@ -0,0 +1,79 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var tslib_1 = require("tslib"); +var crypto = require("crypto"); +var config_service_1 = require("../config-service"); +/** + * @hidden + * Service to store Dragonchain credentials and generate authentication for use in API requests + */ +var CredentialService = /** @class */ (function () { + /** + * Construct a CredentialService object (This should not be called directly, and instead should be constructed with createCredentials) + */ + function CredentialService(dragonchainId, credentials, hmacAlgo) { + var _this = this; + /** + * Return the HMAC signature used as the Authorization Header on REST requests to your dragonchain. + */ + this.getAuthorizationHeader = function (method, path, timestamp, contentType, body) { + var message = CredentialService.getHmacMessageString(method, path, _this.dragonchainId, timestamp, contentType, body, _this.hmacAlgo); + var hmac = crypto.createHmac(_this.hmacAlgo, _this.credentials.authKey); + var signature = hmac.update(message).digest('base64'); + return "DC1-HMAC-" + _this.hmacAlgo + " " + _this.credentials.authKeyId + ":" + signature; + }; + this.dragonchainId = dragonchainId; + this.credentials = credentials; + this.hmacAlgo = hmacAlgo; + } + /** + * async constructor to return an initialized CredentialService instantiation + */ + CredentialService.createCredentials = function (dragonchainId, authKey, authKeyId, hmacAlgo, injected) { + if (authKey === void 0) { authKey = ''; } + if (authKeyId === void 0) { authKeyId = ''; } + if (hmacAlgo === void 0) { hmacAlgo = 'SHA256'; } + if (injected === void 0) { injected = { getDragonchainCredentials: config_service_1.getDragonchainCredentials }; } + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var credentials; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!(!authKey || !authKeyId)) return [3 /*break*/, 2]; + return [4 /*yield*/, injected.getDragonchainCredentials(dragonchainId)]; + case 1: + credentials = _a.sent(); + authKey = credentials.authKey; + authKeyId = credentials.authKeyId; + _a.label = 2; + case 2: return [2 /*return*/, new CredentialService(dragonchainId, { authKey: authKey, authKeyId: authKeyId }, hmacAlgo)]; + } + }); + }); + }; + /** + * transform a DragonchainRequestObject into a compliant hmac message string + */ + CredentialService.getHmacMessageString = function (method, path, dragonchainId, timestamp, contentType, body, hmacAlgo) { + var binaryBody = Buffer.from(body || '', 'utf-8'); + var hashedBase64Content = crypto.createHash(hmacAlgo).update(binaryBody).digest('base64'); + return [method.toUpperCase(), path, dragonchainId, timestamp, contentType, hashedBase64Content].join('\n'); + }; + return CredentialService; +}()); +exports.CredentialService = CredentialService; diff --git a/dist/services/credential-service/CredentialService.spec.js b/dist/services/credential-service/CredentialService.spec.js new file mode 100644 index 0000000..0077b9b --- /dev/null +++ b/dist/services/credential-service/CredentialService.spec.js @@ -0,0 +1,70 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var tslib_1 = require("tslib"); +var chai_1 = require("chai"); +var CredentialService_1 = require("./CredentialService"); +describe('CredentialService', function () { + var credentialService; + beforeEach(function () { + credentialService = new CredentialService_1.CredentialService('testId', { authKey: 'key', authKeyId: 'keyId' }, 'SHA256'); + }); + describe('.createCredentials', function () { + it('calls and uses getDragonchainCredentials when credentials are not provided', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeGetCreds, dcid, service; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeGetCreds = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + return [2 /*return*/, { authKey: 'key', authKeyId: 'keyId' }]; + }); + }); }; + dcid = 'dcid'; + return [4 /*yield*/, CredentialService_1.CredentialService.createCredentials(dcid, '', '', 'SHA256', { getDragonchainCredentials: fakeGetCreds })]; + case 1: + service = _a.sent(); + chai_1.expect(service.dragonchainId).to.equal(dcid); + chai_1.expect(service.credentials.authKey).to.equal('key'); + chai_1.expect(service.credentials.authKeyId).to.equal('keyId'); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('#constructor', function () { + it('initializes with correct variables', function () { + var dcid = 'dcid'; + var key = 'key'; + var keyId = 'keyId'; + var algo = 'SHA256'; + var service = new CredentialService_1.CredentialService(dcid, { authKey: key, authKeyId: keyId }, algo); + chai_1.expect(service.dragonchainId).to.equal(dcid); + chai_1.expect(service.credentials.authKey).to.equal(key); + chai_1.expect(service.credentials.authKeyId).to.equal(keyId); + chai_1.expect(service.hmacAlgo).to.equal(algo); + }); + }); + describe('#getAuthorizationHeader', function () { + it('returns expected hmac', function () { + var result = credentialService.getAuthorizationHeader('GET', '/path', 'timestamp', 'application/json', ''); + chai_1.expect(result).to.equal('DC1-HMAC-SHA256 keyId:8Bc+h0parZxGeMB9rYzzRUuNxxHSIjGqSD4W/635A9k='); + var result2 = credentialService.getAuthorizationHeader('POST', '/new_path', 'timestamp', 'application/json', '"body"'); + chai_1.expect(result2).to.equal('DC1-HMAC-SHA256 keyId:PkVjUxWZr6ST4xh+JxYFZresaFhQbk8sggWqyWv/XkU='); + }); + }); +}); diff --git a/dist/services/credential-service/DragonchainCredentials.js b/dist/services/credential-service/DragonchainCredentials.js new file mode 100644 index 0000000..abddbb2 --- /dev/null +++ b/dist/services/credential-service/DragonchainCredentials.js @@ -0,0 +1,17 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/services/dragonchain-client/DragonchainClient.js b/dist/services/dragonchain-client/DragonchainClient.js new file mode 100644 index 0000000..b761bb2 --- /dev/null +++ b/dist/services/dragonchain-client/DragonchainClient.js @@ -0,0 +1,1358 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var tslib_1 = require("tslib"); +var util_1 = require("util"); +var fs_1 = require("fs"); +var path = require("path"); +var node_fetch_1 = require("node-fetch"); +var CredentialService_1 = require("../credential-service/CredentialService"); +var config_service_1 = require("../config-service"); +var url_1 = require("url"); +var index_1 = require("../../index"); +var FailureByDesign_1 = require("../../errors/FailureByDesign"); +/** + * @hidden + */ +var UrlSearchParams = function (queryParams) { + if (!url_1.URLSearchParams) { + return new URLSearchParams(queryParams); // used in browser ( method on window ) + } + return new url_1.URLSearchParams(queryParams); // used in node +}; +var readFileAsync = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { + return [2 /*return*/, '']; +}); }); }; +if (fs_1.readFile) + readFileAsync = util_1.promisify(fs_1.readFile); +/** + * HTTP Client that interfaces with the dragonchain api + */ +var DragonchainClient = /** @class */ (function () { + /** + * @hidden + * Construct an instance of a DragonchainClient. THIS SHOULD NOT BE CALLED DIRECTLY. Instead use the `createClient` function to instantiate a client + */ + function DragonchainClient(endpoint, credentials, verify, injected) { + var _this = this; + if (injected === void 0) { injected = {}; } + /** + * Reads secrets provided to a smart contract + * + * Note: This will only work when running within a smart contract, given that the smart contract was created/updated with secrets + */ + this.getSmartContractSecret = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var secretPath; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.secretName) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `secretName` is required'); + secretPath = path.join('/', 'var', 'openfaas', 'secrets', "sc-" + process.env.SMART_CONTRACT_ID + "-" + options.secretName); + return [4 /*yield*/, this.readFileAsync(secretPath, 'utf-8')]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Get the status of your dragonchain + */ + this.getStatus = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.get('/v1/status')]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); }); }; + /** + * Get a transaction by id + */ + this.getTransaction = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.transactionId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `transactionId` is required'); + return [4 /*yield*/, this.get("/v1/transaction/" + options.transactionId)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Generate a new HMAC API key + */ + this.createApiKey = function (options) { + if (options === void 0) { options = {}; } + return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + body = {}; + if (options.nickname) + body['nickname'] = options.nickname; + if (options.permissionsDocument) + body['permissions_document'] = options.permissionsDocument; + return [4 /*yield*/, this.post('/v1/api-key', body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); + }; + /** + * List HMAC API key IDs and their associated metadata + */ + this.listApiKeys = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.get('/v1/api-key')]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Get metadata about an existing HMAC API key + */ + this.getApiKey = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.keyId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `keyId` is required'); + return [4 /*yield*/, this.get("/v1/api-key/" + options.keyId)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Delete an existing HMAC API key + */ + this.deleteApiKey = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.keyId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `keyId` is required'); + return [4 /*yield*/, this.delete("/v1/api-key/" + options.keyId)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Update nickname of existing HMAC API key + */ + this.updateApiKey = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.keyId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `keyId` is required'); + body = {}; + if (options.nickname) + body['nickname'] = options.nickname; + if (options.permissionsDocument) + body['permissions_document'] = options.permissionsDocument; + return [4 /*yield*/, this.put("/v1/api-key/" + options.keyId, body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Create a new Transaction on your Dragonchain. + * + * This transaction, if properly structured, will be received by your dragonchain, hashed, and put into a queue for processing into a block. + * + * A POST request is made to the callback URL when the transaction has settled into a block on the Blockchain. + * + * The `transaction_id` returned from this function can be used for checking the status of this transaction, including the block in which it was included. + */ + this.createTransaction = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var transactionBody; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.transactionType) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `transactionType` is required'); + if (!options.payload) + options.payload = ''; // default payload to an empty string if not provided + transactionBody = { + version: '1', + txn_type: options.transactionType, + payload: options.payload, + }; + if (options.tag) + transactionBody.tag = options.tag; + return [4 /*yield*/, this.post('/v1/transaction', transactionBody, options.callbackURL)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Create a bulk transaction to send many transactions to a chain with only a single call + */ + this.createBulkTransaction = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var bulkTransactionBody; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.transactionList) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'parameter `transactionList` is required'); + bulkTransactionBody = []; + options.transactionList.forEach(function (transaction) { + var singleBody = { + version: '1', + txn_type: transaction.transactionType, + payload: transaction.payload || '', + }; + if (transaction.tag) + singleBody.tag = transaction.tag; + bulkTransactionBody.push(singleBody); + }); + return [4 /*yield*/, this.post("/v1/transaction_bulk", bulkTransactionBody)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Query transactions using Redisearch query-string syntax + * + * For more information on how to use the Redisearch query-string syntax checkout their documentation: + * https://oss.redislabs.com/redisearch/Query_Syntax.html + * + * Note that transactions have the following fields: + * timestamp - sortable Numeric field + * block_id - sortable Numeric field + * tag - Text field + * + * Transaction types can also have additional custom fields if specified when creating the relevant transaction type/smart contract + * + * @example + * ```javascript + * myClient.queryTransactions({transactionType: 'example', redisearchQuery: 'somethingInTxnTag', sortBy: 'timestamp'}).then( ...do stuff ) + * ``` + */ + this.queryTransactions = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var queryParams; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + queryParams = { + transaction_type: options.transactionType, + q: options.redisearchQuery, + offset: options.offset || 0, + limit: options.limit || 10, + }; + if (options.verbatim !== undefined) + queryParams.verbatim = options.verbatim; + if (options.idsOnly !== undefined) + queryParams.id_only = options.idsOnly; + if (options.sortBy !== undefined) { + queryParams.sort_by = options.sortBy; + if (options.sortAscending !== undefined) + queryParams.sort_asc = options.sortAscending; + } + return [4 /*yield*/, this.get("/v1/transaction" + this.generateQueryString(queryParams))]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Get a single block by ID + */ + this.getBlock = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.blockId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `blockId` is required'); + return [4 /*yield*/, this.get("/v1/block/" + options.blockId)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Query transactions using Redisearch query-string syntax + * + * For more information on how to use the Redisearch query-string syntax checkout their documentation: + * https://oss.redislabs.com/redisearch/Query_Syntax.html + * + * Note that blocks have the following fields: + * block_id - sortable Numeric field + * timestamp - sortable Numeric field + * prev_id - sortable Numeric field + * + * @example + * ```javascript + * myClient.queryBlocks({redisearchQuery: '*', sortBy: 'block_id'}).then( ...do stuff ) + * ``` + */ + this.queryBlocks = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var queryParams; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + queryParams = { + q: options.redisearchQuery, + offset: options.offset || 0, + limit: options.limit || 10, + }; + if (options.idsOnly !== undefined) + queryParams.id_only = options.idsOnly; + if (options.sortBy !== undefined) { + queryParams.sort_by = options.sortBy; + if (options.sortAscending !== undefined) + queryParams.sort_asc = options.sortAscending; + } + return [4 /*yield*/, this.get("/v1/block" + this.generateQueryString(queryParams))]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Create a new Smart Contract on your Dragonchain + */ + this.createSmartContract = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.transactionType) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `transactionType` is required'); + if (!options.image) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `image` is required'); + if (!options.cmd) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `cmd` is required'); + if (options.scheduleIntervalInSeconds && options.cronExpression) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameters `scheduleIntervalInSeconds` and `cronExpression` are mutually exclusive'); + body = { + version: '3', + txn_type: options.transactionType, + image: options.image, + execution_order: 'parallel', + cmd: options.cmd, + }; + if (options.args) + body.args = options.args; + if (options.executionOrder) + body.execution_order = options.executionOrder; + if (options.environmentVariables) + body.env = options.environmentVariables; + if (options.secrets) + body.secrets = options.secrets; + if (options.scheduleIntervalInSeconds) + body.seconds = options.scheduleIntervalInSeconds; + if (options.cronExpression) + body.cron = options.cronExpression; + if (options.registryCredentials) + body.auth = options.registryCredentials; + if (options.customIndexFields) + body.custom_indexes = this.validateAndBuildCustomIndexFieldsArray(options.customIndexFields); + return [4 /*yield*/, this.post('/v1/contract', body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Update an existing Smart Contract on your Dragonchain + * + * Note that all parameters (aside from contract id) are optional, and only supplied parameters will be updated + */ + this.updateSmartContract = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.smartContractId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `smartContractId` is required'); + if (options.scheduleIntervalInSeconds && options.cronExpression) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameters `scheduleIntervalInSeconds` and `cronExpression` are mutually exclusive'); + body = { + version: '3', + }; + if (options.image) + body.image = options.image; + if (options.cmd) + body.cmd = options.cmd; + if (options.args) + body.args = options.args; + if (options.executionOrder) + body.execution_order = options.executionOrder; + if (options.enabled === true) + body.desired_state = 'active'; + if (options.enabled === false) + body.desired_state = 'inactive'; + if (options.environmentVariables) + body.env = options.environmentVariables; + if (options.secrets) + body.secrets = options.secrets; + if (options.scheduleIntervalInSeconds) + body.seconds = options.scheduleIntervalInSeconds; + if (options.cronExpression) + body.cron = options.cronExpression; + if (options.registryCredentials) + body.auth = options.registryCredentials; + if (options.disableSchedule) + body.disable_schedule = true; + return [4 /*yield*/, this.put("/v1/contract/" + options.smartContractId, body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Deletes a deployed smart contract + */ + this.deleteSmartContract = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (options.smartContractId && options.transactionType) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Only one of `smartContractId` or `transactionType` can be specified'); + if (!options.smartContractId) return [3 /*break*/, 2]; + return [4 /*yield*/, this.delete("/v1/contract/" + options.smartContractId)]; + case 1: return [2 /*return*/, (_a.sent())]; + case 2: + if (!options.transactionType) return [3 /*break*/, 4]; + return [4 /*yield*/, this.delete("/v1/contract/txn_type/" + options.transactionType)]; + case 3: return [2 /*return*/, (_a.sent())]; + case 4: throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'At least one of `smartContractId` or `transactionType` must be supplied'); + } + }); + }); }; + /** + * Get a single smart contract by one of id or transaction type + */ + this.getSmartContract = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (options.smartContractId && options.transactionType) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Only one of `smartContractId` or `transactionType` can be specified'); + if (!options.smartContractId) return [3 /*break*/, 2]; + return [4 /*yield*/, this.get("/v1/contract/" + options.smartContractId)]; + case 1: return [2 /*return*/, (_a.sent())]; + case 2: + if (!options.transactionType) return [3 /*break*/, 4]; + return [4 /*yield*/, this.get("/v1/contract/txn_type/" + options.transactionType)]; + case 3: return [2 /*return*/, (_a.sent())]; + case 4: throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'At least one of `smartContractId` or `transactionType` must be supplied'); + } + }); + }); }; + /** + * Get a single smart contract by one of id or transaction type + */ + this.getSmartContractLogs = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var queryParameters; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.smartContractId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `smartContractId` is required'); + queryParameters = {}; + if (options.tail) + queryParameters.tail = options.tail; + if (options.since) + queryParameters.since = options.since; + return [4 /*yield*/, this.get("/v1/contract/" + options.smartContractId + "/logs" + this.generateQueryString(queryParameters))]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Get all smart contracts on a chain + */ + this.listSmartContracts = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.get('/v1/contract')]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); }); }; + /** + * Get chain ids for the pending verifications for a block. Note that this is only relevant for level 1 chains. + */ + this.getPendingVerifications = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.blockId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `blockId` is required'); + return [4 /*yield*/, this.get("/v1/verifications/pending/" + options.blockId)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Get verifications for a block. Note that this is only relevant for level 1 chains + */ + this.getVerifications = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.blockId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `blockId` is required'); + if (!options.level) return [3 /*break*/, 2]; + return [4 /*yield*/, this.get("/v1/verifications/" + options.blockId + "?level=" + options.level)]; + case 1: return [2 /*return*/, (_a.sent())]; + case 2: return [4 /*yield*/, this.get("/v1/verifications/" + options.blockId)]; + case 3: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Get an object from the smart contract heap. This is used for getting stateful data set by the outputs of smart contracts + */ + this.getSmartContractObject = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.key) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `key` is required'); + if (!options.smartContractId) { + if (!process.env.SMART_CONTRACT_ID) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `smartContractId` is required when not running within a smart contract'); + options.smartContractId = process.env.SMART_CONTRACT_ID; + } + return [4 /*yield*/, this.get("/v1/get/" + options.smartContractId + "/" + options.key, false)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * List objects from a folder within the heap of a smart contract + */ + this.listSmartContractObjects = function (options) { + if (options === void 0) { options = {}; } + return tslib_1.__awaiter(_this, void 0, void 0, function () { + var path; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.smartContractId) { + if (!process.env.SMART_CONTRACT_ID) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `smartContractId` is required when not running within a smart contract'); + options.smartContractId = process.env.SMART_CONTRACT_ID; + } + path = "/v1/list/" + options.smartContractId + "/"; + if (options.prefixKey) { + if (options.prefixKey.endsWith('/')) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', "Parameter `prefixKey` cannot end with '/'"); + path += options.prefixKey + "/"; + } + return [4 /*yield*/, this.get(path)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); + }; + /** + * Create a new transaction type for ledgering transactions + */ + this.createTransactionType = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.transactionType) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `transactionType` is required'); + body = { + version: '2', + txn_type: options.transactionType, + }; + if (options.customIndexFields) + body.custom_indexes = this.validateAndBuildCustomIndexFieldsArray(options.customIndexFields); + return [4 /*yield*/, this.post('/v1/transaction-type', body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Deletes an existing registered transaction type + */ + this.deleteTransactionType = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.transactionType) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `transactionType` is required'); + return [4 /*yield*/, this.delete("/v1/transaction-type/" + options.transactionType)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Lists currently created transaction types + */ + this.listTransactionTypes = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.get('/v1/transaction-types')]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Gets an existing transaction type from the chain + */ + this.getTransactionType = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.transactionType) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `transactionType` is required'); + return [4 /*yield*/, this.get("/v1/transaction-type/" + options.transactionType)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Create (or overwrite) a bitcoin wallet/network for interchain use + */ + this.createBitcoinInterchain = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + body = { version: '1', name: options.name }; + if (typeof options.testnet === 'boolean') + body.testnet = options.testnet; + if (options.privateKey) + body.private_key = options.privateKey; + if (options.rpcAddress) + body.rpc_address = options.rpcAddress; + if (options.rpcAuthorization) + body.rpc_authorization = options.rpcAuthorization; + if (typeof options.utxoScan === 'boolean') + body.utxo_scan = options.utxoScan; + return [4 /*yield*/, this.post("/v1/interchains/bitcoin", body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Update an existing bitcoin wallet/network for interchain use. Will only update the provided fields + */ + this.updateBitcoinInterchain = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + body = { version: '1' }; + if (typeof options.testnet === 'boolean') + body.testnet = options.testnet; + if (options.privateKey) + body.private_key = options.privateKey; + if (options.rpcAddress) + body.rpc_address = options.rpcAddress; + if (options.rpcAuthorization) + body.rpc_authorization = options.rpcAuthorization; + if (typeof options.utxoScan === 'boolean') + body.utxo_scan = options.utxoScan; + return [4 /*yield*/, this.patch("/v1/interchains/bitcoin/" + options.name, body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Sign a transaction for a bitcoin network on the chain + */ + this.signBitcoinTransaction = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + if (options.satoshisPerByte && !Number.isInteger(options.satoshisPerByte)) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `satoshisPerByte` must be an integer'); + body = { version: '1' }; + if (options.satoshisPerByte) + body.fee = options.satoshisPerByte; + if (options.data) + body.data = options.data; + if (options.changeAddress) + body.change = options.changeAddress; + if (options.outputs) { + body.outputs = []; + options.outputs.forEach(function (output) { + body.outputs.push({ + to: output.to, + value: output.value, + }); + }); + } + return [4 /*yield*/, this.post("/v1/interchains/bitcoin/" + options.name + "/transaction", body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Create (or overwrite) an ethereum wallet/network for interchain use + */ + this.createEthereumInterchain = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + if (options.chainId && !Number.isInteger(options.chainId)) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `chainId` must be an integer'); + body = { version: '1', name: options.name }; + if (options.privateKey) + body.private_key = options.privateKey; + if (options.rpcAddress) + body.rpc_address = options.rpcAddress; + if (options.chainId) + body.chain_id = options.chainId; + return [4 /*yield*/, this.post("/v1/interchains/ethereum", body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Update an existing ethereum wallet/network for interchain use + */ + this.updateEthereumInterchain = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + if (options.chainId && !Number.isInteger(options.chainId)) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `chainId` must be an integer'); + body = { version: '1' }; + if (options.privateKey) + body.private_key = options.privateKey; + if (options.rpcAddress) + body.rpc_address = options.rpcAddress; + if (options.chainId) + body.chain_id = options.chainId; + return [4 /*yield*/, this.patch("/v1/interchains/ethereum/" + options.name, body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Create and sign an ethereum transaction using your chain's interchain network + */ + this.signEthereumTransaction = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + if (!options.to) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `to` is required'); + if (!options.value) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `value` is required'); + body = { + version: '1', + to: options.to, + value: options.value, + }; + if (options.data) + body.data = options.data; + if (options.gasPrice) + body.gasPrice = options.gasPrice; + if (options.gas) + body.gas = options.gas; + if (options.nonce) + body.nonce = options.nonce; + return [4 /*yield*/, this.post("/v1/interchains/ethereum/" + options.name + "/transaction", body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Create (or overwrite) a binance wallet/network for interchain use + */ + this.createBinanceInterchain = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + if (options.rpcPort && !Number.isInteger(options.rpcPort)) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `rpcPort` must be an integer'); + if (options.apiPort && !Number.isInteger(options.apiPort)) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `apiPort` must be an integer'); + body = { version: '1', name: options.name }; + if (typeof options.testnet === 'boolean') + body.testnet = options.testnet; + if (options.privateKey) + body.private_key = options.privateKey; + if (options.nodeURL) + body.node_url = options.nodeURL; + if (options.rpcPort) + body.rpc_port = options.rpcPort; + if (options.rpcPort) + body.api_port = options.apiPort; + return [4 /*yield*/, this.post("/v1/interchains/binance", body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Update an existing binance wallet/network for interchain use + */ + this.updateBinanceInterchain = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + if (options.rpcPort && !Number.isInteger(options.rpcPort)) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `rpcPort` must be an integer'); + if (options.apiPort && !Number.isInteger(options.apiPort)) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `apiPort` must be an integer'); + body = { version: '1' }; + if (typeof options.testnet === 'boolean') + body.testnet = options.testnet; + if (options.privateKey) + body.private_key = options.privateKey; + if (options.nodeURL) + body.node_url = options.nodeURL; + if (options.rpcPort) + body.rpc_port = options.rpcPort; + if (options.apiPort) + body.api_port = options.apiPort; + return [4 /*yield*/, this.patch("/v1/interchains/binance/" + options.name, body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Create and sign a binance transaction using your chain's interchain network + */ + this.signBinanceTransaction = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + if (!options.amount) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `amount` is required'); + if (!options.toAddress) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `toAddress` is required'); + body = { + version: '1', + amount: options.amount, + to_address: options.toAddress, + }; + if (options.symbol) + body.symbol = options.symbol; + if (options.memo) + body.memo = options.memo; + return [4 /*yield*/, this.post("/v1/interchains/binance/" + options.name + "/transaction", body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Get a configured interchain network/wallet from the chain + */ + this.getInterchainNetwork = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.blockchain) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `blockchain` is required'); + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + return [4 /*yield*/, this.get("/v1/interchains/" + options.blockchain + "/" + options.name)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Delete an interchain network/wallet from the chain + */ + this.deleteInterchainNetwork = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.blockchain) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `blockchain` is required'); + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + return [4 /*yield*/, this.delete("/v1/interchains/" + options.blockchain + "/" + options.name)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * List all the interchain network/wallets for a blockchain type + */ + this.listInterchainNetworks = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.blockchain) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `blockchain` is required'); + return [4 /*yield*/, this.get("/v1/interchains/" + options.blockchain)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Set the default interchain network for the chain to use (L5 Only) + */ + this.setDefaultInterchainNetwork = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.blockchain) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `blockchain` is required'); + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + body = { + version: '1', + blockchain: options.blockchain, + name: options.name, + }; + return [4 /*yield*/, this.post("/v1/interchains/default", body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Get the set default interchain network for this chain (L5 Only) + */ + this.getDefaultInterchainNetwork = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.get('/v1/interchains/default')]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Publish an interchain transaction that's already been signed + */ + this.publishInterchainTransaction = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.blockchain) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `blockchain` is required'); + if (!options.name) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `name` is required'); + if (!options.signedTransaction) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `signedTransaction` is required'); + body = { + version: '1', + blockchain: options.blockchain, + name: options.name, + signed_txn: options.signedTransaction, + }; + return [4 /*yield*/, this.post('/v1/interchains/transaction/publish', body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * !This method is deprecated and should not be used! + * Backwards compatibility will exist for legacy chains, but will not work on new chains. listInterchainNetworks should be used instead + * + * Gets a list of the chain's interchain addresses + */ + this.getPublicBlockchainAddresses = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + index_1.logger.warn('This method is deprecated. It will continue to work for legacy chains, but will not work on any new chains. Use listInterchainNetworks instead'); + return [4 /*yield*/, this.get('/v1/public-blockchain-address')]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * !This method is deprecated and should not be used! + * Backwards compatibility will exist for legacy chains, but will not work on new chains. signBitcoinTransaction should be used instead + * + * Sign a transaction for a bitcoin network + */ + this.createBitcoinTransaction = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + index_1.logger.warn('This method is deprecated. It will continue to work for legacy chains, but will not work on any new chains. Use signBitcoinTransaction instead'); + if (!options.network) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `network` is required'); + if (options.satoshisPerByte && !Number.isInteger(options.satoshisPerByte)) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `satoshisPerByte` must be an integer'); + body = { + network: options.network, + transaction: {}, + }; + if (options.satoshisPerByte) + body.transaction.fee = options.satoshisPerByte; + if (options.data) + body.transaction.data = options.data; + if (options.changeAddress) + body.transaction.change = options.changeAddress; + if (options.outputs) { + body.transaction.outputs = []; + options.outputs.forEach(function (output) { + body.transaction.outputs.push({ + to: output.to, + value: output.value, + }); + }); + } + return [4 /*yield*/, this.post('/v1/public-blockchain-transaction', body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * !This method is deprecated and should not be used! + * Backwards compatibility will exist for legacy chains, but will not work on new chains. signEthereumTransaction should be used instead + * + * Sign a transaction for an ethereum network + */ + this.createEthereumTransaction = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var body; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + index_1.logger.warn('This method is deprecated. It will continue to work for legacy chains, but will not work on any new chains. Use signEthereumTransaction instead'); + if (!options.network) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `network` is required'); + if (!options.to) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `to` is required'); + if (!options.value) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `value` is required'); + body = { + network: options.network, + transaction: { + to: options.to, + value: options.value, + }, + }; + if (options.data) + body.transaction.data = options.data; + if (options.gasPrice) + body.transaction.gasPrice = options.gasPrice; + if (options.gas) + body.transaction.gas = options.gas; + return [4 /*yield*/, this.post('/v1/public-blockchain-transaction', body)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Query the Dragonchain for the subsequent interchain (L5) transactions + */ + this.queryInterchainTransactions = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.blockId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `blockId` is required'); + return [4 /*yield*/, this.get("/v1/verifications/interchains/" + options.blockId)]; + case 1: return [2 /*return*/, (_a.sent())]; + } + }); + }); }; + /** + * Get/Generate an Eternal-type report given a transaction ID + */ + this.getReport = function (options) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var transaction, blockId, block, verifications, l5verifications; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!options.transactionId) + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `transactionId` is required'); + return [4 /*yield*/, this.getTransaction({ transactionId: options.transactionId })]; + case 1: + transaction = _a.sent(); + if (transaction && !transaction.ok) + return [2 /*return*/, { ok: false, status: transaction.status, response: {} }]; + blockId = transaction.response.header.block_id; + return [4 /*yield*/, this.getBlock({ blockId: blockId })]; + case 2: + block = _a.sent(); + if (block && !block.ok) + return [2 /*return*/, { ok: false, status: block.status, response: {} }]; + return [4 /*yield*/, this.getVerifications({ blockId: blockId })]; + case 3: + verifications = _a.sent(); + return [4 /*yield*/, this.queryInterchainTransactions({ blockId: blockId })]; + case 4: + l5verifications = _a.sent(); + return [2 /*return*/, { + ok: true, + status: 200, + response: { + l1Transaction: transaction.response, + l1Block: block.response, + l2Verifications: verifications.response && verifications.response['2'], + l3Verifications: verifications.response && verifications.response['3'], + l4Verifications: verifications.response && verifications.response['4'], + l5Verifications: l5verifications && l5verifications.response, + }, + }]; + } + }); + }); }; + /** + * @hidden + */ + this.validateAndBuildCustomIndexFieldsArray = function (customIndexFields) { + var returnList = []; + customIndexFields.forEach(function (customIndexField) { + var customTransactionFieldBody = { + path: customIndexField.path, + field_name: customIndexField.fieldName, + type: customIndexField.type, + }; + if (customIndexField.options) { + var optionsBody = {}; + if (customIndexField.options.noIndex !== undefined) + optionsBody.no_index = customIndexField.options.noIndex; + if (customIndexField.type === 'tag') { + if (customIndexField.options.separator !== undefined) + optionsBody.separator = customIndexField.options.separator; + } + else if (customIndexField.type === 'text') { + if (customIndexField.options.noStem !== undefined) + optionsBody.no_stem = customIndexField.options.noStem; + if (customIndexField.options.weight !== undefined) + optionsBody.weight = customIndexField.options.weight; + if (customIndexField.options.sortable !== undefined) + optionsBody.sortable = customIndexField.options.sortable; + } + else if (customIndexField.type === 'number') { + if (customIndexField.options.sortable !== undefined) + optionsBody.sortable = customIndexField.options.sortable; + } + else { + throw new FailureByDesign_1.FailureByDesign('PARAM_ERROR', 'Parameter `customIndexFields[].type must be `tag`, `text`, or `number`'); + } + customTransactionFieldBody.options = optionsBody; + } + returnList.push(customTransactionFieldBody); + }); + return returnList; + }; + /** + * @hidden + */ + this.generateQueryString = function (queryObject) { return (Object.keys(queryObject).length > 0 ? "?" + UrlSearchParams(queryObject) : ''); }; + /** + * @hidden + * For development purposes only! NodeJS naturally distrusts self signed certs (for good reason!). This function allows users the option to "not care" about self signed certs. + * @param {function} asyncFunction an async function to call while NODE_TLS_REJECT_UNAUTHORIZED is quickly toggled from "1" to "0" and back to "1" + */ + this.toggleSslCertVerification = function (asyncFunction) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var result; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + process.env.NODE_TLS_REJECT_UNAUTHORIZED = this.verify ? '1' : '0'; + return [4 /*yield*/, asyncFunction()]; + case 1: + result = _a.sent(); + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'; + return [2 /*return*/, result]; + } + }); + }); }; + this.endpoint = endpoint; + this.verify = verify; + this.credentialService = credentials; + this.fetch = injected.fetch || node_fetch_1.default; + this.readFileAsync = injected.readFileAsync || readFileAsync; + } + /** + * @hidden + */ + DragonchainClient.prototype.getTimestamp = function () { + return "" + new Date().toISOString().slice(0, -1) + (Math.floor(Math.random() * 900) + 100) + "Z"; + }; + /** + * @hidden + */ + DragonchainClient.prototype.get = function (path, jsonParse) { + if (jsonParse === void 0) { jsonParse = true; } + return tslib_1.__awaiter(this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + return [2 /*return*/, this.makeRequest(path, 'GET', undefined, undefined, jsonParse)]; + }); + }); + }; + /** + * @hidden + */ + DragonchainClient.prototype.post = function (path, body, callbackURL) { + return tslib_1.__awaiter(this, void 0, void 0, function () { + var bodyString; + return tslib_1.__generator(this, function (_a) { + bodyString = typeof body === 'string' ? body : JSON.stringify(body); + return [2 /*return*/, this.makeRequest(path, 'POST', callbackURL, bodyString)]; + }); + }); + }; + /** + * @hidden + */ + DragonchainClient.prototype.put = function (path, body) { + return tslib_1.__awaiter(this, void 0, void 0, function () { + var bodyString; + return tslib_1.__generator(this, function (_a) { + bodyString = typeof body === 'string' ? body : JSON.stringify(body); + return [2 /*return*/, this.makeRequest(path, 'PUT', undefined, bodyString)]; + }); + }); + }; + /** + * @hidden + */ + DragonchainClient.prototype.patch = function (path, body) { + return tslib_1.__awaiter(this, void 0, void 0, function () { + var bodyString; + return tslib_1.__generator(this, function (_a) { + bodyString = typeof body === 'string' ? body : JSON.stringify(body); + return [2 /*return*/, this.makeRequest(path, 'PATCH', undefined, bodyString)]; + }); + }); + }; + /** + * @hidden + */ + DragonchainClient.prototype.delete = function (path) { + return tslib_1.__awaiter(this, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + return [2 /*return*/, this.makeRequest(path, 'DELETE')]; + }); + }); + }; + /** + * @hidden + */ + DragonchainClient.prototype.getFetchOptions = function (path, method, callbackURL, body, contentType) { + if (callbackURL === void 0) { callbackURL = ''; } + if (body === void 0) { body = ''; } + if (contentType === void 0) { contentType = ''; } + var timestamp = this.getTimestamp(); + var options = { + method: method, + body: body || undefined, + credentials: 'omit', + headers: { + dragonchain: this.credentialService.dragonchainId, + Authorization: this.credentialService.getAuthorizationHeader(method, path, timestamp, contentType, body || ''), + timestamp: timestamp, + }, + }; + if (contentType) + options.headers['Content-Type'] = contentType; + if (callbackURL) + options.headers['X-Callback-URL'] = callbackURL; + return options; + }; + /** + * @hidden + */ + DragonchainClient.prototype.makeRequest = function (path, method, callbackURL, body, jsonParse) { + if (callbackURL === void 0) { callbackURL = ''; } + if (body === void 0) { body = ''; } + if (jsonParse === void 0) { jsonParse = true; } + return tslib_1.__awaiter(this, void 0, void 0, function () { + var contentType, fetchData, url, res, status, ok, statusText, response; + var _this = this; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + contentType = ''; + // assume content type is json if a body is provided, as it's the only content-type supported + if (body) + contentType = 'application/json'; + fetchData = this.getFetchOptions(path, method, callbackURL, body, contentType); + url = "" + this.endpoint + path; + index_1.logger.debug("[DragonchainClient][FETCH][URL] ==> " + url); + index_1.logger.debug("[DragonchainClient][FETCH][DATA] ==> " + JSON.stringify(fetchData)); + return [4 /*yield*/, this.toggleSslCertVerification(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { + return [2 /*return*/, this.fetch(url, fetchData)]; + }); }); })]; + case 1: + res = _a.sent(); + status = res.status, ok = res.ok, statusText = res.statusText; + index_1.logger.debug("[DragonchainClient][" + method + "] <== " + url + " " + status + " " + statusText); + return [4 /*yield*/, (jsonParse ? res.json() : res.text())]; + case 2: + response = _a.sent(); + index_1.logger.debug("[DragonchainClient][" + method + "] <== " + JSON.stringify(response)); + return [2 /*return*/, { status: status, response: response, ok: ok }]; + } + }); + }); + }; + return DragonchainClient; +}()); +exports.DragonchainClient = DragonchainClient; +/** + * Create and return an instantiation of a dragonchain client + */ +exports.createClient = function (options) { + if (options === void 0) { options = {}; } + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var _a, _b, credentials; + return tslib_1.__generator(this, function (_c) { + switch (_c.label) { + case 0: + if (!!options.dragonchainId) return [3 /*break*/, 2]; + _a = options; + return [4 /*yield*/, config_service_1.getDragonchainId()]; + case 1: + _a.dragonchainId = _c.sent(); + _c.label = 2; + case 2: + if (!!options.endpoint) return [3 /*break*/, 4]; + _b = options; + return [4 /*yield*/, config_service_1.getDragonchainEndpoint(options.dragonchainId)]; + case 3: + _b.endpoint = _c.sent(); + _c.label = 4; + case 4: + // Set defaults + if (!options.algorithm) + options.algorithm = 'SHA256'; + if (options.verify !== false) + options.verify = true; + return [4 /*yield*/, CredentialService_1.CredentialService.createCredentials(options.dragonchainId, options.authKey || '', options.authKeyId || '', options.algorithm)]; + case 5: + credentials = _c.sent(); + return [2 /*return*/, new DragonchainClient(options.endpoint, credentials, options.verify)]; + } + }); + }); +}; diff --git a/dist/services/dragonchain-client/DragonchainClient.spec.js b/dist/services/dragonchain-client/DragonchainClient.spec.js new file mode 100644 index 0000000..b528a95 --- /dev/null +++ b/dist/services/dragonchain-client/DragonchainClient.spec.js @@ -0,0 +1,936 @@ +"use strict"; +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var tslib_1 = require("tslib"); +var chai = require("chai"); +var sinonChai = require("sinon-chai"); +var sinon_1 = require("sinon"); +var DragonchainClient_1 = require("./DragonchainClient"); +var CredentialService_1 = require("../credential-service/CredentialService"); +var expect = chai.expect; +chai.use(sinonChai); +var fakeTime = "" + new Date().toISOString().slice(0, -1) + (Math.floor(Math.random() * 900) + 100) + "Z"; +var fakeTimeStamp = Date.now(); +sinon_1.useFakeTimers({ now: fakeTimeStamp, shouldAdvanceTime: false }); +sinon_1.stub(DragonchainClient_1.DragonchainClient.prototype, 'getTimestamp').returns(fakeTime); +describe('DragonchainClient', function () { + describe('#constructor', function () { + it('returns instance of DragonchainClient', function () { + var client = new DragonchainClient_1.DragonchainClient('banana', new CredentialService_1.CredentialService('id', { authKey: 'key', authKeyId: 'keyId' }, 'SHA256'), true); + expect(client instanceof DragonchainClient_1.DragonchainClient).to.equal(true); + }); + }); + describe('GET', function () { + var fakeResponseObj; + var fetch; + var readFileAsync; + var CredentialService; + var logger; + var client; + var expectedFetchOptions; + var fakeResponseText; + var fakeSecretText; + beforeEach(function () { + fakeResponseObj = { body: 'fakeResponseBody' }; + fakeResponseText = 'fakeString'; + fakeSecretText = 'fakeSecret'; + fetch = sinon_1.stub().resolves({ status: 200, json: sinon_1.stub().resolves(fakeResponseObj), text: sinon_1.stub().resolves(fakeResponseText) }); + readFileAsync = sinon_1.stub().returns(fakeSecretText); + CredentialService = { getAuthorizationHeader: sinon_1.stub().returns('fakeCreds'), dragonchainId: 'fakeDragonchainId' }; + logger = { log: sinon_1.stub(), debug: sinon_1.stub() }; + var injected = { logger: logger, fetch: fetch, readFileAsync: readFileAsync }; + client = new DragonchainClient_1.DragonchainClient('fakeUrl', CredentialService, true, injected); + expectedFetchOptions = { + method: 'GET', + body: undefined, + credentials: 'omit', + headers: { + dragonchain: 'fakeDragonchainId', + Authorization: 'fakeCreds', + timestamp: fakeTime, + }, + }; + }); + describe('.queryInterchainTransactions', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.queryInterchainTransactions({ blockId: '123456789' })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/verifications/interchains/123456789', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getSmartContractSecret', function () { + it('calls readFileAsync with correct dragonchain id and secret name', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + process.env.SMART_CONTRACT_ID = 'fakeSmartContractId'; + return [4 /*yield*/, client.getSmartContractSecret({ secretName: 'fakeSecretName' })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(readFileAsync, '/var/openfaas/secrets/sc-fakeSmartContractId-fakeSecretName', 'utf-8'); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getStatus', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.getStatus()]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/status', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getApiKey', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.getApiKey({ keyId: 'MyKeyID' })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/api-key/MyKeyID', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.listApiKeys', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.listApiKeys()]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/api-key', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getTransaction', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var id; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + id = 'batman-transaction-id'; + return [4 /*yield*/, client.getTransaction({ transactionId: id })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, "fakeUrl/v1/transaction/" + id, expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getBlock', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var id; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + id = 'robin-block-id'; + return [4 /*yield*/, client.getBlock({ blockId: id })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, "fakeUrl/v1/block/" + id, expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getSmartContract', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var id; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + id = 'joker-smartcontract-id'; + return [4 /*yield*/, client.getSmartContract({ smartContractId: id })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, "fakeUrl/v1/contract/" + id, expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getPublicBlockchainAddresses', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.getPublicBlockchainAddresses()]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/public-blockchain-address', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getPendingVerifications', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var id; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + id = 'block_id'; + return [4 /*yield*/, client.getPendingVerifications({ blockId: id })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, "fakeUrl/v1/verifications/pending/" + id, expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getVerifications', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var id; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + id = 'block_id'; + return [4 /*yield*/, client.getVerifications({ blockId: id })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, "fakeUrl/v1/verifications/" + id, expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.queryTransactions', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.queryTransactions({ + transactionType: 'testing', + redisearchQuery: 'banana', + verbatim: false, + limit: 2, + offset: 1, + idsOnly: false, + sortAscending: false, + sortBy: 'whatever', + })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/transaction?transaction_type=testing&q=banana&offset=1&limit=2&verbatim=false&id_only=false&sort_by=whatever&sort_asc=false', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + it('defaults offset and limit', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.queryTransactions({ + transactionType: 'test', + redisearchQuery: 'yeah', + })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/transaction?transaction_type=test&q=yeah&offset=0&limit=10', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.queryBlocks', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.queryBlocks({ redisearchQuery: 'banana', limit: 2, offset: 1, idsOnly: false, sortAscending: false, sortBy: 'something' })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, "fakeUrl/v1/block?q=banana&offset=1&limit=2&id_only=false&sort_by=something&sort_asc=false", expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + it('defaults offset and limit', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.queryBlocks({ + redisearchQuery: 'yeah', + })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/block?q=yeah&offset=0&limit=10', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.listSmartContracts', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.listSmartContracts()]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, "fakeUrl/v1/contract", expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getSmartContractLogs', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.getSmartContractLogs({ smartContractId: 'test', tail: 100, since: 'a-date' })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, "fakeUrl/v1/contract/test/logs?tail=100&since=a-date", expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + it('calls #fetch() with correct params and missing erroneous ?', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.getSmartContractLogs({ smartContractId: 'test' })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, "fakeUrl/v1/contract/test/logs", expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getInterchainNetwork', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.getInterchainNetwork({ blockchain: 'bitcoin', name: 'banana' })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/bitcoin/banana'); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.listInterchainNetworks', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.listInterchainNetworks({ blockchain: 'bitcoin' })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/bitcoin'); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.getDefaultInterchainNetwork', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.getDefaultInterchainNetwork()]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/default'); + return [2 /*return*/]; + } + }); + }); }); + }); + }); + describe('DELETE', function () { + var fakeResponseObj = { body: 'fakeResponseBody' }; + var fakeResponseText = 'fakeString'; + var fetch = sinon_1.stub().resolves({ status: 200, json: sinon_1.stub().resolves(fakeResponseObj), text: sinon_1.stub().resolves(fakeResponseText) }); + var CredentialService = { getAuthorizationHeader: sinon_1.stub().returns('fakeCreds'), dragonchainId: 'fakeDragonchainId' }; + var logger = { log: sinon_1.stub(), debug: sinon_1.stub() }; + var injected = { logger: logger, fetch: fetch }; + var client = new DragonchainClient_1.DragonchainClient('fakeUrl', CredentialService, true, injected); + var expectedFetchOptions = { + method: 'DELETE', + credentials: 'omit', + headers: { + dragonchain: 'fakeDragonchainId', + Authorization: 'fakeCreds', + timestamp: fakeTime, + }, + body: undefined, + }; + describe('.deleteSmartContract', function () { + it('calls #fetch() with correct params (smart contract ID)', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var param; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + param = 'banana'; + return [4 /*yield*/, client.deleteSmartContract({ smartContractId: param })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/contract/banana', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + it('calls #fetch() with correct params (transaction type)', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var param; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + param = 'banana'; + return [4 /*yield*/, client.deleteSmartContract({ transactionType: param })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/contract/txn_type/banana', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.deleteApiKey', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.deleteApiKey({ keyId: 'MyKeyID' })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/api-key/MyKeyID', expectedFetchOptions); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.deleteInterchainNetwork', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.deleteInterchainNetwork({ blockchain: 'bitcoin', name: 'banana' })]; + case 1: + _a.sent(); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/bitcoin/banana'); + return [2 /*return*/]; + } + }); + }); }); + }); + }); + describe('POST', function () { + var fakeResponseObj = { body: 'fakeResponseBody' }; + var fakeResponseText = 'fakeString'; + var fetch = sinon_1.stub().resolves({ status: 200, json: sinon_1.stub().resolves(fakeResponseObj), text: sinon_1.stub().resolves(fakeResponseText) }); + var CredentialService = { getAuthorizationHeader: sinon_1.stub().returns('fakeCreds'), dragonchainId: 'fakeDragonchainId' }; + var logger = { log: sinon_1.stub(), debug: sinon_1.stub() }; + var injected = { logger: logger, CredentialService: CredentialService, fetch: fetch }; + var client = new DragonchainClient_1.DragonchainClient('fakeUrl', CredentialService, true, injected); + var expectedFetchOptions = { + method: 'POST', + credentials: 'omit', + headers: { + 'Content-Type': 'application/json', + dragonchain: 'fakeDragonchainId', + Authorization: 'fakeCreds', + timestamp: fakeTime, + }, + }; + describe('.createApiKey', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var expectedBody; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.createApiKey({ nickname: 'mynickname', permissionsDocument: { version: '1', default_allow: true, permissions: {} } })]; + case 1: + _a.sent(); + expectedBody = { nickname: 'mynickname', permissions_document: { version: '1', default_allow: true, permissions: {} } }; + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/api-key', tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(expectedBody) })); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.createTransaction', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var transactionCreatePayload, expectedBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + transactionCreatePayload = { + transactionType: 'transaction', + payload: 'hi!', + tag: 'Awesome!', + }; + expectedBody = { + version: '1', + txn_type: transactionCreatePayload.transactionType, + payload: transactionCreatePayload.payload, + tag: transactionCreatePayload.tag, + }; + return [4 /*yield*/, client.createTransaction(transactionCreatePayload)]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(expectedBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/transaction', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.createTransactionType', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var expectedBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + expectedBody = { + version: '2', + txn_type: 'testing', + custom_indexes: [ + { + path: 'testPath', + field_name: 'someField', + type: 'text', + options: { + no_index: false, + weight: 0.5, + sortable: true, + }, + }, + ], + }; + return [4 /*yield*/, client.createTransactionType({ + transactionType: 'testing', + customIndexFields: [{ path: 'testPath', fieldName: 'someField', type: 'text', options: { noIndex: false, sortable: true, weight: 0.5 } }], + })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(expectedBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/transaction-type', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.createSmartContract', function () { + it('create custom contract successfully', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var contractPayload, expectedBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + contractPayload = { + transactionType: 'name', + image: 'ubuntu:latest', + environmentVariables: { banana: 'banana', apple: 'banana' }, + cmd: 'banana', + args: ['-m', 'cool'], + }; + expectedBody = { + version: '3', + txn_type: 'name', + image: contractPayload.image, + execution_order: 'parallel', + cmd: contractPayload.cmd, + args: contractPayload.args, + env: contractPayload.environmentVariables, + }; + return [4 /*yield*/, client.createSmartContract(contractPayload)]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(expectedBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/contract', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.createEthereumTransaction', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var transactionCreatePayload, expectedBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + transactionCreatePayload = { + network: 'ETH_MAINNET', + to: '0x0000000000000000000000000000000000000000', + value: '0x0', + data: '0x111', + gasPrice: '0x222', + gas: '0x333', + }; + expectedBody = { + network: transactionCreatePayload.network, + transaction: { + to: transactionCreatePayload.to, + value: transactionCreatePayload.value, + data: transactionCreatePayload.data, + gasPrice: transactionCreatePayload.gasPrice, + gas: transactionCreatePayload.gas, + }, + }; + return [4 /*yield*/, client.createEthereumTransaction(transactionCreatePayload)]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(expectedBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/public-blockchain-transaction', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.createBitcoinInterchain', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + name: 'banana', + testnet: true, + private_key: 'abcd', + rpc_address: 'some rpc', + rpc_authorization: 'some auth', + utxo_scan: false, + }; + return [4 /*yield*/, client.createBitcoinInterchain({ name: 'banana', testnet: true, privateKey: 'abcd', rpcAddress: 'some rpc', rpcAuthorization: 'some auth', utxoScan: false })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/bitcoin', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.createEthereumInterchain', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + name: 'banana', + private_key: 'private key', + rpc_address: 'some rpc', + chain_id: 12, + }; + return [4 /*yield*/, client.createEthereumInterchain({ name: 'banana', privateKey: 'private key', rpcAddress: 'some rpc', chainId: 12 })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/ethereum', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.createBinanceInterchain', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + name: 'banana', + testnet: true, + private_key: 'abcd', + node_url: 'some IP', + rpc_port: 1234, + api_port: 5678, + }; + return [4 /*yield*/, client.createBinanceInterchain({ name: 'banana', testnet: true, privateKey: 'abcd', nodeURL: 'some IP', rpcPort: 1234, apiPort: 5678 })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/binance', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.signBitcoinTransaction', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + fee: 4, + data: 'someData', + change: 'change address', + outputs: [{ to: 'toaddr', value: 1.234 }], + }; + return [4 /*yield*/, client.signBitcoinTransaction({ name: 'banana', satoshisPerByte: 4, data: 'someData', changeAddress: 'change address', outputs: [{ to: 'toaddr', value: 1.234 }] })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/bitcoin/banana/transaction', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.signEthereumTransaction', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + to: 'some addr', + value: 'some value', + data: 'someData', + gasPrice: 'gas price', + gas: 'gas', + nonce: 'nonce', + }; + return [4 /*yield*/, client.signEthereumTransaction({ name: 'banana', to: 'some addr', value: 'some value', data: 'someData', gasPrice: 'gas price', gas: 'gas', nonce: 'nonce' })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/ethereum/banana/transaction', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.signBinanceTransaction', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + amount: 123, + to_address: 'receiver addy', + symbol: 'TOKEN', + memo: 'for bananas', + }; + return [4 /*yield*/, client.signBinanceTransaction({ name: 'banana', amount: 123, toAddress: 'receiver addy', symbol: 'TOKEN', memo: 'for bananas' })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/binance/banana/transaction', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.setDefaultInterchainNetwork', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + blockchain: 'bitcoin', + name: 'banana', + }; + return [4 /*yield*/, client.setDefaultInterchainNetwork({ name: 'banana', blockchain: 'bitcoin' })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/default', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.publishInterchainTransaction', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + blockchain: 'bitcoin', + name: 'banana', + signed_txn: 'banana', + }; + return [4 /*yield*/, client.publishInterchainTransaction({ name: 'banana', blockchain: 'bitcoin', signedTransaction: 'banana' })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/transaction/publish', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + }); + describe('PUT', function () { + var fakeResponseObj = { body: 'fakeResponseBody' }; + var fakeResponseText = 'fakeString'; + var fetch = sinon_1.stub().resolves({ status: 200, json: sinon_1.stub().resolves(fakeResponseObj), text: sinon_1.stub().resolves(fakeResponseText) }); + var CredentialService = { getAuthorizationHeader: sinon_1.stub().returns('fakeCreds'), dragonchainId: 'fakeDragonchainId' }; + var logger = { log: sinon_1.stub(), debug: sinon_1.stub() }; + var injected = { logger: logger, CredentialService: CredentialService, fetch: fetch }; + var client = new DragonchainClient_1.DragonchainClient('fakeUrl', CredentialService, true, injected); + var expectedFetchOptions = { + method: 'PUT', + credentials: 'omit', + headers: { + 'Content-Type': 'application/json', + dragonchain: 'fakeDragonchainId', + Authorization: 'fakeCreds', + timestamp: fakeTime, + }, + }; + describe('.updateApiKey', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var expectedBody; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, client.updateApiKey({ keyId: 'someKeyId', nickname: 'mynickname', permissionsDocument: { version: '1', default_allow: true, permissions: {} } })]; + case 1: + _a.sent(); + expectedBody = { nickname: 'mynickname', permissions_document: { version: '1', default_allow: true, permissions: {} } }; + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/api-key/someKeyId', tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(expectedBody) })); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.updateSmartContract', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var smartContractId, status, fakeBodyResponse, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + smartContractId = '616152367378'; + status = 'active'; + fakeBodyResponse = { + version: '3', + desired_state: status, + }; + return [4 /*yield*/, client.updateSmartContract({ smartContractId: smartContractId, enabled: true })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBodyResponse) }); + sinon_1.assert.calledWith(fetch, "fakeUrl/v1/contract/" + smartContractId, obj); + return [2 /*return*/]; + } + }); + }); }); + }); + }); + describe('PATCH', function () { + var fakeResponseObj = { body: 'fakeResponseBody' }; + var fakeResponseText = 'fakeString'; + var fetch = sinon_1.stub().resolves({ status: 200, json: sinon_1.stub().resolves(fakeResponseObj), text: sinon_1.stub().resolves(fakeResponseText) }); + var CredentialService = { getAuthorizationHeader: sinon_1.stub().returns('fakeCreds'), dragonchainId: 'fakeDragonchainId' }; + var logger = { log: sinon_1.stub(), debug: sinon_1.stub() }; + var injected = { logger: logger, CredentialService: CredentialService, fetch: fetch }; + var client = new DragonchainClient_1.DragonchainClient('fakeUrl', CredentialService, true, injected); + var expectedFetchOptions = { + method: 'PATCH', + credentials: 'omit', + headers: { + 'Content-Type': 'application/json', + dragonchain: 'fakeDragonchainId', + Authorization: 'fakeCreds', + timestamp: fakeTime, + }, + }; + describe('.updateBitcoinInterchain', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + testnet: true, + private_key: 'abcd', + rpc_address: 'some rpc', + rpc_authorization: 'some auth', + utxo_scan: false, + }; + return [4 /*yield*/, client.updateBitcoinInterchain({ name: 'banana', testnet: true, privateKey: 'abcd', rpcAddress: 'some rpc', rpcAuthorization: 'some auth', utxoScan: false })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/bitcoin/banana', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.updateEthereumInterchain', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + private_key: 'abcd', + rpc_address: 'some rpc', + chain_id: 12, + }; + return [4 /*yield*/, client.updateEthereumInterchain({ name: 'banana', privateKey: 'abcd', rpcAddress: 'some rpc', chainId: 12 })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/ethereum/banana', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + describe('.updateBinanceInterchain', function () { + it('calls #fetch() with correct params', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var fakeBody, obj; + return tslib_1.__generator(this, function (_a) { + switch (_a.label) { + case 0: + fakeBody = { + version: '1', + testnet: true, + private_key: 'abcd', + node_url: 'some IP', + rpc_port: 1234, + api_port: 5678, + }; + return [4 /*yield*/, client.updateBinanceInterchain({ name: 'banana', testnet: true, privateKey: 'abcd', nodeURL: 'some IP', rpcPort: 1234, apiPort: 5678 })]; + case 1: + _a.sent(); + obj = tslib_1.__assign(tslib_1.__assign({}, expectedFetchOptions), { body: JSON.stringify(fakeBody) }); + sinon_1.assert.calledWith(fetch, 'fakeUrl/v1/interchains/binance/banana', obj); + return [2 /*return*/]; + } + }); + }); }); + }); + }); +}); diff --git a/dist/types/errors/FailureByDesign.d.ts b/dist/types/errors/FailureByDesign.d.ts new file mode 100644 index 0000000..2cfdfdb --- /dev/null +++ b/dist/types/errors/FailureByDesign.d.ts @@ -0,0 +1,29 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Type of failure + */ +declare type failureCode = 'PARAM_ERROR' | 'NOT_FOUND'; +/** + * Error class thrown by the SDK + * All expected errors thrown by the SDK should be an instantiation of this class, with different codes as appropriate + */ +export declare class FailureByDesign extends Error { + code: failureCode; + message: string; + constructor(code: failureCode, message: string); +} +export {}; diff --git a/dist/types/index.d.ts b/dist/types/index.d.ts new file mode 100644 index 0000000..5afd7b4 --- /dev/null +++ b/dist/types/index.d.ts @@ -0,0 +1,30 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createClient, DragonchainClient as Client } from './services/dragonchain-client/DragonchainClient'; +/** + * @hidden + */ +declare let logger: any; +/** + * Set the logger that the sdk uses + * + * By default this logger will do nothing, thorwing away all logs + * @param newLogger a logger object that implements functions for: `log`, `info`, `warn`, `error`, and `debug` + */ +declare const setLogger: (newLogger?: any) => void; +export { createClient, setLogger, logger }; +export * from './interfaces/DragonchainClientInterfaces'; +export declare type DragonchainClient = Client; diff --git a/dist/types/interfaces/DragonchainClientInterfaces.d.ts b/dist/types/interfaces/DragonchainClientInterfaces.d.ts new file mode 100644 index 0000000..cc7d777 --- /dev/null +++ b/dist/types/interfaces/DragonchainClientInterfaces.d.ts @@ -0,0 +1,1201 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @hidden + * Supported HTTP methods for the sdk + */ +export declare type SupportedHTTP = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; +/** + * @hidden + * Fetch options used internally + */ +export interface FetchOptions { + method: SupportedHTTP; + headers: { + 'Content-Type'?: string; + 'X-Callback-URL'?: string; + dragonchain: string; + timestamp: string; + Authorization: string; + }; + body: string | undefined; + credentials?: string; +} +/** + * Response returned from a `DragonchainClient` call to a dragonchain + */ +export interface Response { + /** + * Boolean result if the response from the dragonchain was a 2XX status code, indicating a successful call + */ + ok: boolean; + /** + * HTTP status code returned from this call + */ + status: number; + /** + * Responses from Dragonchain will return here. + * + * Check the docs for the specific function you are calling to see what will appear here. + */ + response: T; +} +/** + * Data returned from a query against a chain + */ +export interface QueryResult { + /** + * Array of results + */ + results: T[]; + /** + * Total count of results that match the query + * + * Note this number can be higher than the length of the `results` array, + * indicating that pagination was used to shorten the `results` returned + */ + total: number; +} +/** + * Example Transaction At Rest Object + * @name Transaction::L1::FullTransaction + * @example + * ```json + * + * { + * "version": "1", + * "dcrn": "Transaction::L1::FullTransaction", + * "header": { + * "txn_type": "btcWatcher", + * "dc_id": "134376ff-8272-4da0-8523-53b0f60e26eb", + * "txn_id": "be3390a3-b76a-4749-9703-22e48a9c5a54", + * "block_id": "21500625", + * "timestamp": "1539741341", + * "tag": "", + * "invoker": "37aee185-bd5c-48bc-886e-52c6c9110314" + * }, + * "payload": "", + * "proof": { + * "full": "r9IjV3Mo3Sd9mWh5cAXxQP4h9tjiIec3Z1/+fI9F218=", + * "stripped": "MEUCIQCJLaYXAkm7/VkyrulVTxmUVAfVnOQy5hSYJZG2U7fgIgIgHGJWMoHt7/o/hoIGLqgqiGUc4ESiwMbIyKeJs88KHf4=" + * } + * } + * ``` + */ +export interface L1DragonchainTransactionFull { + /** + * string representing this Dragonchain Resource Name + */ + dcrn: 'Transaction::L1::FullTransaction'; + /** + * string representing the version of this DataTransferObject + */ + version: string; + header: { + /** + * name of a smart contract, or 'transaction' + */ + txn_type: string; + /** + * the dragonchainId which originally received this transaction + */ + dc_id: string; + /** + * the GUID of this transaction + */ + txn_id: string; + /** + * free-form string of search searchable data submitted by the transaction author + */ + tag: string; + /** + * unix timestamp of when this transaction was first processed + */ + timestamp: string; + /** + * the block id to which this transaction was fixated + */ + block_id: string; + /** + * the optional GUID of a smart-contract transaction which triggered this record. + * SC invocation requests are null here, their output will contain the transaction ID of their invokation request transaction) + */ + invoker: string; + }; + /** + * Payload data for this transaction + */ + payload: any; + proof: { + /** + * hash of the full transaction + */ + full: string; + /** + * signature of the stripped transaction + */ + stripped: string; + }; +} +/** + * @example + * ```json + * + * { + * "transaction_id": "487d6646-a988-40f0-bfee-3dba013fbc2c" + * } + * ``` + */ +export interface DragonchainTransactionCreateResponse { + transaction_id: string; +} +export interface BulkTransactionPayload { + /** + * The transaction type to use for this new transaction. This transaction type must already exist on the chain (via `createTransactionType`) + */ + transactionType: string; + /** + * Payload of the transaction. Must be a utf-8 encodable string, or any json object + */ + payload?: string | object; + /** + * Tag of the transaction which gets indexed and can be searched on for queries + */ + tag?: string; +} +interface FailedBulkTransactionCreate { + version: string; + txn_type: string; + payload: string | object; + tag?: string; +} +export interface DragonchainBulkTransactionCreateResponse { + /** + * Successfully posted transactions + */ + 201: DragonchainTransactionCreateResponse[]; + /** + * Transactions that failed to post + */ + 400: FailedBulkTransactionCreate[]; +} +export interface BitcoinTransactionOutputs { + to: string; + value: number; +} +/** + * Example response for signEthereumTransaction + * @example + * ```json + * + * { + * "signed": "0xf86380844160997982ea6094558c01dd95335749a29d040b24a183d8f7637bc880802aa05555e1cc2acd2543c3408855dea997678feaecdd66c2df1591109f43d4a7fc10a04594fe1c321f8dd344b5e7be43b2f58265d78d908a7520add57df0f31c69bc85" + * } + * ``` + */ +export interface PublicBlockchainTransactionResponse { + signed: string; +} +export declare type SupportedInterchains = 'ethereum' | 'bitcoin' | 'binance'; +/** + * @example + * ```json + * + * { + * "version": "1", + * "blockchain": "ethereum", + * "name": "myRopstenNetwork", + * "rpc_address": "http://1.2.3.4:8545", + * "chain_id": 3, + * "address": "0xbbF5029Fd710d227630c8b7d338051B8E76d50B3" + * } + * ``` + */ +export interface EthereumInterchainNetwork { + version: string; + blockchain: 'ethereum'; + name: string; + rpc_address: string; + chain_id: number; + address: string; +} +/** + * @example + * ```json + * + * { + * "version": "1", + * "blockchain": "bitcoin", + * "name": "myBTCTestNetwork", + * "rpc_address": "http://1.2.3.4:18332", + * "testnet": true, + * "address": "n1bUzF6LRENLPaiJRFTcnGLMLsbZSquft1" + * } + * ``` + */ +export interface BitcoinInterchainNetwork { + version: string; + blockchain: 'bitcoin'; + name: string; + rpc_address: string; + testnet: boolean; + address: string; +} +/** + * @example + * ```json + * + * { + * "version": "1", + * "blockchain": "binance", + * "name": "myBNBTestNetwork", + * "testnet": True, + * "node_url": "http://1.2.3.4", + * "rpc_port": 26657, + * "api_port": 11699, + * "address": "tbnb1zesqcktldshz7tat9u74duc037frzwvdq83wan" + * } + * ``` + */ +export interface BinanceInterchainNetwork { + version: string; + blockchain: 'binance'; + name: string; + node_url: string; + rpc_port: number; + api_port: number; + address: string; +} +/** + * Array of interchains will be all of one type + * @example + * ```json + * + * { + * "interchains": [{ + * "version": "1", + * "blockchain": "bitcoin", + * "name": "myBTCTestNetwork", + * "rpc_address": "http://1.2.3.4:18332", + * "tesnet": true, + * "address": "n1bUzF6LRENLPaiJRFTcnGLMLsbZSquft1" + * }] + * } + * ``` + */ +export interface InterchainNetworkList { + interchains: BitcoinInterchainNetwork[] | EthereumInterchainNetwork[] | BinanceInterchainNetwork[]; +} +/** + * Transaction hash (or equivalent) of a published interchain transaction + * @example + * ```json + * + * { + * "transaction": "0x37d1b1032288f7b434973c7840123bbf1acdb5ef5e40dda94257208ccf6c0c9f" + * } + * ``` + */ +export interface PublishedInterchainTransaction { + transaction: string; +} +/** + * @example + * ```json + * + * { + * "key": "d5K20n1VfHZYIgk55UdJO0bTyMTnjasdGkNyg66ASnd", + * "id": "PDJSYJNBTDBP", + * "registration_time": 1548604295, + * "nickname": "key1", + * "root": false, + * "permissions_document": { + * "version": "1", + * "default_allow": true, + * "permissions": { + * "api_keys": { + * "allow_create": false, + * "allow_update": false, + * "allow_delete": false + * } + * } + * } + * } + * ``` + */ +export interface CreateAPIKeyResponse { + key: string; + id: string; + registration_time: number; + nickname: string; + root: boolean; + permissions_document: PermissionsDocument; +} +/** + * @example + * ```json + * + * { + * "success": true + * } + * ``` + */ +export interface DeleteAPIKeyResponse { + success: boolean; +} +/** + * @example + * ```json + * + * { + * "id": "PDJSYJNBTDBP", + * "registration_time": 1548604295 + * "nickname": "", + * "root": false, + * "permissions_document": { + * "version": "1", + * "default_allow": true, + * "permissions": { + * "api_keys": { + * "allow_create": false, + * "allow_update": false, + * "allow_delete": false + * } + * } + * } + * } + * ``` + */ +export interface GetAPIKeyResponse { + id: string; + /** + * Unix timestamp (integer) when this key was created. Could be 0 if root key. + */ + registration_time: number; + nickname: string; + root: boolean; + permissions_document: PermissionsDocument; +} +/** + * @example + * ```json + * + * { + * "keys": [ + * { + * "id": "YLDSY14NTNJ8", + * "registration_time": 0 + * "nickname": "", + * "root": true, + * "permissions_document": { + * "version": "1", + * "default_allow": true, + * "permissions": {} + * } + * } + * ] + * } + * ``` + */ +export interface ListAPIKeyResponse { + keys: GetAPIKeyResponse[]; +} +/** + * @example + * ```json + * + * { + * "eth_mainnet": "0xa5C32bE6323Cd5E2BC87468F5F2D91849cDb3A3D", + * "eth_ropsten": "0x558c01dd95335749a29D040b24a183D8f7637BC8", + * "etc_mainnet": "0xf7A802DB95D783254A1f29F47785BA080daBF1db", + * "btc_mainnet": "17eK35gAem9Pezzs1RdntsoK9kK8dsF7DQ", + * "btc_testnet3": "mrgFVPYFMojNsx3gih84PSbQCDiB4rnoQJ" + * } + * ``` + */ +export interface PublicBlockchainAddressListResponse { + eth_mainnet?: string; + etc_mainnet?: string; + eth_ropsten?: string; + btc_mainnet?: string; + btc_testnet3?: string; +} +export declare type SmartContractExecutionOrder = 'parallel' | 'serial'; +/** + * Example SmartContract At Rest Object + * @name SmartContract::L1::AtRest + * @example + * ```json + * + * { + * "dcrn": "SmartContract::L1::AtRest", + * "version": "1", + * "txn_type": "c1", + * "id": "ec3e6dac-da91-4186-9c21-3f996b4462ab", + * "status": { + * "state": "active", + * "msg": "Creation success", + * "timestamp": "2019-05-21 20:19:10.519848" + * }, + * "image": "ubuntu:latest", + * "auth_key_id": "SC_ELDVFTEQWXCW", + * "image_digest": "sha256:9cf55af627c98299a13aac1349936128770bb0ce44b65344779034f52b2a7934", + * "cmd": "cat", + * "args": [ + * "-" + * ], + * "env": { + * "STAGE": "dev", + * "DRAGONCHAIN_ID": "ec67bbf5-b41e-4526-95fd-6a7c3abdd058", + * "SMART_CONTRACT_ID": "ec3e6dac-da91-4186-9c21-3f996b4462ab", + * "SMART_CONTRACT_NAME": "c1" + * }, + * "existing_secrets": [ + * "secret-key", + * "auth-key-id" + * ], + * "cron": null, + * "seconds": null, + * "execution_order": "parallel" + * } + * ``` + */ +export interface SmartContractAtRest { + /** + * string representing this Dragonchain Resource Name + */ + dcrn: 'SmartContract::L1::AtRest'; + /** + * string representing the version of this DataTransferObject + */ + version: '3'; + /** + * the name (and also transaction type to invoke) this smart contract + */ + txn_type: string; + /** + * The unique guid identifier for this contract + */ + id: string; + /** + * data about the current status of the smart contract + */ + status: { + state: 'active' | 'inactive'; + msg: string; + timestamp: string; + }; + /** + * docker image of the smart contract + */ + image: string; + /** + * id of the auth key that is used by the smart contract for communication back with the chain + */ + auth_key_id: string | null; + /** + * docker image pull digest of the deployed smart contract + */ + image_digest: string | null; + /** + * command that is run on execution of the smart contract + */ + cmd: string; + /** + * args passed into the command on execution of the smart contract + */ + args: string[] | null; + /** + * environment variables given to the smart contract + */ + env: object | null; + /** + * array of secret names for this smart contract + */ + existing_secrets: string[] | null; + /** + * cron expression for scheduling automatic execution of the smart contract + */ + cron: string | null; + /** + * number of seconds between automatic executions of the smart contract + */ + seconds: number | null; + /** + * execution order of the contract, whether it gets invoked asap (parallel), or in a single queue (serial) + */ + execution_order: SmartContractExecutionOrder; +} +/** + * Example smart contract logs + * @example + * ```json + * + * { + * "logs": [ + * { + * "name": "contract-my-contract-id", + * "instance": "contract-my-contract-id-5930345", + * "timestamp": "1568676319", + * "text": "This is my log!" + * }, + * ... + * ] + * } + * ``` + */ +export interface SmartContractLogs { + /** + * Array of logs + */ + logs: { + /** + * The name of the contract deployment + */ + name: string; + /** + * The pod instance the log came from + */ + instance: string; + /** + * The timestamp the log occurred at + */ + timestamp: string; + /** + * The log itself + */ + text: string; + }[]; +} +/** + * Example smart contract list + * @example + * ```json + * + * { + * "smart_contracts": [{ + * "dcrn": "SmartContract::L1::AtRest", + * "version": "1", + * "txn_type": "c1", + * "id": "ec3e6dac-da91-4186-9c21-3f996b4462ab", + * "status": { + * "state": "active", + * "msg": "Creation success", + * "timestamp": "2019-05-21 20:19:10.519848" + * }, + * "image": "ubuntu:latest", + * "auth_key_id": "SC_ELDVFTEQWXCW", + * "image_digest": "sha256:9cf55af627c98299a13aac1349936128770bb0ce44b65344779034f52b2a7934", + * "cmd": "cat", + * "args": [ + * "-" + * ], + * "env": { + * "STAGE": "dev", + * "DRAGONCHAIN_ID": "ec67bbf5-b41e-4526-95fd-6a7c3abdd058", + * "SMART_CONTRACT_ID": "ec3e6dac-da91-4186-9c21-3f996b4462ab", + * "SMART_CONTRACT_NAME": "c1" + * }, + * "existing_secrets": [ + * "secret-key", + * "auth-key-id" + * ], + * "cron": null, + * "seconds": null, + * "execution_order": "parallel" + * }] + * } + * ``` + */ +export interface SmartContractList { + smart_contracts: SmartContractAtRest[]; +} +/** + * Example of the status result + * @example + * ```json + * + * { + * "id": "23UeELiu8WDM7iVtvFqNbBJTt29xFS3J53zX5ZJTiRyob", + * "level": 1, + * "url": "https://d3cabac3-e30d-4bb9-aeed-1fc8cbd38c66.api.dragonchain.com", + * "scheme": "trust", + * "hashAlgo": "blake2b", + * "version": "3.3.1", + * "encryptionAlgo": "secp256k1" + * "indexingEnabled": true + * } + * ``` + */ +export interface L1DragonchainStatusResult { + /** + * Public id of the dragonchain + */ + id: string; + /** + * Level of this dragonchain (as an integer) + */ + level: number; + /** + * URL of the chain + */ + url: string; + /** + * Proof scheme that this chain uses + */ + scheme: string; + /** + * Hashing algorithm used for blocks on this chain + */ + hashAlgo: string; + /** + * Dragonchain version of this chain + */ + version: string; + /** + * Encryption algorithm used for blocks on this chain + */ + encryptionAlgo: string; + /** + * Whether or not indexing is enabled on this chain + */ + indexingEnabled: boolean; +} +/** + * Example L1 Block At Rest Object + * @name Block::L1::AtRest + * @example + * ```json + * + * { + * "version": "1", + * "dcrn": "Block::L1::AtRest", + * "header": { + * "dc_id": "28VhSgtPhwkhKBgmQSW6vrsir7quEYHdCjqsW6aAYbfrw", + * "block_id": "25261901", + * "level": 1, + * "timestamp": "1558547725", + * "prev_id": "25261892", + * "prev_proof": "MEUCIQCa8Ps0uV56BnE84hkl3HywSxCmkTIWqWVrMfilryhhjgIgdpwC2s0n5trRXI8yCsYItX173KHiyaSIjczw1pM1w24=" + * }, + * "transactions": [ + * "{\"version\": \"2\", \"dcrn\": \"Transaction::L1::Stripped\", \"header\": {\"txn_type\": \"c1\", \"dc_id\": \"28VhSgtPhwkhKBgmQSW6vrsir7quEYHdCjqsW6aAYbfrw\", \"txn_id\": \"77b902ff-5900-432a-a507-93ba097446fa\", \"block_id\": \"25261901\", \"timestamp\": \"1558547724\", \"tag\": \"\", \"invoker\": \"cron\"}, \"proof\": {\"full\": \"FIF2mF2fS7Ihcq1B/KjU/WcOZQ5vu/9C/SJVnReAsEc=\", \"stripped\": \"MEUCIQDVwWctm4CFiTJdkGkY6fG/rM+B1gBwxavm9ws0OSpLHQIgYp/ucEZUa0Vk/Tw/qyI14HyNTyHzLoKp8XsJLq2GXVY=\"}}" + * ], + * "proof": { + * "scheme": "trust", + * "proof": "MEQCICfhDVHOjVN6aexzimxn18+6IBhYg05/5YXadhm5+9GVAiA+BqW0kVfeJEESiiT4WqEH1vT7K0F6xnnwRcbM7cgasQ==" + * } + * } + * ``` + */ +export interface L1BlockAtRest { + version: '1'; + dcrn: 'Block::L1::AtRest'; + header: { + dc_id: string; + block_id: string; + level: 1; + timestamp: string; + prev_id: string; + prev_proof: string; + }; + transactions: string[]; + proof: { + scheme: string; + proof: string; + nonce?: number; + }; +} +/** + * Example L2 Block At Rest Object + * @name Block::L2::AtRest + * @example + * ```json + * + * { + * "version": "1", + * "dcrn": "Block::L2::AtRest", + * "header": { + * "dc_id": "e7rBQ3CP2Q93wmwQcH6VKzTiRUsAHoGh8fRvxnvx7M31", + * "current_ddss": "5484875.54508316", + * "level": 2, + * "block_id": "44192", + * "timestamp": "1555830009", + * "prev_proof": "MEQCIBjCggGtfMbra7RYlmNxiGReGHB7Y+6yM56/s73tRCymAiBlySM+yxwKBvBvNpR3FXucCbQYRdciQPGKEThv2E3Q4Q==" + * }, + * "validation": { + * "dc_id": "28VhSgtPhwkhKBgmQSW6vrsir7quEYHdCjqsW6aAYbfrw", + * "block_id": "24718321", + * "stripped_proof": "MEUCIQC3Boti9Sh+nECPvG0Y4dg+h/8GgVF6HmJZcEujUwlDEwIgRClM/01rejnGDbfmFS4VUhOUzMYDr+Pdo02B9Xwf/u8=", + * "transactions": "{\"358da848-4cd5-45ff-a776-6d1af52cb972\": true}" + * }, + * "proof": { + * "scheme": "trust", + * "proof": "MEQCIHDm8ecCpHUf6/cJ05xhIGKdOJBWP0pdLgILnqcvM+BCAiALVMKFdsNHw4IBgzsiOp8lRPizV88jklQNuMnSyLKhkQ==" + * } + * } + * ``` + */ +export interface L2BlockAtRest { + version: '1'; + dcrn: 'Block::L2::AtRest'; + header: { + dc_id: string; + current_ddss: string | null; + level: 2; + block_id: string; + timestamp: string; + prev_proof: string; + }; + validation: { + dc_id: string; + block_id: string; + stripped_proof: string; + transactions: string; + }; + proof: { + scheme: string; + proof: string; + nonce?: number; + }; +} +interface L2Proofs { + dc_id: string; + block_id: string; + proof: string; +} +/** + * Example L3 Block At Rest Object + * @name Block::L3::AtRest + * @example + * ```json + * + * { + * "version": "2", + * "dcrn": "Block::L3::AtRest", + * "header": { + * "dc_id": "nGfVFAKSUrdC7UrfzuBKErx7rKGwoPRuaFWQa8hrZcFs", + * "current_ddss": "1856875.54502316", + * "level": 3, + * "block_id": "56", + * "timestamp": "1557436010", + * "prev_proof": "MEUCIQCx67WNIzUmzwtS+0PH3cWzIvzJYIgzvl8kN1nWk6S+RQIgIkuTpB1BMS8Lto6sPRbWhjUbc5AGm3W8Kcb77PgPTEk=" + * }, + * "l2-validations": { + * "l1_dc_id": "28VhSgtPhwkhKBgmQSW6vrsir7quEYHdCjqsW6aAYbfrw", + * "l1_block_id": "25039557", + * "l1_proof": "MEUCIQDtq1SPpP4Rx6c3ivI8DZqdIVbXkzNYlq1Wy/8XBnavIQIgQ16eV3Fm65mI3RKTdtDQZUMeOKSBfxFzM9/LRrndYi0=", + * "l2_proofs": [ + * { + * "dc_id": "e7rBQ3CP2Q93wmwQcH6VKzTiRUsAHoGh8fRvxnvx7M31", + * "block_id": "186183", + * "proof": "MEQCIBVx8UXqi1SOz0gVyQQ/AGZO0z/4K/3IF9HzerIdSrTEAiB5K8NsQXnFoRiPcPGxcKyrfmvp0j3zJhTRHAwiXxED6Q==" + * } + * ], + * "ddss": "0", + * "count": "1", + * "regions": [ + * "us-west-2" + * ], + * "clouds": [ + * "aws" + * ] + * }, + * "proof": { + * "scheme": "trust", + * "proof": "MEUCIQDJkRS++nb8m0vVMfH/QsGssLsMn9J8e8Qd9jj+50P8pQIgG2MjJkGCbhXew0PTc+h3yk47m05btsVtw7vhV6olHfw=" + * } + * } + * ``` + */ +export interface L3BlockAtRest { + version: '2'; + dcrn: 'Block::L3::AtRest'; + header: { + dc_id: string; + current_ddss: string | null; + level: 3; + block_id: string; + timestamp: string; + prev_proof: string; + }; + 'l2-Validations': { + l1_dc_id: string; + l1_block_id: string; + l1_proof: string; + l2_proofs: L2Proofs[]; + ddss: string; + count: string; + regions: string[]; + clouds: string[]; + }; + proof: { + scheme: string; + proof: string; + nonce?: number; + }; +} +interface L3Validations { + l3_dc_id: string; + l3_block_id: string; + l3_proof: string; + valid: boolean; +} +/** + * Example L4 Block At Rest Object + * @name Block::L4::AtRest + * @example + * ```json + * + * { + * "version": "2", + * "dcrn": "Block::L4::AtRest", + * "header": { + * "dc_id": "sCXTCajomLiDxuU6j18UfMdNLYohgJ7SwmF3WgCGZ9v2", + * "current_ddss": "1189586.16584187", + * "level": 4, + * "block_id": "1337", + * "timestamp": "1555056367", + * "l1_dc_id": "28VhSgtPhwkhKBgmQSW6vrsir7quEYHdCjqsW6aAYbfrw", + * "l1_block_id": "24563621", + * "l1_proof": "MEQCIHHn/1gCCY5DqkCRo8ZJbZeru+MWkXl0GpbR05Ejx7t+AiANd5M0EWzIneQrX0PP4mGiykGkof60e0r6i09hKF84vA==", + * "prev_proof": "MEUCIQCjmrzAWBDpKnLbD83lrv+eVkLhWFBntcFCrfzr+C473QIgNIEvSrIK6LFRbXkDnpWcss0TOlO+JhcJU8jF1eiVsGw=" + * }, + * "l3-validations": [ + * { + * "l3_dc_id": "nGfVFAKSUrdC7UrfzuBKErx7rKGwoPRuaFWQa8hrZcFs", + * "l3_block_id": "3212", + * "l3_proof": "MEUCIQDkVyFbjbazUvWMpn+Ca0Q+XVYyFfwxEfc1qp7fGK0vAgIgQII9Wb79DpLsV9wG/5BnNQF132Z+MgCZL9SyC/ONmr0=", + * "valid": true + * } + * ], + * "proof": { + * "scheme": "trust", + * "proof": "MEUCIQDih7ldBKtdltCkiEe1KV8U5+XXaeQ+gUUMR9okqNbz0wIgGnxFEpwQYcB70nOx/972PWC0G+7n2soCkCdvG4jveZY=" + * } + * } + * ``` + */ +export interface L4BlockAtRest { + version: '2'; + dcrn: 'Block::L4::AtRest'; + header: { + dc_id: string; + current_ddss: string | null; + level: 4; + block_id: string; + timestamp: string; + l1_dc_id: string; + l1_block_id: string; + l1_proof: string; + prev_proof: string; + }; + 'l3-Validations': L3Validations[]; + proof: { + scheme: string; + proof: string; + nonce?: number; + }; +} +/** + * Example L5 Block At Rest Object + * @name Block::L5::AtRest + * @example + * ```json + * + * { + * "version": "1", + * "dcrn": "Block::L5::AtRest", + * "header": { + * "dc_id": "x9RLJC7pZW1QLCsQAWYsBLSKMXG7sAVNg9Bo9BJxDuB5", + * "current_ddss": "698453.15864657, + * "level": 5, + * "block_id": "3848", + * "timestamp": "1557649020", + * "prev_proof": "MEQCIHcpCbcYKGFq++zHB3RsQAC1PZ+wYAZWr/KLMv8WxQEuAiAlRyPYPzJOfu3ivZfwWIy/+dYDKuXxCvrnoI7biBvkBw==" + * }, + * "l4-blocks": [ + * "{\"l1_dc_id\": \"28VhSgtPhwkhKBgmQSW6vrsir7quEYHdCjqsW6aAYbfrw\", \"l1_block_id\": \"24563150\", \"l4_dc_id\": \"sCXTCajomLiDxuU6j18UfMdNLYohgJ7SwmF3WgCGZ9v2\", \"l4_block_id\": \"1209\", \"l4_proof\": \"MEUCIQCgYcj/nht2BImgomi9KVae33Eb2xAFwFAhAnN/PyfzPAIgIIZbRscNi4TvvSYXrs4PtN4eRuVE1c5LjU9be7hmBT4=\"}" + * ], + * "proof": { + * "scheme": "trust", + * "transaction_hash": [ + * "19691d2f876738e2329f8546669a184cbfa74549ec7057bb797fd85e4a2bc702" + * ], + * "block_last_sent_at": 1515332, + * "network": "testnet3", + * "proof": "MEQCICL13yYHYc1F7mkd00SEoYT6OSMQvKPO27R4lVZSGe7gAiBFRBBhjXQiOih3uHMqqRdF0D0S41IKfg+JpwKICE4dJw==" + * } + * } + * ``` + */ +export interface L5BlockAtRest { + version: '1'; + dcrn: 'Block::L5::AtRest'; + header: { + dc_id: string; + current_ddss: string | null; + level: 5; + block_id: string; + timestamp: string; + prev_proof: string; + }; + 'l4-blocks': string[]; + proof: { + scheme: string; + transaction_hash: string[]; + block_last_sent_at: number; + network: string; + proof: string; + nonce?: number; + }; +} +/** + * @example + * ```json + * + * { + * "2": [], + * "3": [], + * "4": ["21yog8rLpaH43D8JgoczsQf7oHhwa9JJDr2FdsedjmSV9"], + * "5": ["vAo8DkPEPS8syjxEoJRmNNoX3tt6upXkSqhGxwzjz5Ws"], + * } + * ``` + */ +export interface PendingVerifications { + '2': string[]; + '3': string[]; + '4': string[]; + '5': string[]; +} +export interface Verifications { + '2': L2BlockAtRest[]; + '3': L3BlockAtRest[]; + '4': L4BlockAtRest[]; + '5': L5BlockAtRest[]; +} +export declare type levelVerifications = L2BlockAtRest[] | L3BlockAtRest[] | L4BlockAtRest[] | L5BlockAtRest[]; +export declare type BlockSchemaType = L1BlockAtRest | L2BlockAtRest | L3BlockAtRest | L4BlockAtRest | L5BlockAtRest; +/** + * @example + * ```json + * + * { + * "success": true + * } + * ``` + */ +export interface SimpleResponse { + success: boolean; +} +export interface CustomTextFieldOptions { + weight?: number; + noStem?: boolean; + sortable?: boolean; + noIndex?: boolean; +} +export interface CustomTagFieldOptions { + separator?: string; + noIndex?: boolean; +} +export interface CustomNumberFieldOptions { + sortable?: boolean; + noIndex?: boolean; +} +export declare type CustomIndexType = 'text' | 'tag' | 'number'; +export interface TransactionTypeCustomIndex { + path: string; + fieldName: string; + type: CustomIndexType; + options?: CustomTextFieldOptions | CustomTagFieldOptions | CustomNumberFieldOptions; +} +/** + * @example + * ```json + * + * { + * "version": "2", + * "txn_type": "example", + * "custom_indexes": [ + * { + * "path": "someJsonPath", + * "field_name": "aField", + * "type": "text", + * "options": { + * "weight": 0.5, + * "sortable": true + * } + * } + * ], + * "contract_id": "", + * "active_since_block": "26925824" + * } + * ``` + */ +export interface TransactionTypeResponse { + version: '2'; + txn_type: string; + custom_indexes: TransactionTypeCustomIndex[]; + /** + * If this is not a transaction type for a smart contract, this will be an empty string + */ + contract_id: string; + /** + * When this transaction type has been active since + */ + active_since_block: string; +} +/** + * @example + * ```json + * + * { + * "transaction_types": [ + * { + * "version": "2", + * "txn_type": "example", + * "custom_indexes": [ + * { + * "path": "someJsonPath", + * "field_name": "aField", + * "type": "text", + * "options": { + * "weight": 0.5, + * "sortable": true + * } + * } + * ], + * "contract_id": "", + * "active_since_block": "26925824" + * } + * ] + * } + * ``` + */ +export interface TransactionTypeListResponse { + transaction_types: TransactionTypeResponse[]; +} +export interface PermissionsDocumentDefaultEndpoint { + allowed: boolean; +} +export interface PermissionsDocument { + version: '1'; + default_allow: boolean; + permissions: { + allow_create?: boolean; + allow_read?: boolean; + allow_update?: boolean; + allow_delete?: boolean; + apiKeys?: { + allow_create?: boolean; + allow_read?: boolean; + allow_update?: boolean; + allow_delete?: boolean; + create_api_key?: PermissionsDocumentDefaultEndpoint; + get_api_key?: PermissionsDocumentDefaultEndpoint; + list_api_keys?: PermissionsDocumentDefaultEndpoint; + delete_api_key?: PermissionsDocumentDefaultEndpoint; + update_api_key?: PermissionsDocumentDefaultEndpoint; + }; + blocks?: { + allow_create?: boolean; + allow_read?: boolean; + allow_update?: boolean; + allow_delete?: boolean; + get_block?: PermissionsDocumentDefaultEndpoint; + query_blocks?: PermissionsDocumentDefaultEndpoint; + }; + interchains?: { + allow_create?: boolean; + allow_read?: boolean; + allow_update?: boolean; + allow_delete?: boolean; + create_interchain?: PermissionsDocumentDefaultEndpoint; + update_interchain?: PermissionsDocumentDefaultEndpoint; + create_interchain_transaction?: PermissionsDocumentDefaultEndpoint; + list_interchains?: PermissionsDocumentDefaultEndpoint; + get_interchain?: PermissionsDocumentDefaultEndpoint; + delete_interchain?: PermissionsDocumentDefaultEndpoint; + get_default_interchain?: PermissionsDocumentDefaultEndpoint; + set_default_interchain?: PermissionsDocumentDefaultEndpoint; + get_interchain_legacy?: PermissionsDocumentDefaultEndpoint; + create_interchain_transaction_legacy?: PermissionsDocumentDefaultEndpoint; + }; + misc?: { + allow_create?: boolean; + allow_read?: boolean; + allow_update?: boolean; + allow_delete?: boolean; + get_status?: PermissionsDocumentDefaultEndpoint; + }; + contracts?: { + allow_create?: boolean; + allow_read?: boolean; + allow_update?: boolean; + allow_delete?: boolean; + get_contract?: PermissionsDocumentDefaultEndpoint; + get_contract_logs?: PermissionsDocumentDefaultEndpoint; + list_contracts?: PermissionsDocumentDefaultEndpoint; + create_contract?: PermissionsDocumentDefaultEndpoint; + update_contract?: PermissionsDocumentDefaultEndpoint; + delete_contract?: PermissionsDocumentDefaultEndpoint; + get_contract_object?: PermissionsDocumentDefaultEndpoint; + list_contract_objects?: PermissionsDocumentDefaultEndpoint; + }; + transactionTypes?: { + allow_create?: boolean; + allow_read?: boolean; + allow_update?: boolean; + allow_delete?: boolean; + create_transaction_type?: PermissionsDocumentDefaultEndpoint; + delete_transaction_type?: PermissionsDocumentDefaultEndpoint; + list_transaction_types?: PermissionsDocumentDefaultEndpoint; + get_transaction_type?: PermissionsDocumentDefaultEndpoint; + }; + transactions?: { + allow_create?: boolean; + allow_read?: boolean; + allow_update?: boolean; + allow_delete?: boolean; + create_transaction?: { + allowed?: boolean; + transaction_types?: { + [txn_type: string]: boolean; + }; + }; + query_transactions?: PermissionsDocumentDefaultEndpoint; + get_transaction?: PermissionsDocumentDefaultEndpoint; + }; + verifications?: { + allow_create?: boolean; + allow_read?: boolean; + allow_update?: boolean; + allow_delete?: boolean; + get_verifications?: PermissionsDocumentDefaultEndpoint; + get_pending_verifications?: PermissionsDocumentDefaultEndpoint; + query_interchain_verifications?: PermissionsDocumentDefaultEndpoint; + }; + }; +} +export interface EternalReportV1 { + l1Transaction?: L1DragonchainTransactionFull; + l1Block?: BlockSchemaType; + l2Verifications?: L2BlockAtRest[]; + l3Verifications?: L3BlockAtRest[]; + l4Verifications?: L4BlockAtRest[]; + l5Verifications?: L5BlockAtRest[]; +} +export {}; diff --git a/dist/types/services/config-service/ConfigCient.d.ts b/dist/types/services/config-service/ConfigCient.d.ts new file mode 100644 index 0000000..e460386 --- /dev/null +++ b/dist/types/services/config-service/ConfigCient.d.ts @@ -0,0 +1,95 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { DragonchainCredentials } from '../credential-service/DragonchainCredentials'; +/** + * @hidden + * Get the path for the configuration file depending on the OS + * @returns {string} dragonchain configuration file path + * @example e.g.: "~/.dragonchain/credentials" or "%LOCALAPPDATA%\dragonchain\credentials" on Windows + */ +declare const getConfigFilePath: (injected?: any) => string; +/** + * @hidden + * Get the endpoint for a dragonchain from environment variables + * @returns {string} Dragonchain enpdoint if found, empty string if not + */ +declare const getIdFromEnvVars: () => string; +/** + * @hidden + * get the endpoint for a dragonchain from environment variables + * @returns {string} Dragonchain enpdoint if found, empty string if not + */ +declare const getEndpointFromEnvVars: () => string; +/** + * @hidden + * get the credentials for a dragonchain from environment variables + * @returns {DragonchainCredentials} Dragonchain enpdoint if found, false if not + */ +declare const getCredsFromEnvVars: () => any; +/** + * @hidden + * get the default dragonchain ID from the configuration file + * @returns {Promise} dragonchain ID if found in file, empty string if not + */ +declare const getIdFromFile: (injected?: any) => Promise; +/** + * @hidden + * get the dragonchain endpoint from the configuration file + * @returns {Promise} dragonchain endpoint if found in file, empty string if not + */ +declare const getEndpointFromFile: (dragonchainId: string, injected?: any) => Promise; +/** + * @hidden + * get the dragonchain credentials from the configuration file + * @returns {Promise} dragonchain credentials if found in file, false if not + */ +declare const getCredsFromFile: (dragonchainId: string, injected?: any) => Promise; +/** + * @hidden + * use a remote service to fetch the endpoint of a dragonchain by id + * @param {string} dragonchainId dragonchainId to request endpoint for + * @returns {Promise} the endpoint of the dragonchain + * @throws {FailureByDesign} if unable to contact remote service or not found + */ +declare const getEndpointFromRemote: (dragonchainId: string, injected?: any) => Promise; +/** + * @hidden + * get credentials for a dragonchain from the standard location for a smart contract + * @returns {Promise} dragonchain credentials if found, false if not + */ +declare const getCredsAsSmartContract: (injected?: any) => Promise; +/** + * Get the default configured dragonchainId from environment/config file + * @returns {Promise} + * @throws {FailureByDesign} + */ +declare const getDragonchainId: (injected?: any) => Promise; +/** + * @hidden + * Get the endpoint for a dragonchain. First checks environment, then configuration files, then a remote service + * @param {string} dragonchainId dragonchainId to get endpoint for + * @returns {Promise} Endpoint of the dragonchain + * @throws {FailureByDesign} + */ +declare const getDragonchainEndpoint: (dragonchainId: string, injected?: any) => Promise; +/** + * Get the credentials for a dragonchain. First checks environment, then configuration files, then a smart contract location + * @param {string} dragonchainId dragonchainId to get credentials for + * @returns {DragonchainCredentials} Credentials of the dragonchain + * @throws {FailureByDesign} + */ +declare const getDragonchainCredentials: (dragonchainId: string, injected?: any) => Promise; +export { getDragonchainId, getDragonchainEndpoint, getDragonchainCredentials, getConfigFilePath, getIdFromEnvVars, getEndpointFromEnvVars, getCredsFromEnvVars, getIdFromFile, getEndpointFromFile, getCredsFromFile, getEndpointFromRemote, getCredsAsSmartContract, }; diff --git a/dist/types/services/config-service/ConfigClient.spec.d.ts b/dist/types/services/config-service/ConfigClient.spec.d.ts new file mode 100644 index 0000000..7bdb57b --- /dev/null +++ b/dist/types/services/config-service/ConfigClient.spec.d.ts @@ -0,0 +1,16 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export {}; diff --git a/dist/types/services/config-service/index.d.ts b/dist/types/services/config-service/index.d.ts new file mode 100644 index 0000000..32e5fcd --- /dev/null +++ b/dist/types/services/config-service/index.d.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { getDragonchainCredentials, getDragonchainId, getDragonchainEndpoint } from './ConfigCient'; +export { getDragonchainCredentials, getDragonchainId, getDragonchainEndpoint }; diff --git a/dist/types/services/credential-service/CredentialService.d.ts b/dist/types/services/credential-service/CredentialService.d.ts new file mode 100644 index 0000000..052869d --- /dev/null +++ b/dist/types/services/credential-service/CredentialService.d.ts @@ -0,0 +1,42 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { DragonchainCredentials } from './DragonchainCredentials'; +export declare type HmacAlgorithm = 'SHA256' | 'SHA3-256' | 'BLAKE2b512'; +/** + * @hidden + * Service to store Dragonchain credentials and generate authentication for use in API requests + */ +export declare class CredentialService { + dragonchainId: string; + credentials: DragonchainCredentials; + hmacAlgo: HmacAlgorithm; + /** + * async constructor to return an initialized CredentialService instantiation + */ + static createCredentials: (dragonchainId: string, authKey?: string, authKeyId?: string, hmacAlgo?: HmacAlgorithm, injected?: any) => Promise; + /** + * Construct a CredentialService object (This should not be called directly, and instead should be constructed with createCredentials) + */ + constructor(dragonchainId: string, credentials: DragonchainCredentials, hmacAlgo: HmacAlgorithm); + /** + * Return the HMAC signature used as the Authorization Header on REST requests to your dragonchain. + */ + getAuthorizationHeader: (method: string, path: string, timestamp: string, contentType: string, body: string) => string; + /** + * transform a DragonchainRequestObject into a compliant hmac message string + */ + private static getHmacMessageString; +} diff --git a/dist/types/services/credential-service/CredentialService.spec.d.ts b/dist/types/services/credential-service/CredentialService.spec.d.ts new file mode 100644 index 0000000..7bdb57b --- /dev/null +++ b/dist/types/services/credential-service/CredentialService.spec.d.ts @@ -0,0 +1,16 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export {}; diff --git a/dist/types/services/credential-service/DragonchainCredentials.d.ts b/dist/types/services/credential-service/DragonchainCredentials.d.ts new file mode 100644 index 0000000..600a8b3 --- /dev/null +++ b/dist/types/services/credential-service/DragonchainCredentials.d.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export interface DragonchainCredentials { + authKey: string; + authKeyId: string; +} diff --git a/dist/types/services/dragonchain-client/DragonchainClient.d.ts b/dist/types/services/dragonchain-client/DragonchainClient.d.ts new file mode 100644 index 0000000..a8cd007 --- /dev/null +++ b/dist/types/services/dragonchain-client/DragonchainClient.d.ts @@ -0,0 +1,1063 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { L1DragonchainTransactionFull, DragonchainTransactionCreateResponse, DragonchainBulkTransactionCreateResponse, SmartContractAtRest, SmartContractList, L1DragonchainStatusResult, Response, QueryResult, BlockSchemaType, Verifications, PendingVerifications, levelVerifications, TransactionTypeResponse, PublicBlockchainTransactionResponse, PublicBlockchainAddressListResponse, SimpleResponse, TransactionTypeListResponse, TransactionTypeCustomIndex, BitcoinTransactionOutputs, BulkTransactionPayload, ListAPIKeyResponse, CreateAPIKeyResponse, GetAPIKeyResponse, DeleteAPIKeyResponse, EthereumInterchainNetwork, BitcoinInterchainNetwork, BinanceInterchainNetwork, SupportedInterchains, InterchainNetworkList, PublishedInterchainTransaction, SmartContractLogs, PermissionsDocument, L5BlockAtRest, EternalReportV1 } from '../../interfaces/DragonchainClientInterfaces'; +import { CredentialService } from '../credential-service/CredentialService'; +/** + * HTTP Client that interfaces with the dragonchain api + */ +export declare class DragonchainClient { + /** + * @hidden + */ + private endpoint; + /** + * @hidden + */ + private verify; + /** + * @hidden + */ + private credentialService; + /** + * @hidden + */ + private fetch; + /** + * @hidden + */ + private readFileAsync; + /** + * @hidden + * Construct an instance of a DragonchainClient. THIS SHOULD NOT BE CALLED DIRECTLY. Instead use the `createClient` function to instantiate a client + */ + constructor(endpoint: string, credentials: CredentialService, verify: boolean, injected?: any); + /** + * Reads secrets provided to a smart contract + * + * Note: This will only work when running within a smart contract, given that the smart contract was created/updated with secrets + */ + getSmartContractSecret: (options: { + /** + * the name of the secret to retrieve for smart contract + */ + secretName: string; + }) => Promise; + /** + * Get the status of your dragonchain + */ + getStatus: () => Promise>; + /** + * Get a transaction by id + */ + getTransaction: (options: { + /** + * the transaction id of the transaction to get + */ + transactionId: string; + }) => Promise>; + /** + * Generate a new HMAC API key + */ + createApiKey: (options?: { + /** + * nickname for the newly created key + */ + nickname?: string | undefined; + /** + * Permissions document to use with this key + */ + permissionsDocument?: PermissionsDocument | undefined; + }) => Promise>; + /** + * List HMAC API key IDs and their associated metadata + */ + listApiKeys: () => Promise>; + /** + * Get metadata about an existing HMAC API key + */ + getApiKey: (options: { + /** + * the key id of the key to get + */ + keyId: string; + }) => Promise>; + /** + * Delete an existing HMAC API key + */ + deleteApiKey: (options: { + /** + * the key id of the key to delete + */ + keyId: string; + }) => Promise>; + /** + * Update nickname of existing HMAC API key + */ + updateApiKey: (options: { + /** + * Key ID to modify + */ + keyId: string; + /** + * New nickname to set for key + */ + nickname?: string | undefined; + /** + * New permissions document to assign to this key + */ + permissionsDocument?: PermissionsDocument | undefined; + }) => Promise>; + /** + * Create a new Transaction on your Dragonchain. + * + * This transaction, if properly structured, will be received by your dragonchain, hashed, and put into a queue for processing into a block. + * + * A POST request is made to the callback URL when the transaction has settled into a block on the Blockchain. + * + * The `transaction_id` returned from this function can be used for checking the status of this transaction, including the block in which it was included. + */ + createTransaction: (options: { + /** + * The transaction type to use for this new transaction. This transaction type must already exist on the chain (via `createTransactionType`) + */ + transactionType: string; + /** + * Payload of the transaction. Must be a utf-8 encodable string, or any json object + */ + payload?: string | object | undefined; + /** + * Tag of the transaction which gets indexed and can be searched on for queries + */ + tag?: string | undefined; + /** + * URL to callback when this transaction is processed + */ + callbackURL?: string | undefined; + }) => Promise>; + /** + * Create a bulk transaction to send many transactions to a chain with only a single call + */ + createBulkTransaction: (options: { + transactionList: BulkTransactionPayload[]; + }) => Promise>; + /** + * Query transactions using Redisearch query-string syntax + * + * For more information on how to use the Redisearch query-string syntax checkout their documentation: + * https://oss.redislabs.com/redisearch/Query_Syntax.html + * + * Note that transactions have the following fields: + * timestamp - sortable Numeric field + * block_id - sortable Numeric field + * tag - Text field + * + * Transaction types can also have additional custom fields if specified when creating the relevant transaction type/smart contract + * + * @example + * ```javascript + * myClient.queryTransactions({transactionType: 'example', redisearchQuery: 'somethingInTxnTag', sortBy: 'timestamp'}).then( ...do stuff ) + * ``` + */ + queryTransactions: (options: { + /** + * The single transaction type to query + */ + transactionType: string; + /** + * Redisearch query syntax string to search with + * https://oss.redislabs.com/redisearch/Query_Syntax.html + * @example + * word1|word2 + */ + redisearchQuery: string; + /** + * Whether or not to use redisearch's VERBATIM + * (if true, no stemming occurs on the query) + */ + verbatim?: boolean | undefined; + /** + * Pagination offset of query (default 0) + * Must be an integer + */ + offset?: number | undefined; + /** + * Pagination limit (default 10) + * Must be an integer + */ + limit?: number | undefined; + /** + * The name of the field to sort by + */ + sortBy?: string | undefined; + /** + * If sortBy is set, this sorts the results by that field in ascending order + * (descending if false) + */ + sortAscending?: boolean | undefined; + /** + * If true, rather than an array of transaction objects, + * it will return an array of transaction id strings instead + */ + idsOnly?: boolean | undefined; + }) => Promise>>; + /** + * Get a single block by ID + */ + getBlock: (options: { + /** + * ID of the block to fetch + */ + blockId: string; + }) => Promise>; + /** + * Query transactions using Redisearch query-string syntax + * + * For more information on how to use the Redisearch query-string syntax checkout their documentation: + * https://oss.redislabs.com/redisearch/Query_Syntax.html + * + * Note that blocks have the following fields: + * block_id - sortable Numeric field + * timestamp - sortable Numeric field + * prev_id - sortable Numeric field + * + * @example + * ```javascript + * myClient.queryBlocks({redisearchQuery: '*', sortBy: 'block_id'}).then( ...do stuff ) + * ``` + */ + queryBlocks: (options: { + /** + * Redisearch query syntax string to search with + * https://oss.redislabs.com/redisearch/Query_Syntax.html + * @example + * word1|word2 + */ + redisearchQuery: string; + /** + * Pagination offset of query (default 0) + * Must be an integer + */ + offset?: number | undefined; + /** + * Pagination limit (default 10) + * Must be an integer + */ + limit?: number | undefined; + /** + * The name of the field to sort by + */ + sortBy?: string | undefined; + /** + * If sortBy is set, this sorts the results by that field in ascending order + * (descending if false) + */ + sortAscending?: boolean | undefined; + /** + * If true, rather than an array of block objects, + * it will return an array of block id strings instead + */ + idsOnly?: boolean | undefined; + }) => Promise>>; + /** + * Create a new Smart Contract on your Dragonchain + */ + createSmartContract: (options: { + /** + * Transaction type to assign to this new smart contract + * + * Must not already exist as a transaction type on the chain + */ + transactionType: string; + /** + * Docker image to use with the smart contract. Should be in the form registry/image:tag (or just image:tag if it's a docker hub image) + * @example quay.io/coreos/awscli:latest + * @example alpine:3.9 + */ + image: string; + /** + * The command to run in your docker container for your application + * @example echo + */ + cmd: string; + /** + * The list of arguments to use in conjunction with cmd + * @example ['input', 'that', 'will', 'be', 'passed', 'in', 'as', 'args', 'to', 'cmd'] + */ + args?: string[] | undefined; + /** + * The execution of the smart contract, can be `serial` or `parallel`. Will default to `parallel` + * + * If running in serial, the contract will be queued and executed in order, only one at a time + * + * If running in parallel, the contract will be executed as soon as possible after invocation, potentially out of order, and many at a time + */ + executionOrder?: "parallel" | "serial" | undefined; + /** + * JSON object key-value pairs of strings for environments variables provided to the smart contract on execution + * @example + * ```javascript + * + * { MY_CUSTOM_ENV_VAR: "my_custom_env_value" } + * ``` + */ + environmentVariables?: object | undefined; + /** + * JSON object key-value pairs of strings for secrets provided to the smart contract on execution + * + * These are more securely stored than environment variables, and can be accessed during execution the smart contract by using the `getSmartContractSecret` method of the sdk + * @example + * ```javascript + * + * { MY_SECRET: "some secret special data" } + * ``` + */ + secrets?: object | undefined; + /** + * Schedule a smart contract to be automatically executed every `x` seconds + * + * For example: if `10` is supplied, then this contract will be automatically invoked and create a transaction once every 10 seconds + * + * This value should be a whole integer, and not a decimal + * + * Note: This is a mutually exclusive parameter with cronExpression + */ + scheduleIntervalInSeconds?: number | undefined; + /** + * Schedule a smart contract to be automatically executed on a cadence via a cron expression + * + * Note: This is a mutually exclusive parameter with scheduleIntervalInSeconds + * @example `* * * * *` This will invoke the contract automatically every minute, on the minute + */ + cronExpression?: string | undefined; + /** + * The basic-auth credentials necessary to pull the docker container. + * + * This should be a base64-encoded string of `username:password` for the docker registry + * @example ZXhhbXBsZVVzZXI6ZXhhbXBsZVBhc3N3b3JkCg== + */ + registryCredentials?: string | undefined; + /** + * The custom indexes that should be associated with the transaction type for this smart contract + */ + customIndexFields?: TransactionTypeCustomIndex[] | undefined; + }) => Promise>; + /** + * Update an existing Smart Contract on your Dragonchain + * + * Note that all parameters (aside from contract id) are optional, and only supplied parameters will be updated + */ + updateSmartContract: (options: { + /** + * Smart contract id of which to update. Should be a guid + */ + smartContractId: string; + /** + * Docker image to use with the smart contract. Should be in the form registry/image:tag (or just image:tag if it's a docker hub image) + * @example quay.io/coreos/awscli:latest + * @example alpine:3.9 + */ + image?: string | undefined; + /** + * The command to run in your docker container for your application + * @example echo + */ + cmd?: string | undefined; + /** + * The list of arguments to use in conjunction with cmd + * @example ['input', 'that', 'will', 'be', 'passed', 'in', 'as', 'args', 'to', 'cmd'] + */ + args?: string[] | undefined; + /** + * The execution of the smart contract, can be `serial` or `parallel`. Will default to `parallel` + * + * If running in serial, the contract will be queued and executed in order, only one at a time + * + * If running in parallel, the contract will be executed as soon as possible after invocation, potentially out of order, and many at a time + */ + executionOrder?: "parallel" | "serial" | undefined; + /** + * Boolean whether or not the contract should be enabled, and able to be invoked + */ + enabled?: boolean | undefined; + /** + * JSON object key-value pairs of strings for environments variables provided to the smart contract on execution + * @example + * ```javascript + * + * { MY_CUSTOM_ENV_VAR: "my_custom_env_value" } + * ``` + */ + environmentVariables?: object | undefined; + /** + * JSON object key-value pairs of strings for secrets provided to the smart contract on execution + * + * These are more securely stored than environment variables, and can be accessed during execution the smart contract by using the `getSmartContractSecret` method of the sdk + * @example + * ```javascript + * + * { MY_SECRET: "some secret special data" } + * ``` + */ + secrets?: object | undefined; + /** + * Schedule a smart contract to be automatically executed every `x` seconds + * + * For example, if `10` is supplied, then this contract will be automatically invoked and create a transaction once every 10 seconds + * + * This value should be a whole integer, and not a decimal + * + * Note: This is a mutually exclusive parameter with cronExpression + */ + scheduleIntervalInSeconds?: number | undefined; + /** + * Schedule a smart contract to be automatically executed on a cadence via a cron expression + * + * Note: This is a mutually exclusive parameter with scheduleIntervalInSeconds + * + * @example `* * * * *` This will invoke the contract automatically every minute, on the minute + */ + cronExpression?: string | undefined; + /** + * The basic-auth credentials necessary to pull the docker container. + * + * This should be a base64-encoded string of `username:password` for the docker registry + * + * @example ZXhhbXBsZVVzZXI6ZXhhbXBsZVBhc3N3b3JkCg== + */ + registryCredentials?: string | undefined; + /** + * Set true to remove the existing scheduleIntervalInSeconds or cronExpression from the contract + */ + disableSchedule?: boolean | undefined; + }) => Promise>; + /** + * Deletes a deployed smart contract + */ + deleteSmartContract: (options: { + /** + * The id of the smart contract to delete. Should be a guid + */ + smartContractId?: string | undefined; + /** + * Transaction type of the smart contract, mutually exclusive with smartContractId + */ + transactionType?: string | undefined; + }) => Promise>; + /** + * Get a single smart contract by one of id or transaction type + */ + getSmartContract: (options: { + /** + * Contract id to get, mutually exclusive with transactionType + */ + smartContractId?: string | undefined; + /** + * Transaction id of smart contract to get, mutually exclusive with smartContractId + */ + transactionType?: string | undefined; + }) => Promise>; + /** + * Get a single smart contract by one of id or transaction type + */ + getSmartContractLogs: (options: { + /** + * Contract id to get logs from + */ + smartContractId: string; + /** + * Tail, the maximum number of logs to return (unsigned integer) + */ + tail?: number | undefined; + /** + * RFC3339 timestamp string. Returns all logs since this datetime string + */ + since?: string | undefined; + }) => Promise>; + /** + * Get all smart contracts on a chain + */ + listSmartContracts: () => Promise>; + /** + * Get chain ids for the pending verifications for a block. Note that this is only relevant for level 1 chains. + */ + getPendingVerifications: (options: { + /** + * The block ID to retrieve pending verifications for + */ + blockId: string; + }) => Promise>; + /** + * Get verifications for a block. Note that this is only relevant for level 1 chains + */ + getVerifications: (options: { + /** + * The block ID to retrieve verifications for + */ + blockId: string; + /** + * The level of verifications to retrieve (2-5). If not supplied, all levels are returned + */ + level?: number | undefined; + }) => Promise | Response>; + /** + * Get an object from the smart contract heap. This is used for getting stateful data set by the outputs of smart contracts + */ + getSmartContractObject: (options: { + /** + * Key of the object to retrieve + */ + key: string; + /** + * Smart contract to get the object from + * + * When running from within a smart contract, this is provided via the SMART_CONTRACT_ID environment variable, and doesn't need to be explicitly provided + */ + smartContractId?: string | undefined; + }) => Promise>; + /** + * List objects from a folder within the heap of a smart contract + */ + listSmartContractObjects: (options?: { + /** + * The folder to list from the heap. Please note this CANNOT end in a '/' + * + * If nothing is provided, it will list at the root of the heap + * @example folder1 + * @example folder1/subFolder + */ + prefixKey?: string | undefined; + /** + * Smart contract to list the objects from + * + * When running from within a smart contract, this is provided via the SMART_CONTRACT_ID environment variable, and doesn't need to be explicitly provided + */ + smartContractId?: string | undefined; + }) => Promise>; + /** + * Create a new transaction type for ledgering transactions + */ + createTransactionType: (options: { + /** + * The string of the transaction type to create + * @example cust1 + */ + transactionType: string; + /** + * The custom indexes that should be associated with this transaction type + */ + customIndexFields?: TransactionTypeCustomIndex[] | undefined; + }) => Promise>; + /** + * Deletes an existing registered transaction type + */ + deleteTransactionType: (options: { + /** + * The name of the transaction type to delete + */ + transactionType: string; + }) => Promise>; + /** + * Lists currently created transaction types + */ + listTransactionTypes: () => Promise>; + /** + * Gets an existing transaction type from the chain + */ + getTransactionType: (options: { + /** + * The name of the transaction type to get + */ + transactionType: string; + }) => Promise>; + /** + * Create (or overwrite) a bitcoin wallet/network for interchain use + */ + createBitcoinInterchain: (options: { + /** + * The name of the network to update + */ + name: string; + /** + * Whether or not this is a testnet wallet/address (not required if providing privateKey as WIF) + */ + testnet?: boolean | undefined; + /** + * The base64 encoded private key, or WIF for the desired wallet + */ + privateKey?: string | undefined; + /** + * The endpoint of the bitcoin core RPC node to use (i.e. http://my-node:8332) + */ + rpcAddress?: string | undefined; + /** + * The base64-encoded username:password for the rpc node. For example, user: a pass: b would be 'YTpi' (base64("a:b")) + */ + rpcAuthorization?: string | undefined; + /** + * Whether or not to force a utxo-rescan for the address. + * If using a new private key for an existing wallet with funds, this must be true to use its existing funds + */ + utxoScan?: boolean | undefined; + }) => Promise>; + /** + * Update an existing bitcoin wallet/network for interchain use. Will only update the provided fields + */ + updateBitcoinInterchain: (options: { + /** + * The name of the network to update + */ + name: string; + /** + * Whether or not this is a testnet wallet/address (not required if providing privateKey as WIF) + */ + testnet?: boolean | undefined; + /** + * The base64 encoded private key, or WIF for the desired wallet + */ + privateKey?: string | undefined; + /** + * The endpoint of the bitcoin core RPC node to use (i.e. http://my-node:8332) + */ + rpcAddress?: string | undefined; + /** + * The base64-encoded username:password for the rpc node. For example, user: a pass: b would be 'YTpi' (base64("a:b")) + */ + rpcAuthorization?: string | undefined; + /** + * Whether or not to force a utxo-rescan for the address. + * If using a new private key for an existing wallet with funds, this must be true to use its existing funds + */ + utxoScan?: boolean | undefined; + }) => Promise>; + /** + * Sign a transaction for a bitcoin network on the chain + */ + signBitcoinTransaction: (options: { + /** + * The name of the bitcoin network to use for signing + */ + name: string; + /** + * The desired fee in satoshis/byte. Must be an integer + * + * If not supplied, an estimate will be automatically generated + */ + satoshisPerByte?: number | undefined; + /** + * String data to embed in the transaction as null-data output type + */ + data?: string | undefined; + /** + * Change address to use for this transaction. If not supplied, this will be the source address + */ + changeAddress?: string | undefined; + /** + * The desired bitcoin outputs to create for this transaction + */ + outputs?: BitcoinTransactionOutputs[] | undefined; + }) => Promise>; + /** + * Create (or overwrite) an ethereum wallet/network for interchain use + */ + createEthereumInterchain: (options: { + /** + * The name of the network to update + */ + name: string; + /** + * The base64 or hex encoded private key to use. Will automatically generate a random one if not provided + */ + privateKey?: string | undefined; + /** + * The endpoint of the ethereum RPC node to use (i.e. http://my-node:8545) + */ + rpcAddress?: string | undefined; + /** + * The ethereum chain id to use. Will automatically derive this if providing a custom rpcAddress. This should be an integer. + * Without providing a custom rpcAddress, Dragonchain manages and supports: 1=ETH Mainnet|3=ETH Ropsten|61=ETC Mainnet + */ + chainId?: number | undefined; + }) => Promise>; + /** + * Update an existing ethereum wallet/network for interchain use + */ + updateEthereumInterchain: (options: { + /** + * The name of the network to update + */ + name: string; + /** + * The base64 or hex encoded private key to use. Will automatically generate a random one if not provided + */ + privateKey?: string | undefined; + /** + * The endpoint of the ethereum RPC node to use (i.e. http://my-node:8545) + */ + rpcAddress?: string | undefined; + /** + * The ethereum chain id to use. Will automatically derive this if providing a custom rpcAddress. This should be an integer. + * Without providing a custom rpcAddress, Dragonchain manages and supports: 1=ETH Mainnet|3=ETH Ropsten|61=ETC Mainnet + */ + chainId?: number | undefined; + }) => Promise>; + /** + * Create and sign an ethereum transaction using your chain's interchain network + */ + signEthereumTransaction: (options: { + /** + * The name of the ethereum network to use for signing + */ + name: string; + /** + * The (hex-encoded) address to send the transaction to + */ + to: string; + /** + * The (hex-encoded) number of wei to send with this transaction + */ + value: string; + /** + * The (hex-encoded) string of extra data to include with this transaction + */ + data?: string | undefined; + /** + * The (hex-encoded) gas price in gwei to pay. If not supplied, this will be estimated automatically + */ + gasPrice?: string | undefined; + /** + * The (hex-encoded) gas limit for this transaction. If not supplied, this will be estimated automatically + */ + gas?: string | undefined; + /** + * The (hex-encoded) nonce for this transaction. If not supplied, it will be fetched automatically + */ + nonce?: string | undefined; + }) => Promise>; + /** + * Create (or overwrite) a binance wallet/network for interchain use + */ + createBinanceInterchain: (options: { + /** + * The name of the network to update + */ + name: string; + /** + * Whether or not this is a testnet wallet/address. Defaults to True. + */ + testnet?: boolean | undefined; + /** + * The base64 or hex encoded private key (or mnemonic) to use. Will automatically generate a random one if not provided + */ + privateKey?: string | undefined; + /** + * The endpoint of the binance node to use (i.e. http://my.node.address) + */ + nodeURL?: string | undefined; + /** + * The port being used to hit the RPC endpoints (i.e. 27147) + */ + rpcPort?: number | undefined; + /** + * The port being used to hit the API endpoints (i.e. 1169) + */ + apiPort?: number | undefined; + }) => Promise>; + /** + * Update an existing binance wallet/network for interchain use + */ + updateBinanceInterchain: (options: { + /** + * The name of the network to update + */ + name: string; + /** + * Whether or not this is a testnet wallet/address. Defaults to True. + */ + testnet?: boolean | undefined; + /** + * The base64 or hex encoded private key to use. Will automatically generate a random one if not provided + */ + privateKey?: string | undefined; + /** + * The endpoint of the binance node to use (i.e. http://my.node.address) + */ + nodeURL?: string | undefined; + /** + * The port being used to hit the RPC endpoints (i.e. 27147) + */ + rpcPort?: number | undefined; + /** + * The port being used to hit the API endpoints (i.e. 1169) + */ + apiPort?: number | undefined; + }) => Promise>; + /** + * Create and sign a binance transaction using your chain's interchain network + */ + signBinanceTransaction: (options: { + /** + * The name of the binance network to use for signing + */ + name: string; + /** + * the amount of token to send with this transaction + */ + amount: number; + /** + * The (hex-encoded) address to send the transaction to + */ + toAddress: string; + /** + * the exchange symbol for the token (defaults to BNB) + */ + symbol?: string | undefined; + /** + * string of data to publish in the transaction (defaults to "") + */ + memo?: string | undefined; + }) => Promise>; + /** + * Get a configured interchain network/wallet from the chain + */ + getInterchainNetwork: (options: { + /** + * The blockchain type to get (i.e. 'bitcoin', 'ethereum') + */ + blockchain: SupportedInterchains; + /** + * The name of that blockchain's network (set when creating the network) + */ + name: string; + }) => Promise>; + /** + * Delete an interchain network/wallet from the chain + */ + deleteInterchainNetwork: (options: { + /** + * The blockchain type to delete (i.e. 'bitcoin', 'ethereum') + */ + blockchain: SupportedInterchains; + /** + * The name of that blockchain's network (set when creating the network) + */ + name: string; + }) => Promise>; + /** + * List all the interchain network/wallets for a blockchain type + */ + listInterchainNetworks: (options: { + /** + * The blockchain type to get (i.e. 'bitcoin', 'ethereum') + */ + blockchain: SupportedInterchains; + }) => Promise>; + /** + * Set the default interchain network for the chain to use (L5 Only) + */ + setDefaultInterchainNetwork: (options: { + /** + * The blockchain type to set (i.e. 'bitcoin', 'ethereum') + */ + blockchain: SupportedInterchains; + /** + * The name of that blockchain's network to use (set when creating the network) + */ + name: string; + }) => Promise>; + /** + * Get the set default interchain network for this chain (L5 Only) + */ + getDefaultInterchainNetwork: () => Promise>; + /** + * Publish an interchain transaction that's already been signed + */ + publishInterchainTransaction: (options: { + /** + * The blockchain type to set (i.e. 'bitcoin', 'ethereum') + */ + blockchain: SupportedInterchains; + /** + * The name of that blockchain's network to use (set when creating the network) + */ + name: string; + /** + * Signed transaction string (return from signTransaction function) + */ + signedTransaction: string; + }) => Promise>; + /** + * !This method is deprecated and should not be used! + * Backwards compatibility will exist for legacy chains, but will not work on new chains. listInterchainNetworks should be used instead + * + * Gets a list of the chain's interchain addresses + */ + getPublicBlockchainAddresses: () => Promise>; + /** + * !This method is deprecated and should not be used! + * Backwards compatibility will exist for legacy chains, but will not work on new chains. signBitcoinTransaction should be used instead + * + * Sign a transaction for a bitcoin network + */ + createBitcoinTransaction: (options: { + /** + * The bitcoin network that the transaction is for (mainnet or testnet) + */ + network: "BTC_MAINNET" | "BTC_TESTNET3"; + /** + * The desired fee in satoshis/byte. Must be an integer + * + * If not supplied, an estimate will be automatically generated + */ + satoshisPerByte?: number | undefined; + /** + * String data to embed in the transaction as null-data output type + */ + data?: string | undefined; + /** + * Change address to use for this transaction. If not supplied, this will be the source address + */ + changeAddress?: string | undefined; + /** + * The desired bitcoin outputs to create for this transaction + */ + outputs?: BitcoinTransactionOutputs[] | undefined; + }) => Promise>; + /** + * !This method is deprecated and should not be used! + * Backwards compatibility will exist for legacy chains, but will not work on new chains. signEthereumTransaction should be used instead + * + * Sign a transaction for an ethereum network + */ + createEthereumTransaction: (options: { + /** + * The ethereum network that the transaction is for (ETH/ETC mainnet or testnet) + */ + network: "ETH_MAINNET" | "ETH_ROPSTEN" | "ETC_MAINNET"; + /** + * The (hex-encoded) address to send the transaction to + */ + to: string; + /** + * The (hex-encoded) number of wei to send with this transaction + */ + value: string; + /** + * The (hex-encoded) string of extra data to include with this transaction + */ + data?: string | undefined; + /** + * The (hex-encoded) gas price in gwei to pay. If not supplied, this will be estimated automatically + */ + gasPrice?: string | undefined; + /** + * The (hex-encoded) gas limit for this transaction. If not supplied, this will be estimated automatically + */ + gas?: string | undefined; + }) => Promise>; + /** + * Query the Dragonchain for the subsequent interchain (L5) transactions + */ + queryInterchainTransactions: (options: { + /** + * L1 block ID + */ + blockId: string; + }) => Promise>; + /** + * Get/Generate an Eternal-type report given a transaction ID + */ + getReport: (options: { + /** + * the transaction ID of the transaction to generate report for + */ + transactionId: string; + }) => Promise>; + /** + * @hidden + */ + getTimestamp(): string; + /** + * @hidden + */ + private get; + /** + * @hidden + */ + private post; + /** + * @hidden + */ + private put; + /** + * @hidden + */ + private patch; + /** + * @hidden + */ + private delete; + /** + * @hidden + */ + private validateAndBuildCustomIndexFieldsArray; + /** + * @hidden + */ + private generateQueryString; + /** + * @hidden + */ + private getFetchOptions; + /** + * @hidden + * For development purposes only! NodeJS naturally distrusts self signed certs (for good reason!). This function allows users the option to "not care" about self signed certs. + * @param {function} asyncFunction an async function to call while NODE_TLS_REJECT_UNAUTHORIZED is quickly toggled from "1" to "0" and back to "1" + */ + private toggleSslCertVerification; + /** + * @hidden + */ + private makeRequest; +} +/** + * Create and return an instantiation of a dragonchain client + */ +export declare const createClient: (options?: { + /** + * DragonchainId for this client. Not necessary if DRAGONCHAIN_ID env var is set, or if default is set in config file + */ + dragonchainId?: string | undefined; + /** + * AuthKeyId to explicitly use with this client. Must be set along with authKey or it will be ignored + */ + authKeyId?: string | undefined; + /** + * AuthKey to explicitly use with this client. Must be set along with authKeyId or it will be ignored + */ + authKey?: string | undefined; + /** + * Endpoint to explicitly use with this client. Should not have a trailing slash and look something like https://some.url + */ + endpoint?: string | undefined; + /** + * Whether or not to verify the https certificate for https connections. Defaults to true if not provided + */ + verify?: boolean | undefined; + /** + * The hmac algorithm to use when generating authenticated requests. Defaults to SHA256 + */ + algorithm?: "SHA256" | "SHA3-256" | "BLAKE2b512" | undefined; +}) => Promise; diff --git a/dist/types/services/dragonchain-client/DragonchainClient.spec.d.ts b/dist/types/services/dragonchain-client/DragonchainClient.spec.d.ts new file mode 100644 index 0000000..7bdb57b --- /dev/null +++ b/dist/types/services/dragonchain-client/DragonchainClient.spec.d.ts @@ -0,0 +1,16 @@ +/** + * Copyright 2020 Dragonchain, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export {}; diff --git a/package.json b/package.json index f206b35..4fecb9a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dragonchain-sdk", - "version": "4.3.4", + "version": "4.4.0", "description": "Dragonchain SDK for Node.JS and the Browser", "license": "Apache-2.0", "homepage": "https://github.com/dragonchain/dragonchain-sdk-javascript#readme", diff --git a/src/interfaces/DragonchainClientInterfaces.ts b/src/interfaces/DragonchainClientInterfaces.ts index ea49cfd..14a8a17 100644 --- a/src/interfaces/DragonchainClientInterfaces.ts +++ b/src/interfaces/DragonchainClientInterfaces.ts @@ -783,7 +783,7 @@ export interface L2BlockAtRest { dcrn: 'Block::L2::AtRest'; header: { dc_id: string; - current_ddds: string | null; + current_ddss: string | null; level: 2; block_id: string; timestamp: string; @@ -1233,6 +1233,16 @@ export interface PermissionsDocument { allow_delete?: boolean; get_verifications?: PermissionsDocumentDefaultEndpoint; get_pending_verifications?: PermissionsDocumentDefaultEndpoint; + query_interchain_verifications?: PermissionsDocumentDefaultEndpoint; }; }; } + +export interface EternalReportV1 { + l1Transaction?: L1DragonchainTransactionFull; + l1Block?: BlockSchemaType; + l2Verifications?: L2BlockAtRest[]; + l3Verifications?: L3BlockAtRest[]; + l4Verifications?: L4BlockAtRest[]; + l5Verifications?: L5BlockAtRest[]; +} diff --git a/src/services/dragonchain-client/DragonchainClient.spec.ts b/src/services/dragonchain-client/DragonchainClient.spec.ts index 9a24412..51ad19b 100644 --- a/src/services/dragonchain-client/DragonchainClient.spec.ts +++ b/src/services/dragonchain-client/DragonchainClient.spec.ts @@ -68,6 +68,13 @@ describe('DragonchainClient', () => { }; }); + describe('.queryInterchainTransactions', () => { + it('calls #fetch() with correct params', async () => { + await client.queryInterchainTransactions({ blockId: '123456789' }); + assert.calledWith(fetch, 'fakeUrl/v1/verifications/interchains/123456789', expectedFetchOptions); + }); + }); + describe('.getSmartContractSecret', () => { it('calls readFileAsync with correct dragonchain id and secret name', async () => { process.env.SMART_CONTRACT_ID = 'fakeSmartContractId'; diff --git a/src/services/dragonchain-client/DragonchainClient.ts b/src/services/dragonchain-client/DragonchainClient.ts index ece0f29..8c26807 100644 --- a/src/services/dragonchain-client/DragonchainClient.ts +++ b/src/services/dragonchain-client/DragonchainClient.ts @@ -57,6 +57,8 @@ import { CustomTagFieldOptions, SmartContractLogs, PermissionsDocument, + L5BlockAtRest, + EternalReportV1, } from '../../interfaces/DragonchainClientInterfaces'; import { CredentialService, HmacAlgorithm } from '../credential-service/CredentialService'; import { getDragonchainId, getDragonchainEndpoint } from '../config-service'; @@ -1437,6 +1439,50 @@ export class DragonchainClient { return (await this.post('/v1/public-blockchain-transaction', body)) as Response; }; + /** + * Query the Dragonchain for the subsequent interchain (L5) transactions + */ + public queryInterchainTransactions = async (options: { + /** + * L1 block ID + */ + blockId: string; + }) => { + if (!options.blockId) throw new FailureByDesign('PARAM_ERROR', 'Parameter `blockId` is required'); + return (await this.get(`/v1/verifications/interchains/${options.blockId}`)) as Response; + }; + + /** + * Get/Generate an Eternal-type report given a transaction ID + */ + public getReport = async (options: { + /** + * the transaction ID of the transaction to generate report for + */ + transactionId: string; + }) => { + if (!options.transactionId) throw new FailureByDesign('PARAM_ERROR', 'Parameter `transactionId` is required'); + const transaction = await this.getTransaction({ transactionId: options.transactionId }); + if (transaction && !transaction.ok) return { ok: false, status: transaction.status, response: {} }; + const blockId = transaction.response.header.block_id; + const block = await this.getBlock({ blockId }); + if (block && !block.ok) return { ok: false, status: block.status, response: {} }; + const verifications = await this.getVerifications({ blockId }); + const l5verifications = await this.queryInterchainTransactions({ blockId }); + return { + ok: true, + status: 200, + response: { + l1Transaction: transaction.response, + l1Block: block.response, + l2Verifications: verifications.response && verifications.response['2'], + l3Verifications: verifications.response && verifications.response['3'], + l4Verifications: verifications.response && verifications.response['4'], + l5Verifications: l5verifications && l5verifications.response, + }, + } as Response; + }; + /** * @hidden */