UNPKG

n8n-nodes-wax

Version:

n8n Community Node Package for the WAX Blockchain

219 lines (218 loc) 9.79 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const eosjs_1 = require("eosjs"); const WaxEventSource_1 = require("./WaxEventSource"); class WaxJS { constructor(rcpEndpoint, userAccount = null, pubKeys = null, tryAutoLogin = true, apiSigner = null, waxSigningURL = "https://all-access.wax.io", waxAutoSigningURL = "https://api-idm.wax.io/v1/accounts/auto-accept/") { this.apiSigner = apiSigner; this.waxSigningURL = waxSigningURL; this.waxAutoSigningURL = waxAutoSigningURL; this.waxEventSource = new WaxEventSource_1.WaxEventSource(waxSigningURL); this.rpc = new eosjs_1.JsonRpc(rcpEndpoint); if (userAccount && Array.isArray(pubKeys)) { // login from constructor const data = { userAccount, pubKeys, verified: true }; this.receiveLogin({ data }); } else { // try to auto-login via endpoint if (tryAutoLogin) { this.loginViaEndpoint(); } } } login() { return __awaiter(this, void 0, void 0, function* () { if (this.userAccount && Array.isArray(this.pubKeys)) { return this.userAccount; } else { // login via UI return this.loginViaWindow(); } }); } isAutoLoginAvailable() { return __awaiter(this, void 0, void 0, function* () { if (this.userAccount && Array.isArray(this.pubKeys)) { return true; } else { // try to auto-login via endpoint try { yield this.loginViaEndpoint(); return true; } catch (e) { return false; } } return false; }); } loginViaWindow() { return __awaiter(this, void 0, void 0, function* () { const confirmationWindow = yield this.waxEventSource.openEventSource(this.waxSigningURL + "/cloud-wallet/login/"); return this.waxEventSource.onceEvent(confirmationWindow, this.waxSigningURL, this.receiveLogin.bind(this)); }); } loginViaEndpoint() { return __awaiter(this, void 0, void 0, function* () { const response = yield fetch(this.waxAutoSigningURL + "login", { credentials: "include", method: "get" }); if (!response.ok) { throw new Error(`Login Endpoint Error ${response.status} ${response.statusText}`); } const data = yield response.json(); if (data.processed && data.processed.except) { throw new Error(data); } return this.receiveLogin({ data }); }); } receiveLogin(event) { return __awaiter(this, void 0, void 0, function* () { const { verified, userAccount, pubKeys, whitelistedContracts, autoLogin } = event.data; if (!verified) { throw new Error("User declined to share their user account"); } if (userAccount == null || pubKeys == null) { throw new Error("User does not have a blockchain account"); } localStorage.setItem("autoLogin", autoLogin); this.whitelistedContracts = whitelistedContracts || []; this.userAccount = userAccount; this.pubKeys = pubKeys; const signer = { getAvailableKeys: () => __awaiter(this, void 0, void 0, function* () { return [ ...this.pubKeys, ...((this.apiSigner && (yield this.apiSigner.getAvailableKeys())) || []) ]; }), sign: (data) => __awaiter(this, void 0, void 0, function* () { return { serializedTransaction: data.serializedTransaction, signatures: [ ...(yield this.signing(data.serializedTransaction)), ...((this.apiSigner && (yield this.apiSigner.sign(data)).signatures) || []) ] }; }) }; // @ts-ignore this.api = new eosjs_1.Api({ rpc: this.rpc, signatureProvider: signer }); const transact = this.api.transact.bind(this.api); const url = this.waxSigningURL + "/cloud-wallet/signing/"; // We monkeypatch the transact method to overcome timeouts // firing the pop-up which some browsers enforce, such as Safari. // By pre-creating the pop-up window we will interact with, // we ensure that it is not going to be rejected due to a delayed // pop up that would otherwise occur post transaction creation this.api.transact = (transaction, namedParams) => __awaiter(this, void 0, void 0, function* () { if (!(yield this.canAutoSign(transaction))) { this.signingWindow = yield window.open(url, "WaxPopup", "height=800,width=600"); } return yield transact(transaction, namedParams); }); return this.userAccount; }); } canAutoSign(transaction) { return __awaiter(this, void 0, void 0, function* () { const deserializedTransaction = transaction.actions ? transaction : yield this.api.deserializeTransactionWithActions(transaction); return !deserializedTransaction.actions.find((action) => { return !this.isWhitelisted(action); }); }); } isWhitelisted(action) { return !!this.whitelistedContracts.find((w) => { if (w.contract === action.account) { if (action.account === "eosio.token" && action.name === "transfer") { return w.recipients.includes(action.data.to); } return true; } return false; }); } signing(transaction) { return __awaiter(this, void 0, void 0, function* () { if (yield this.canAutoSign(transaction)) { return this.signViaEndpoint(transaction).catch(() => // Attempt to recover by signing via the window method this.signViaWindow(undefined, transaction)); } return this.signViaWindow(this.signingWindow, transaction); }); } signViaEndpoint(transaction) { return __awaiter(this, void 0, void 0, function* () { try { const response = yield fetch(this.waxAutoSigningURL + "signing", { body: JSON.stringify({ transaction: Object.values(transaction) }), credentials: "include", headers: { "Content-Type": "application/json" }, method: "POST" }); if (!response.ok) { throw new Error(`Signing Endpoint Error ${response.status} ${response.statusText}`); } const data = yield response.json(); if (data.processed && data.processed.except) { throw new Error(data); } return this.receiveSignatures({ data }); } catch (e) { // clear the whitelist to make sure we don't repeatedly attempt blocked actions this.whitelistedContracts = []; throw e; } }); } signViaWindow(window, transaction) { return __awaiter(this, void 0, void 0, function* () { const confirmationWindow = yield this.waxEventSource.openEventSource(this.waxSigningURL + "/cloud-wallet/signing/", { type: "TRANSACTION", transaction }, window); return this.waxEventSource.onceEvent(confirmationWindow, this.waxSigningURL, this.receiveSignatures.bind(this)); }); } receiveSignatures(event) { return __awaiter(this, void 0, void 0, function* () { if (event.data.type === "TX_SIGNED") { const { verified, signatures, whitelistedContracts } = event.data; if (!verified || signatures == null) { throw new Error("User declined to sign the transaction"); } this.whitelistedContracts = whitelistedContracts || []; return signatures; } else if (event.data.type !== "READY") { throw new Error(`Unexpected response received when attempting signing: ${JSON.stringify(event.data, undefined, 2)}`); } return []; }); } } exports.WaxJS = WaxJS;