Skip to content

Commit 1554f5f

Browse files
committed
feat: add initial webln support
1 parent 520ff92 commit 1554f5f

File tree

11 files changed

+283
-40
lines changed

11 files changed

+283
-40
lines changed

app/sources/public/content.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,44 @@
55

66
window[`walletIntegrated_${chrome.runtime.id}`] = true;
77

8+
const weblnContainer = document.createElement('script');
9+
weblnContainer.textContent = `
10+
window.webln = { isEnabled: true };
11+
window.webln.enable = async () => true;
12+
const createWeblnPromise = (method, options) => new Promise(resolve => {
13+
window.addEventListener('message', function(e) {
14+
if (e.data.from === 'bitlum' && e.data.method === method) {
15+
resolve(e.data.response);
16+
}
17+
}, true);
18+
window.postMessage({ from: 'webln', method, options }, "*");
19+
});
20+
window.webln.makeInvoice = (options) => createWeblnPromise('makeInvoice', options);
21+
window.webln.sendPayment = (options) => createWeblnPromise('sendPayment', options);
22+
`;
23+
(document.head || document.documentElement).appendChild(weblnContainer);
24+
weblnContainer.remove();
25+
26+
window.addEventListener(
27+
'message',
28+
async e => {
29+
if (e.data.from === 'webln') {
30+
chrome.runtime.sendMessage(
31+
{
32+
type: 'weblnRequest',
33+
method: e.data.method,
34+
options: e.data.options,
35+
origin: window.location.hostname,
36+
},
37+
response => {
38+
window.postMessage({ from: 'bitlum', method: e.data.method, response }, '*');
39+
},
40+
);
41+
}
42+
},
43+
true,
44+
);
45+
846
const vendorHandlers = {
947
default: {
1048
handleWuid(wuid, amount) {

app/sources/src/background.js

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,23 @@ const openConfirmationWindow = payment => {
127127
);
128128
};
129129

130+
const openReceiveWindow = payment => {
131+
window.open(
132+
`chrome-extension://${
133+
window.chrome.runtime.id
134+
}/index.html#/payments/receive/confirm?receive=${payment}&nopopup=true`,
135+
'_blank',
136+
'width=450,height=700,titlebar=0,menubar=0,location=0',
137+
);
138+
};
139+
130140
(async () => {
131141
await stores.init();
132142
const { accounts, payments, ui, info, wallets } = stores;
133143

134144
const latestPaymentRequests = {};
135145
const latestClipboardChange = {};
146+
const withdrawalRequest = {};
136147

137148
setUninstallUrl(accounts.get.data);
138149

@@ -142,7 +153,7 @@ const openConfirmationWindow = payment => {
142153
});
143154
}
144155

145-
window.chrome.runtime.onMessage.addListener(async req => {
156+
window.chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
146157
if (req.type === 'clipboardEvent') {
147158
if (req.action === 'copy') {
148159
localStorage.setItem(
@@ -159,16 +170,77 @@ const openConfirmationWindow = payment => {
159170
}
160171

161172
if (req.type === 'authenticated') {
162-
await accounts.authenticate.run();
163-
LiveChat.boot({
164-
user_id: accounts.get.data && accounts.get.data.auid,
173+
accounts.authenticate.run().then(r => {
174+
LiveChat.boot({
175+
user_id: accounts.get.data && accounts.get.data.auid,
176+
});
177+
setUninstallUrl(accounts.get.data);
165178
});
166-
setUninstallUrl(accounts.get.data);
167179
}
168180

169181
if (req.type === 'signedOut') {
170182
accounts.authenticate.cleanup('all');
171183
}
184+
185+
if (req.type === 'weblnRequest') {
186+
GA({
187+
type: 'event',
188+
category: 'extension',
189+
action: 'weblnRequest',
190+
label: req.method,
191+
});
192+
if (req.method === 'makeInvoice') {
193+
const amount = req.options
194+
? (req.options.amount || req.options.defaultAmount) / 10 ** 8
195+
: undefined;
196+
// Return invoice with maximum amount by default
197+
// instead of open withdraw confirmation window
198+
// payments.receive
199+
// .run(
200+
// 'lightning',
201+
// req.options ? (req.options.amount || req.options.defaultAmount) / 10 ** 8 : 0,
202+
// 'BTC',
203+
// )
204+
// .then(response => {
205+
// if (response.data) {
206+
// sendResponse({ paymentRequest: response.data.wuid });
207+
// } else {
208+
// sendResponse({ response });
209+
// }
210+
// });
211+
openReceiveWindow(
212+
JSON.stringify({
213+
amount,
214+
type: 'lightning',
215+
asset: 'BTC',
216+
origin: req.origin,
217+
}),
218+
);
219+
withdrawalRequest[`${req.origin}_${amount}`] = response => {
220+
if (response.data) {
221+
sendResponse({ paymentRequest: response.data.wuid });
222+
} else {
223+
sendResponse({ response });
224+
}
225+
};
226+
return true;
227+
}
228+
if (req.method === 'sendPayment') {
229+
openConfirmationWindow(
230+
JSON.stringify({ wuid: req.options, asset: 'BTC', origin: req.origin }),
231+
);
232+
}
233+
}
234+
235+
if (req.type === 'wuidGenerated') {
236+
withdrawalRequest[`${req.initialRequest.origin}_${req.initialRequest.amount}`](req);
237+
GA({
238+
type: 'event',
239+
category: 'extension',
240+
action: 'weblnInvoicePassed',
241+
label: req.initialRequest.origin,
242+
});
243+
}
172244
});
173245
const paymentsFetcher = setInterval(async () => {
174246
if (accounts.authenticate.data) {
@@ -267,6 +339,11 @@ const openConfirmationWindow = payment => {
267339
// }
268340
// latestClipboardChange.value = wuid;
269341
// }, 400);
342+
343+
if (process.env.NODE_ENV === 'development') {
344+
// Any configurations are optional
345+
window.stores = stores;
346+
}
270347
})();
271348

272349
window.chrome.runtime.onInstalled.addListener(details => {

app/sources/src/components/ReceivePayment/styles.js

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ import completedIcon from 'assets/icons/check-circle.svg';
3030

3131
export * from 'components/common';
3232

33-
export const CopyButton = styled(({ data, className }) => (
34-
<CopyButtonRaw className={className} copyData={data}>
35-
<CopyIcon />
33+
export const CopyButton = styled(({ data, className, inline, copiedText, copyText }) => (
34+
<CopyButtonRaw className={className} copyData={data} copiedText={copiedText} copyText={copyText}>
35+
{!inline ? <CopyIcon /> : null}
3636
</CopyButtonRaw>
3737
))`
3838
font: var(--fonts__text);
@@ -45,7 +45,7 @@ export const CopyButton = styled(({ data, className }) => (
4545
width: 1.8em;
4646
}
4747
margin-top: -0.2em;
48-
margin-left: 0.6em;
48+
margin-left: ${({ inline }) => (inline ? '0' : '0.6em')};
4949
`;
5050

5151
export const AssetSelector = styled.div`
@@ -181,6 +181,28 @@ export const SendResult = styled.div`
181181
}
182182
`;
183183

184+
export const ReceiveResult = styled.div`
185+
display: flex;
186+
flex-direction: column;
187+
text-align: center;
188+
justify-content: center;
189+
align-items: center;
190+
background: var(--colors__bg_bright);
191+
position: absolute;
192+
top: 0;
193+
width: 100vw;
194+
white-space: pre;
195+
z-index: 10;
196+
& > ${P} {
197+
font: var(--fonts__header_bold);
198+
color: var(--colors__bg_dark);
199+
}
200+
& ${CopyButton} {
201+
font-size: 1.2em;
202+
padding-top: 0.5em;
203+
}
204+
`;
205+
184206
export const SendResultIcon = styled.div`
185207
background-image: url(${completedIcon});
186208
height: 8em;
@@ -194,6 +216,32 @@ export const SendResultIcon = styled.div`
194216
margin-bottom: 2em;
195217
`;
196218

219+
export const ReceiveResultIcon = styled.div`
220+
background-image: url(${completedIcon});
221+
height: 8em;
222+
width: 8em;
223+
background-color: var(--colors__bg_dark);
224+
background-repeat: no-repeat;
225+
border-radius: 50%;
226+
background-size: 60%;
227+
background-position: center;
228+
margin-top: 6em;
229+
margin-bottom: 2em;
230+
`;
231+
232+
export const SendResultDesc = styled.p`
233+
color: var(--colors__bg_dark);
234+
font-size: 0.8em;
235+
max-width: 90%;
236+
word-break: break-word;
237+
margin-top: 1em;
238+
`;
239+
export const SendResultCta = styled.a`
240+
color: var(--colors__bg_accent);
241+
font-size: 0.8em;
242+
margin-top: 1em;
243+
`;
244+
197245
export const Root = withLoader(styled(Form)`
198246
position: relative;
199247
background-color: var(--colors__bg_bright);

0 commit comments

Comments
 (0)