UNPKG

@aeternity/aepp-sdk

Version:
765 lines (667 loc) 28 kB
import _Object$getOwnPropertySymbols from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols"; import _Object$getOwnPropertyDescriptor from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor"; import _Object$getOwnPropertyDescriptors from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors"; import _Object$defineProperties from "@babel/runtime-corejs3/core-js-stable/object/define-properties"; import _Object$defineProperty from "@babel/runtime-corejs3/core-js-stable/object/define-property"; import _slicedToArray from "@babel/runtime-corejs3/helpers/slicedToArray"; import _toConsumableArray from "@babel/runtime-corejs3/helpers/toConsumableArray"; import _defineProperty from "@babel/runtime-corejs3/helpers/defineProperty"; import _asyncToGenerator from "@babel/runtime-corejs3/helpers/asyncToGenerator"; var _REQUESTS; function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); if (enumerableOnly) symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context21; _forEachInstanceProperty(_context21 = ownKeys(Object(source), true)).call(_context21, function (key) { _defineProperty(target, key, source[key]); }); } else if (_Object$getOwnPropertyDescriptors) { _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)); } else { var _context22; _forEachInstanceProperty(_context22 = ownKeys(Object(source))).call(_context22, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } } return target; } import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat"; import _Object$keys from "@babel/runtime-corejs3/core-js-stable/object/keys"; import _Promise from "@babel/runtime-corejs3/core-js-stable/promise"; import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each"; import _bindInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/bind"; import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter"; import _Object$values from "@babel/runtime-corejs3/core-js-stable/object/values"; import _reduceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/reduce"; import _Object$entries from "@babel/runtime-corejs3/core-js-stable/object/entries"; import _regeneratorRuntime from "@babel/runtime-corejs3/regenerator"; /** * RPC handler for WAELLET side * * @module @aeternity/aepp-sdk/es/utils/aepp-wallet-communication/rpc/wallet-rpc * @export WalletRpc * @example import WalletRpc from '@aeternity/aepp-sdk/es/utils/aepp-wallet-communication/rpc/wallet-rpc' */ import { v4 as uuid } from 'uuid'; import Ae from '../../../ae'; import AccountMultiple from '../../../account/multiple'; import TxObject from '../../../tx/tx-object'; import RpcClient from './rpc-client'; import { getBrowserAPI, getHandler, isValidAccounts, message, resolveOnAccount, sendResponseMessage } from '../helpers'; import { ERRORS, METHODS, RPC_STATUS, VERSION, WALLET_TYPE } from '../schema'; var NOTIFICATIONS = _defineProperty({}, METHODS.closeConnection, function (instance, _ref) { var client = _ref.client; return /*#__PURE__*/function () { var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(msg) { return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: client.disconnect(true); instance.onDisconnect(msg.params, client); case 2: case "end": return _context.stop(); } } }, _callee); })); return function (_x) { return _ref2.apply(this, arguments); }; }(); }); var RESPONSES = {}; var REQUESTS = (_REQUESTS = {}, _defineProperty(_REQUESTS, METHODS.aepp.connect, function (callInstance, instance, client, _ref3) { var name = _ref3.name, networkId = _ref3.networkId, version = _ref3.version, icons = _ref3.icons; // Check if protocol and network is compatible with wallet if (version !== VERSION) return { error: ERRORS.unsupportedProtocol() }; // Store new AEPP and wait for connection approve client.updateInfo({ status: RPC_STATUS.WAITING_FOR_CONNECTION_APPROVE, name: name, networkId: networkId, icons: icons, version: version }); // Call onConnection callBack to notice Wallet about new AEPP return callInstance('onConnection', { name: name, networkId: networkId, version: version }, function () { client.updateInfo({ status: RPC_STATUS.CONNECTED }); return { result: instance.getWalletInfo() }; }, function (error) { client.updateInfo({ status: RPC_STATUS.CONNECTION_REJECTED }); return { error: ERRORS.connectionDeny(error) }; }); }), _defineProperty(_REQUESTS, METHODS.aepp.subscribeAddress, function (callInstance, instance, client, _ref4) { var type = _ref4.type, value = _ref4.value; // Authorization check if (!client.isConnected()) return { error: ERRORS.notAuthorize() }; return callInstance('onSubscription', { type: type, value: value }, /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() { var _ref6, accounts, clientAccounts, subscription, _args2 = arguments; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: _ref6 = _args2.length > 0 && _args2[0] !== undefined ? _args2[0] : {}, accounts = _ref6.accounts; _context2.prev = 1; clientAccounts = accounts || instance.getAccounts(); if (isValidAccounts(clientAccounts)) { _context2.next = 5; break; } throw new Error('Invalid provided accounts object'); case 5: subscription = client.updateSubscription(type, value); client.setAccounts(clientAccounts, { forceNotification: true }); return _context2.abrupt("return", { result: { subscription: subscription, address: clientAccounts } }); case 10: _context2.prev = 10; _context2.t0 = _context2["catch"](1); console.error(_context2.t0); return _context2.abrupt("return", { error: ERRORS.internalError({ msg: _context2.t0.message }) }); case 14: case "end": return _context2.stop(); } } }, _callee2, null, [[1, 10]]); })), function (error) { return { error: ERRORS.rejectedByUser(error) }; }); }), _defineProperty(_REQUESTS, METHODS.aepp.address, function (callInstance, instance, client) { // Authorization check if (!client.isConnected()) return { error: ERRORS.notAuthorize() }; if (!client.isSubscribed()) return { error: ERRORS.notAuthorize() }; return callInstance('onAskAccounts', {}, function () { var _context3; var _ref7 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, accounts = _ref7.accounts; return { result: accounts || _concatInstanceProperty(_context3 = []).call(_context3, _toConsumableArray(_Object$keys(client.accounts.current)), _toConsumableArray(_Object$keys(client.accounts.connected))) }; }, function (error) { return { error: ERRORS.rejectedByUser(error) }; }); }), _defineProperty(_REQUESTS, METHODS.aepp.sign, function (callInstance, instance, client, _ref8) { var tx = _ref8.tx, onAccount = _ref8.onAccount, networkId = _ref8.networkId, _ref8$returnSigned = _ref8.returnSigned, returnSigned = _ref8$returnSigned === void 0 ? false : _ref8$returnSigned; var address = onAccount || client.currentAccount; // Update client with new networkId networkId && client.updateInfo({ networkId: networkId }); // Authorization check if (!client.isConnected()) return { error: ERRORS.notAuthorize() }; // Account permission check if (!client.hasAccessToAccount(address)) return { error: ERRORS.permissionDeny({ account: address }) }; // NetworkId check if (!networkId || networkId !== instance.getNetworkId()) return { error: ERRORS.unsupportedNetwork() }; return callInstance('onSign', { tx: tx, returnSigned: returnSigned, onAccount: address, txObject: TxObject.fromString(tx) }, /*#__PURE__*/function () { var _ref9 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(rawTx) { var opt, onAcc, validationResult, _args3 = arguments; return _regeneratorRuntime.wrap(function _callee3$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: opt = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : {}; _context4.prev = 1; onAcc = resolveOnAccount(instance.addresses(), address, opt); _context4.next = 9; break; case 5: _context4.prev = 5; _context4.t0 = _context4["catch"](1); console.error(_context4.t0); return _context4.abrupt("return", { error: ERRORS.internalError({ msg: _context4.t0.message }) }); case 9: _context4.prev = 9; _context4.t1 = _objectSpread; _context4.t2 = {}; if (!returnSigned) { _context4.next = 19; break; } _context4.next = 15; return instance.signTransaction(rawTx || tx, { onAccount: onAcc }); case 15: _context4.t4 = _context4.sent; _context4.t3 = { signedTransaction: _context4.t4 }; _context4.next = 23; break; case 19: _context4.next = 21; return instance.send(rawTx || tx, { onAccount: onAcc, verify: false }); case 21: _context4.t5 = _context4.sent; _context4.t3 = { transactionHash: _context4.t5 }; case 23: _context4.t6 = _context4.t3; _context4.t7 = (0, _context4.t1)(_context4.t2, _context4.t6); return _context4.abrupt("return", { result: _context4.t7 }); case 28: _context4.prev = 28; _context4.t8 = _context4["catch"](9); if (returnSigned) { _context4.next = 37; break; } _context4.next = 33; return instance.unpackAndVerify(rawTx || tx); case 33: validationResult = _context4.sent; if (!validationResult.validation.length) { _context4.next = 36; break; } return _context4.abrupt("return", { error: ERRORS.invalidTransaction(validationResult) }); case 36: return _context4.abrupt("return", { error: ERRORS.broadcastFailde(_context4.t8.message) }); case 37: throw _context4.t8; case 38: case "end": return _context4.stop(); } } }, _callee3, null, [[1, 5], [9, 28]]); })); return function (_x2) { return _ref9.apply(this, arguments); }; }(), function (error) { return { error: ERRORS.rejectedByUser(error) }; }); }), _defineProperty(_REQUESTS, METHODS.aepp.signMessage, function (callInstance, instance, client, _ref10) { var message = _ref10.message, onAccount = _ref10.onAccount; // Authorization check if (!client.isConnected()) return { error: ERRORS.notAuthorize() }; var address = onAccount || client.currentAccount; if (!client.hasAccessToAccount(address)) return { error: ERRORS.permissionDeny({ account: address }) }; return callInstance('onMessageSign', { message: message, onAccount: address }, /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() { var opt, onAcc, _args4 = arguments; return _regeneratorRuntime.wrap(function _callee4$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: opt = _args4.length > 0 && _args4[0] !== undefined ? _args4[0] : {}; _context5.prev = 1; onAcc = resolveOnAccount(instance.addresses(), address, opt); _context5.next = 5; return instance.signMessage(message, { onAccount: onAcc, returnHex: true }); case 5: _context5.t0 = _context5.sent; _context5.t1 = { signature: _context5.t0 }; return _context5.abrupt("return", { result: _context5.t1 }); case 10: _context5.prev = 10; _context5.t2 = _context5["catch"](1); console.error(_context5.t2); return _context5.abrupt("return", { error: ERRORS.internalError({ msg: _context5.t2.message }) }); case 14: case "end": return _context5.stop(); } } }, _callee4, null, [[1, 10]]); })), function (error) { return { error: ERRORS.rejectedByUser(error) }; }); }), _REQUESTS); var handleMessage = function handleMessage(instance, id) { return /*#__PURE__*/function () { var _ref12 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(msg, origin) { var client, _id, method, callInstance, errorObjectOrHandler, response; return _regeneratorRuntime.wrap(function _callee5$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: client = instance.rpcClients[id]; if (msg.id) { _context6.next = 3; break; } return _context6.abrupt("return", getHandler(NOTIFICATIONS, msg, { debug: instance.debug })(instance, { client: client })(msg, origin)); case 3: if (!Object.prototype.hasOwnProperty.call(client.callbacks, msg.id)) { _context6.next = 7; break; } return _context6.abrupt("return", getHandler(RESPONSES, msg, { debug: instance.debug })(instance, { client: client })(msg, origin)); case 7: _id = msg.id, method = msg.method; callInstance = function callInstance(methodName, params, _accept, _deny) { return function () { return new _Promise(function (resolve) { instance[methodName](client, { id: _id, method: method, params: params, accept: function accept() { return resolve(_accept.apply(void 0, arguments)); }, deny: function deny() { return resolve(_deny.apply(void 0, arguments)); } }, origin); }); }; }; // TODO make one structure for handler functions errorObjectOrHandler = getHandler(REQUESTS, msg, { debug: instance.debug })(callInstance, instance, client, msg.params); if (!(typeof errorObjectOrHandler === 'function')) { _context6.next = 16; break; } _context6.next = 13; return errorObjectOrHandler(); case 13: _context6.t0 = _context6.sent; _context6.next = 17; break; case 16: _context6.t0 = errorObjectOrHandler; case 17: response = _context6.t0; sendResponseMessage(client)(_id, method, response); case 19: case "end": return _context6.stop(); } } }, _callee5); })); return function (_x3, _x4) { return _ref12.apply(this, arguments); }; }(); }; /** * Contain functionality for aepp interaction and managing multiple aepps * @alias module:@aeternity/aepp-sdk/es/utils/aepp-wallet-communication/rpc/wallet-rpc * @function * @rtype Stamp * @param {Object} param Init params object * @param {String=} [param.name] Wallet name * @param {Function} onConnection Call-back function for incoming AEPP connection (Second argument contain function for accept/deny request) * @param {Function} onSubscription Call-back function for incoming AEPP account subscription (Second argument contain function for accept/deny request) * @param {Function} onSign Call-back function for incoming AEPP sign request (Second argument contain function for accept/deny request) * @param {Function} onAskAccounts Call-back function for incoming AEPP get address request (Second argument contain function for accept/deny request) * @param {Function} onMessageSign Call-back function for incoming AEPP sign message request (Second argument contain function for accept/deny request) * @param {Function} onDisconnect Call-back function for disconnect event * @return {Object} */ export default Ae.compose(AccountMultiple, { init: function init() { var _this = this, _context7, _context8, _context9; var _ref13 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, name = _ref13.name, onConnection = _ref13.onConnection, onSubscription = _ref13.onSubscription, onSign = _ref13.onSign, onDisconnect = _ref13.onDisconnect, onAskAccounts = _ref13.onAskAccounts, onMessageSign = _ref13.onMessageSign, _ref13$forceValidatio = _ref13.forceValidation, forceValidation = _ref13$forceValidatio === void 0 ? false : _ref13$forceValidatio, _ref13$debug = _ref13.debug, debug = _ref13$debug === void 0 ? false : _ref13$debug; this.debug = debug; var eventsHandlers = ['onConnection', 'onSubscription', 'onSign', 'onDisconnect', 'onMessageSign']; // CallBacks for events this.onConnection = onConnection; this.onSubscription = onSubscription; this.onSign = onSign; this.onDisconnect = onDisconnect; this.onAskAccounts = onAskAccounts; this.onMessageSign = onMessageSign; this.rpcClients = {}; _forEachInstanceProperty(eventsHandlers).call(eventsHandlers, function (event) { if (!forceValidation && typeof _this[event] !== 'function') throw new Error("Call-back for ".concat(event, " must be an function!")); }); // this.name = name; this.id = uuid(); var _selectAccount = _bindInstanceProperty(_context7 = this.selectAccount).call(_context7, this); var _addAccount = _bindInstanceProperty(_context8 = this.addAccount).call(_context8, this); var _selectNode = _bindInstanceProperty(_context9 = this.selectNode).call(_context9, this); // Overwrite AE methods this.selectAccount = function (address) { var _context10, _context11; var _ref14 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, _ref14$condition = _ref14.condition, condition = _ref14$condition === void 0 ? function () { return true; } : _ref14$condition; _selectAccount(address); _forEachInstanceProperty(_context10 = _filterInstanceProperty(_context11 = _Object$values(_this.rpcClients)).call(_context11, function (client) { return client.isConnected() && client.isSubscribed() && client.hasAccessToAccount(address) && condition(client); })).call(_context10, function (client) { var _context12, _context13; return client.setAccounts({ current: _defineProperty({}, address, {}), connected: _objectSpread(_objectSpread({}, client.accounts.current), _reduceInstanceProperty(_context12 = _filterInstanceProperty(_context13 = _Object$entries(client.accounts.connected)).call(_context13, function (_ref15) { var _ref16 = _slicedToArray(_ref15, 2), k = _ref16[0], v = _ref16[1]; return k !== address; })).call(_context12, function (acc, _ref17) { var _ref18 = _slicedToArray(_ref17, 2), k = _ref18[0], v = _ref18[1]; return _objectSpread(_objectSpread({}, acc), {}, _defineProperty({}, k, v)); }, {})) }); }); }; this.addAccount = /*#__PURE__*/function () { var _ref19 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6(account) { var _context14, _context15; var _ref20, select, _ref20$meta, meta, _ref20$condition, condition, address, _args6 = arguments; return _regeneratorRuntime.wrap(function _callee6$(_context16) { while (1) { switch (_context16.prev = _context16.next) { case 0: _ref20 = _args6.length > 1 && _args6[1] !== undefined ? _args6[1] : {}, select = _ref20.select, _ref20$meta = _ref20.meta, meta = _ref20$meta === void 0 ? {} : _ref20$meta, _ref20$condition = _ref20.condition, condition = _ref20$condition === void 0 ? function () { return true; } : _ref20$condition; _context16.next = 3; return _addAccount(account, { select: select }); case 3: _context16.next = 5; return account.address(); case 5: address = _context16.sent; // Send notification 'update.address' to all Aepp which are subscribed for connected accounts _forEachInstanceProperty(_context14 = _filterInstanceProperty(_context15 = _Object$values(_this.rpcClients)).call(_context15, function (client) { return client.isConnected() && client.isSubscribed() && condition(client); })).call(_context14, function (client) { return client.setAccounts({ current: _objectSpread({}, select ? _defineProperty({}, address, meta) : client.accounts.current), connected: _objectSpread(_objectSpread({}, select ? client.accounts.current : _defineProperty({}, address, meta)), client.accounts.connected) }); }); case 7: case "end": return _context16.stop(); } } }, _callee6); })); return function (_x5) { return _ref19.apply(this, arguments); }; }(); this.selectNode = function (name) { var _context17, _context18; _selectNode(name); // Send notification 'update.network' to all Aepp which connected _forEachInstanceProperty(_context17 = _filterInstanceProperty(_context18 = _Object$values(_this.rpcClients)).call(_context18, function (client) { return client.isConnected(); })).call(_context17, function (client) { return client.sendMessage(message(METHODS.updateNetwork, { networkId: _this.getNetworkId() }), true); }); }; }, methods: { /** * Remove specific RpcClient by ID * @function removeRpcClient * @instance * @rtype (id: string) => void * @param {String} id Client ID * @param {Object} [opt = {}] * @return {void} */ removeRpcClient: function removeRpcClient(id) { var _ref23 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, _ref23$forceConnectio = _ref23.forceConnectionClose, forceConnectionClose = _ref23$forceConnectio === void 0 ? false : _ref23$forceConnectio; var client = this.rpcClients[id]; if (!client) throw new Error("RpcClient with id ".concat(id, " do not exist")); client.disconnect(forceConnectionClose); delete this.rpcClients[id]; }, /** * Add new client by AEPP connection * @function addRpcClient * @instance * @rtype (clientConnection: Object) => Object * @param {Object} clientConnection AEPP connection object * @return {String} Client ID */ addRpcClient: function addRpcClient(clientConnection) { // @TODO detect if aepp has some history based on origin????: if yes use this instance for connection var id = uuid(); this.rpcClients[id] = RpcClient({ id: id, info: { status: RPC_STATUS.WAITING_FOR_CONNECTION_REQUEST }, connection: clientConnection, handlers: [handleMessage(this, id), this.onDisconnect] }); return id; }, /** * Share wallet info * Send shareWalletInfo message to notify AEPP about wallet * @function shareWalletInfo * @instance * @rtype (postFn: Function) => void * @param {Function} postFn Send message function like `(msg) => void` * @return {void} */ shareWalletInfo: function shareWalletInfo(postFn) { postFn(_objectSpread({ jsonrpc: '2.0' }, message(METHODS.wallet.readyToConnect, this.getWalletInfo()))); }, /** * Get Wallet info object * @function getWalletInfo * @instance * @rtype () => Object * @return {Object} Object with wallet information(id, name, network, ...) */ getWalletInfo: function getWalletInfo() { var runtime = getBrowserAPI(true).runtime; return { id: runtime && runtime.id ? runtime.id : this.id, name: this.name, networkId: this.getNetworkId(), origin: window.location.origin, type: runtime && runtime.id ? WALLET_TYPE.extension : WALLET_TYPE.window }; }, /** * Get Wallet accounts * @function getAccounts * @instance * @rtype () => Object * @return {Object} Object with accounts information({ connected: Object, current: Object }) */ getAccounts: function getAccounts() { var _context19, _context20, _this2 = this; return { current: this.selectedAddress ? _defineProperty({}, this.selectedAddress, {}) : {}, connected: _reduceInstanceProperty(_context19 = _filterInstanceProperty(_context20 = this.addresses()).call(_context20, function (a) { return a !== _this2.selectedAddress; })).call(_context19, function (acc, a) { return _objectSpread(_objectSpread({}, acc), {}, _defineProperty({}, a, {})); }, {}) }; } } }); //# sourceMappingURL=wallet-rpc.js.map