UNPKG

cosmic-lib

Version:

A JavaScript implementation of the CosmicLink protocol for Stellar

478 lines (390 loc) 14 kB
"use strict"; /** * Contains the action methods for CosmicLink. * * @private * @exports action */ var _regeneratorRuntime = require("@babel/runtime/regenerator"); var _asyncToGenerator = require("@babel/runtime/helpers/asyncToGenerator"); var action = exports; var axios = require("@cosmic-plus/base/es5/axios"); var env = require("@cosmic-plus/jsutils/es5/env"); var misc = require("@cosmic-plus/jsutils/es5/misc"); var convert = require("./convert"); var format = env.isBrowser && require("./format"); var resolve = require("./resolve"); var signersUtils = require("./signers-utils"); var status = require("./status"); /** * Lock a CosmicLink to a network/source pair. If the cosmicLink was created * from a query/uri/tdesc/json, it will create the corresponding * transaction/xdr/sep7 formats. * * This operation must be performed by the wallet before signing & sending the * transaction. * * @example * cosmicLib.config.network = "test" * const cosmicLink = new CosmicLink("?setOptions") * console.log(cosmicLink.network) // => undefined * console.log(cosmicLink.xdr) // => undefined * await cosmicLink.lock() * console.log(cosmicLink.network) // => "test" * console.log(cosmicLink.xdr) // => "AAAA...AA==" * * * @alias CosmicLink#lock * @async * @param {Object} [options] * @param {string} options.network Local fallback network * @param {string} options.horizon Local fallback horizon (overwrited by global configuration) * @param {string} options.callback Local fallback callback * @param {string} options.source Local fallback source */ action.lock = /*#__PURE__*/function () { var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(cosmicLink) { var options, _args = arguments; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {}; if (!cosmicLink.status) { _context.next = 3; break; } throw new Error(cosmicLink.status); case 3: if (!cosmicLink.locker) { _context.next = 5; break; } throw new Error("CosmicLink is already locked."); case 5: _context.prev = 5; _context.next = 8; return applyLock(cosmicLink, options); case 8: _context.next = 14; break; case 10: _context.prev = 10; _context.t0 = _context["catch"](5); if (!cosmicLink.errors) { console.error(_context.t0); status.error(cosmicLink, _context.t0.message); } status.fail(cosmicLink, "Transaction build failed", "throw"); case 14: updateSignersNode(cosmicLink); return _context.abrupt("return", cosmicLink); case 16: case "end": return _context.stop(); } } }, _callee, null, [[5, 10]]); })); return function (_x) { return _ref.apply(this, arguments); }; }(); function applyLock(_x2, _x3) { return _applyLock.apply(this, arguments); } /** * Sign CosmicLink's Transaction with **keypairs_or_preimage** and update the * other formats accordingly. Only legit signers are allowed to sign, and a * CosmicLink have to be [locked]{@link CosmicLink#lock} before signing. * * @alias CosmicLink#sign * @param {...Keypair|Buffer|string} ...keypairs_or_preimage */ function _applyLock() { _applyLock = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(cosmicLink, options) { return _regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: /** * The locker property tells that a CosmicLink have been locked, and exposes * the network & source values to which it have been locked. * * @alias CosmicLink#locker */ cosmicLink.locker = { source: cosmicLink.tdesc.source || options.source || cosmicLink.config.source, network: cosmicLink.tdesc.network || options.network || cosmicLink.config.network, horizon: options.horizon || cosmicLink.horizon, callback: cosmicLink.tdesc.callback || options.callback || cosmicLink.config.callback }; /// Preserve the underlying tdesc object. cosmicLink._tdesc = Object.assign({}, cosmicLink.tdesc, cosmicLink.locker); delete cosmicLink._query; delete cosmicLink._json; if (cosmicLink._transaction) { _context4.next = 9; break; } _context4.next = 7; return convert.tdescToTransaction(cosmicLink, cosmicLink.tdesc); case 7: cosmicLink._transaction = _context4.sent; delete cosmicLink._tdesc; case 9: delete cosmicLink._transaction._cosmicplus; _context4.next = 12; return signersUtils["extends"](cosmicLink, cosmicLink._transaction); case 12: case "end": return _context4.stop(); } } }, _callee4); })); return _applyLock.apply(this, arguments); } action.sign = /*#__PURE__*/function () { var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(cosmicLink) { var transaction, allFine, _len, keypairsOrPreimage, _key, index, keypair, publicKey, _short, _short2, _short3, _args2 = arguments; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (cosmicLink.locker) { _context2.next = 2; break; } throw new Error("cosmicLink is not locked."); case 2: transaction = cosmicLink.transaction; allFine = true; for (_len = _args2.length, keypairsOrPreimage = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { keypairsOrPreimage[_key - 1] = _args2[_key]; } if (!(typeof keypairsOrPreimage[0] !== "string")) { _context2.next = 33; break; } _context2.t0 = _regeneratorRuntime.keys(keypairsOrPreimage); case 7: if ((_context2.t1 = _context2.t0()).done) { _context2.next = 31; break; } index = _context2.t1.value; keypair = keypairsOrPreimage[index]; publicKey = keypair.publicKey(); if (cosmicLink.transaction.hasSigner(publicKey)) { _context2.next = 16; break; } _short = misc.shorter(publicKey); status.error(cosmicLink, "Not a legit signer: " + _short); allFine = false; return _context2.abrupt("continue", 7); case 16: if (!cosmicLink.transaction.hasSigned(publicKey)) { _context2.next = 18; break; } return _context2.abrupt("continue", 7); case 18: _context2.prev = 18; transaction.sign(keypair); _context2.next = 29; break; case 22: _context2.prev = 22; _context2.t2 = _context2["catch"](18); console.error(_context2.t2); _short2 = misc.shorter(publicKey); status.error(cosmicLink, "Failed to sign with key: " + _short2); allFine = false; return _context2.abrupt("continue", 7); case 29: _context2.next = 7; break; case 31: _context2.next = 34; break; case 33: try { transaction.signHashX(keypairsOrPreimage[0]); } catch (error) { console.error(error); _short3 = misc.shorter(keypairsOrPreimage[0]); status.error(cosmicLink, "Failed to sign with preimage: " + _short3, "throw"); } case 34: /// Update other formats. ["_query", "_xdr", "_sep7"].forEach(function (format) { return delete cosmicLink[format]; }); updateSignersNode(cosmicLink); if (allFine) { _context2.next = 40; break; } throw new Error("Some signers where invalid"); case 40: return _context2.abrupt("return", transaction); case 41: case "end": return _context2.stop(); } } }, _callee2, null, [[18, 22]]); })); return function (_x4) { return _ref2.apply(this, arguments); }; }(); function updateSignersNode(cosmicLink) { if (cosmicLink._signersNode) { var signersNode = format.signatures(cosmicLink, cosmicLink._transaction); cosmicLink.htmlDescription.replaceChild(signersNode, cosmicLink._signersNode); cosmicLink._signersNode = signersNode; } } /** * Send CosmicLink's transaction to a blockchain validator, or to * [StellarGuard]{@link https://stellarguard.me} when relevant. A * CosmicLink have to be [locked]{@link CosmicLink#lock} before sending. * * Returns a promise that resolve/reject to the horizon server response. * * @example * cosmicLink.send() * .then(console.log) * .catch(console.error) * * @alias CosmicLink#send * @param {horizon} [horizon] An horizon node URL * @return {Object} The server response */ action.send = /*#__PURE__*/function () { var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(cosmicLink) { var horizon, _args3 = arguments; return _regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: horizon = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : cosmicLink.horizon; if (cosmicLink.locker) { _context3.next = 3; break; } throw new Error("cosmicLink is not locked."); case 3: _context3.prev = 3; if (!cosmicLink.transaction.hasSigner(STELLARGUARD_PUBKEY)) { _context3.next = 10; break; } _context3.next = 7; return sendToStellarGuard(cosmicLink); case 7: return _context3.abrupt("return", _context3.sent); case 10: if (!cosmicLink.callback) { _context3.next = 16; break; } _context3.next = 13; return axios.post(cosmicLink.callback, { xdr: cosmicLink.xdr }); case 13: return _context3.abrupt("return", _context3.sent); case 16: _context3.next = 18; return sendToHorizon(cosmicLink, horizon); case 18: return _context3.abrupt("return", _context3.sent); case 19: _context3.next = 25; break; case 21: _context3.prev = 21; _context3.t0 = _context3["catch"](3); if (_context3.t0.response) console.error(_context3.t0.message, _context3.t0.response); throw _context3.t0; case 25: case "end": return _context3.stop(); } } }, _callee3, null, [[3, 21]]); })); return function (_x5) { return _ref3.apply(this, arguments); }; }(); function sendToHorizon(_x6, _x7) { return _sendToHorizon.apply(this, arguments); } function _sendToHorizon() { _sendToHorizon = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(cosmicLink, horizon) { var server; return _regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: server = resolve.server(cosmicLink, horizon); // Keep connection alive until transaction gets validated or a non-504 error // is returned. 504 error means the transaction is still following the // validation process. // eslint-disable-next-line no-constant-condition case 1: if (!true) { _context5.next = 14; break; } _context5.prev = 2; _context5.next = 5; return server.submitTransaction(cosmicLink.transaction); case 5: return _context5.abrupt("return", _context5.sent); case 8: _context5.prev = 8; _context5.t0 = _context5["catch"](2); if (!(_context5.t0.response.status !== 504)) { _context5.next = 12; break; } throw _context5.t0; case 12: _context5.next = 1; break; case 14: case "end": return _context5.stop(); } } }, _callee5, null, [[2, 8]]); })); return _sendToHorizon.apply(this, arguments); } function sendToStellarGuard(cosmicLink) { var url = cosmicLink.network === "test" ? "https://test.stellarguard.me/api/transactions" : "https://stellarguard.me/api/transactions"; return axios.post(url, { xdr: cosmicLink.xdr, callback: cosmicLink.callback }).then(function (result) { return result.data; }); } var STELLARGUARD_PUBKEY = "GCVHEKSRASJBD6O2Z532LWH4N2ZLCBVDLLTLKSYCSMBLOYTNMEEGUARD";