@aeternity/aepp-sdk
Version:
SDK for the æternity blockchain
765 lines (667 loc) • 28 kB
JavaScript
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