From 5b1510bf1541138a6ea3ac61d71c7cde380ca12d Mon Sep 17 00:00:00 2001 From: Evan Hallmark Date: Thu, 2 Dec 2021 13:41:40 -0800 Subject: [PATCH 1/2] Integrate lwc with mobile-friendly wallet --- walletController.js | 120 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 108 insertions(+), 12 deletions(-) diff --git a/walletController.js b/walletController.js index 33eb703..aaed894 100644 --- a/walletController.js +++ b/walletController.js @@ -1,5 +1,9 @@ 'use strict' + +const LAMDEN_MOBILE_WALLET_URL = "https://lamdenwallet.com"; + + class WalletController { /** * Lamden Wallet Controller Class @@ -24,10 +28,11 @@ class WalletController { * @param {string=} connectionRequest.charms.key Key assoicated to the value you want to lookup * @param {string=} connectionRequest.charms.formatAs What format the data is * @param {string=} connectionRequest.charms.iconPath An icon to display along with your charm + * @param {boolean=} chromeExtension A flag of whether to use the Chrome extension or mobile-friendly browser wallet * @fires newInfo * @return {WalletController} */ - constructor(connectionRequest = undefined) { + constructor(connectionRequest = undefined, chromeExtension = true) { this.connectionRequest = connectionRequest ? new WalletConnectionRequest(connectionRequest) : null; this.events = new MyEventEmitter(); this.installed = null; @@ -37,6 +42,8 @@ class WalletController { this.autoTransactions = false; this.walletAddress = "" this.callbacks = {}; + this.popup = null; + this.chromeExtension = chromeExtension; document.addEventListener('lamdenWalletInfo', (e) => { this.installed = true; let data = e.detail; @@ -149,15 +156,21 @@ class WalletController { sendConnection(connectionRequest = undefined){ if (connectionRequest) this.connectionRequest = new WalletConnectionRequest(connectionRequest) if (this.connectionRequest === null) throw new Error('No connetionRequest information.') - return new Promise((resolve) => { - const handleConnecionResponse = (e) => { - this.events.emit('newInfo', e.detail) - resolve(e.detail); - document.removeEventListener("lamdenWalletInfo", handleConnecionResponse); - } - document.addEventListener('lamdenWalletInfo', handleConnecionResponse, { once: true }) - document.dispatchEvent(new CustomEvent('lamdenWalletConnect', {detail: this.connectionRequest.getInfo()})); - }) + if (this.chromeExtension) { + return new Promise((resolve) => { + const handleConnecionResponse = (e) => { + this.events.emit('newInfo', e.detail) + resolve(e.detail); + document.removeEventListener("lamdenWalletInfo", handleConnecionResponse); + } + document.addEventListener('lamdenWalletInfo', handleConnecionResponse, { once: true }) + document.dispatchEvent(new CustomEvent('lamdenWalletConnect', {detail: this.connectionRequest.getInfo()})); + }) + } else { + return new Promise((resolve) => { + this.loginMobile() + }) + } } /** * Creates a "lamdenWalletSendTx" event to send a transaction request to the Lamden Wallet. @@ -175,9 +188,92 @@ class WalletController { sendTransaction(tx, callback = undefined){ tx.uid = new Date().toISOString() if (typeof callback === 'function') this.callbacks[tx.uid] = callback - document.dispatchEvent(new CustomEvent('lamdenWalletSendTx', {detail: JSON.stringify(tx)})); + if (this.chromeExtension) { + document.dispatchEvent(new CustomEvent('lamdenWalletSendTx', {detail: JSON.stringify(tx)})); + } else { + var params = { + contractName: tx.contractName, + methodName: tx.methodName, + stampLimit: tx.stampLimit.toString(), + kwargs: JSON.stringify(tx.kwargs), + origin: window.location.href, + type: "sign", + } + var url = ( + LAMDEN_MOBILE_WALLET_URL + + "?contractName=" + encodeURIComponent(params.contractName) + + "&methodName=" + encodeURIComponent(params.methodName) + + "&stampLimit=" + encodeURIComponent(params.stampLimit) + + "&kwargs=" + encodeURIComponent(params.kwargs) + + "&origin=" + encodeURIComponent(params.origin) + + "&type=sign" + ); + this.openWalletPopup(url, params, tx.uid, (data)=>{ + this.callbacks[tx.uid]({data: data}) + }) + } } - } + /** + * Logs a user into their browser-compatible wallet + * + * This will fire the "newInfo" events.on event + * @fires newInfo + * @return {Promise} The User's Lamden Wallet Account details or errors from the wallet + */ + loginMobile() { + var url = ( + LAMDEN_MOBILE_WALLET_URL + + "?origin=" + encodeURIComponent(window.location.href) + + "&type=login" + ); + this.openWalletPopup(url, null, new Date().toISOString(), (data)=>{ + if (data.type && data.type==="vk") { + this.walletAddress = data.vk; + this.events.emit('newInfo', data); + return; + } + }); + } + /** + * If a user is using the mobile-compatible browser wallet, a popup will be opened (if not already exists) + * allowing them to approve connections and transactions. + * + * @param {string} url The url of the popup to open + * @param {Object} message The parameters to pass to the browser wallet + * @param {string} uid The uid of the transaction + * @param {Function=} callback A function that will called and passed the tx results. + */ + openWalletPopup(url, message, uid, callback) { + const eventHandler = (event) => { + if (event.origin !== LAMDEN_MOBILE_WALLET_URL) + return; + if (event.data.uid && event.data.uid !== uid) { + return; + } + if (message !== null && event.data.payload) { + if (message.contractName !== event.data.payload.contract + || message.methodName !== event.data.payload.function) { + return; + } + } + callback(event.data); + window.removeEventListener("message", eventHandler); + }; + window.addEventListener("message", eventHandler, false); + if (this.popup === null || this.popup.closed || message === null) { + this.popup = window.open( + url, + "LamdenWallet" + ); + } else { + this.popup.postMessage({ + jsonrpc: '2.0', + uid: uid, + ...message + }, LAMDEN_MOBILE_WALLET_URL); + } + } +} class WalletConnectionRequest { /** From 6c0a8edf3b2cb7c4eec4c9e3f310e9d47457cec7 Mon Sep 17 00:00:00 2001 From: Evan Hallmark Date: Fri, 3 Dec 2021 11:01:18 -0800 Subject: [PATCH 2/2] minor updates --- walletController.js | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/walletController.js b/walletController.js index aaed894..1cc6821 100644 --- a/walletController.js +++ b/walletController.js @@ -110,16 +110,22 @@ class WalletController { return new Promise((resolve, reject) => { const handleWalletInstalled = (e) => { this.installed = true; - this.events.emit('installed', true) + if (this.chromeExtension) { + this.events.emit('installed', true) + } document.removeEventListener("lamdenWalletInfo", handleWalletInstalled); if (this.connectionRequest !== null) this.sendConnection(); resolve(true); } document.addEventListener('lamdenWalletInfo', handleWalletInstalled, { once: true }) - this.getInfo(); - setTimeout(() => { - if (!this.installed) resolve(false); - }, 1000) + if (this.chromeExtension) { + this.getInfo(); + setTimeout(() => { + if (!this.installed) resolve(false); + }, 1000) + } else { + return this.loginMobile(); + } }) } /** @@ -156,21 +162,17 @@ class WalletController { sendConnection(connectionRequest = undefined){ if (connectionRequest) this.connectionRequest = new WalletConnectionRequest(connectionRequest) if (this.connectionRequest === null) throw new Error('No connetionRequest information.') - if (this.chromeExtension) { - return new Promise((resolve) => { - const handleConnecionResponse = (e) => { - this.events.emit('newInfo', e.detail) - resolve(e.detail); - document.removeEventListener("lamdenWalletInfo", handleConnecionResponse); - } - document.addEventListener('lamdenWalletInfo', handleConnecionResponse, { once: true }) + return new Promise((resolve) => { + const handleConnecionResponse = (e) => { + this.events.emit('newInfo', e.detail) + resolve(e.detail); + document.removeEventListener("lamdenWalletInfo", handleConnecionResponse); + } + document.addEventListener('lamdenWalletInfo', handleConnecionResponse, { once: true }) + if (this.chromeExtension) { document.dispatchEvent(new CustomEvent('lamdenWalletConnect', {detail: this.connectionRequest.getInfo()})); - }) - } else { - return new Promise((resolve) => { - this.loginMobile() - }) - } + } + }) } /** * Creates a "lamdenWalletSendTx" event to send a transaction request to the Lamden Wallet. @@ -228,8 +230,7 @@ class WalletController { ); this.openWalletPopup(url, null, new Date().toISOString(), (data)=>{ if (data.type && data.type==="vk") { - this.walletAddress = data.vk; - this.events.emit('newInfo', data); + document.dispatchEvent(new CustomEvent('lamdenWalletInfo', {detail: {wallets: [data.vk]}})); return; } });